root/src/stratcon_realtime_http.c

Revision 6de024fe1a245773c4b8c107f9063f2f40e5c344, 19.6 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 3 years ago)

updates... yay! for test suites... all passes, refs #334

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2007, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  *       notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  *       copyright notice, this list of conditions and the following
13  *       disclaimer in the documentation and/or other materials provided
14  *       with the distribution.
15  *     * Neither the name OmniTI Computer Consulting, Inc. nor the names
16  *       of its contributors may be used to endorse or promote products
17  *       derived from this software without specific prior written
18  *       permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include "noit_defines.h"
34 #include "eventer/eventer.h"
35 #include "noit_conf.h"
36 #include "utils/noit_hash.h"
37 #include "utils/noit_log.h"
38 #include "utils/noit_str.h"
39 #include "jlog/jlog.h"
40 #include "noit_jlog_listener.h"
41 #include "noit_listener.h"
42 #include "noit_http.h"
43 #include "noit_rest.h"
44 #include "noit_check.h"
45 #include "noit_livestream_listener.h"
46 #include "stratcon_realtime_http.h"
47 #include "stratcon_jlog_streamer.h"
48 #include "stratcon_datastore.h"
49
50 #include <ctype.h>
51 #include <unistd.h>
52 #include <assert.h>
53 #include <errno.h>
54 #include <sys/types.h>
55 #include <sys/socket.h>
56 #ifdef HAVE_SYS_FILIO_H
57 #include <sys/filio.h>
58 #endif
59 #include <netinet/in.h>
60 #include <sys/un.h>
61 #include <arpa/inet.h>
62
63
64 typedef struct realtime_recv_ctx_t {
65   int bytes_expected;
66   int bytes_read;
67   int bytes_written;
68   int body_len;
69   char *buffer;         /* These guys are for doing partial reads */
70
71   enum {
72     REALTIME_HTTP_WANT_INITIATE = 0,
73     REALTIME_HTTP_WANT_SEND_INTERVAL = 1,
74     REALTIME_HTTP_WANT_SEND_UUID = 2,
75     REALTIME_HTTP_WANT_HEADER = 3,
76     REALTIME_HTTP_WANT_BODY = 4,
77   } state;
78   int count;            /* Number of jlog messages we need to read */
79   u_int32_t hack_inc_id;
80   noit_http_session_ctx *ctx;
81   struct realtime_tracker *rt;
82 } realtime_recv_ctx_t;
83
84 typedef struct realtime_context {
85   enum { RC_INITIAL = 0, RC_REQ_RECV, RC_INTERESTS_RESOLVED, RC_FEEDING } setup;
86   struct realtime_tracker *checklist;
87   char *document_domain;
88 } realtime_context;
89
90 static realtime_context *alloc_realtime_context(const char *domain) {
91   realtime_context *ctx;
92   ctx = calloc(sizeof(*ctx), 1);
93   ctx->document_domain = strdup(domain);
94   return ctx;
95 }
96 static void free_realtime_tracker(struct realtime_tracker *rt) {
97   if(rt->noit) free(rt->noit);
98   free(rt);
99 }
100 static void clear_realtime_context(realtime_context *rc) {
101  rc->setup = RC_INITIAL;
102   while(rc->checklist) {
103     struct realtime_tracker *tofree;
104     tofree = rc->checklist;
105     rc->checklist = tofree->next;
106     free_realtime_tracker(tofree);
107   }
108   if(rc->document_domain) free(rc->document_domain);
109   rc->document_domain = NULL;
110 }
111 int
112 stratcon_line_to_javascript(noit_http_session_ctx *ctx, char *buff,
113                             u_int32_t inc_id) {
114   char buffer[1024];
115   char *scp, *ecp, *token;
116   int len;
117   const char *v, *cb = NULL;
118   noit_hash_table json = NOIT_HASH_EMPTY;
119   noit_http_request *req = noit_http_session_request(ctx);
120   char s_inc_id[42];
121
122   snprintf(s_inc_id, sizeof(s_inc_id), "script-%08x", inc_id);
123  
124   cb = noit_http_request_querystring(req, "cb");
125   for(v = cb; v && *v; v++)
126     if(!((*v >= '0' && *v <= '9') ||
127          (*v >= 'a' && *v <= 'z') ||
128          (*v >= 'A' && *v <= 'Z') ||
129          (*v == '_') || (*v == '.'))) {
130       cb = NULL;
131       break;
132     }
133   if(!cb) cb = "window.parent.plot_iframe_data";
134
135 #define BAIL_HTTP_WRITE do { \
136   noit_hash_destroy(&json, NULL, free); \
137   noitL(noit_error, "javascript emit failed: %s:%s:%d\n", \
138         __FILE__, __FUNCTION__, __LINE__); \
139   return -1; \
140 } while(0)
141
142 #define PROCESS_NEXT_FIELD(t,l) do { \
143   if(!*scp) goto bad_row; \
144   ecp = strchr(scp, '\t'); \
145   if(!ecp) goto bad_row; \
146   t = scp; \
147   l = (ecp-scp); \
148   scp = ecp + 1; \
149 } while(0)
150 #define PROCESS_LAST_FIELD(t,l) do { \
151   if(!*scp) ecp = scp; \
152   else { \
153     ecp = scp + strlen(scp); /* Puts us at the '\0' */ \
154     if(*(ecp-1) == '\n') ecp--; /* We back up on letter if we ended in \n */ \
155   } \
156   t = scp; \
157   l = (ecp-scp); \
158 } while(0)
159
160   scp = buff;
161   PROCESS_NEXT_FIELD(token,len); /* Skip the leader */
162   if(buff[1] == '\t' && (buff[0] == 'M' || buff[0] == 'S')) {
163     char target[256], module[256], name[256], uuid_str[UUID_STR_LEN+1];
164     noit_http_request *req = noit_http_session_request(ctx);
165     noit_hash_table *qs;
166     noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
167     const char *key;
168     int klen, i=0;
169     void *vval;
170     char type[2] = { '\0', '\0' };
171     type[0] = buff[0];
172
173 #define ra_write(a,b) if(noit_http_response_append(ctx, a, b) == noit_false) BAIL_HTTP_WRITE
174
175     snprintf(buffer, sizeof(buffer), "<script id=\"%s\">%s({", s_inc_id, cb);
176     ra_write(buffer, strlen(buffer));
177
178     qs = noit_http_request_querystring_table(req);
179     while(noit_hash_next(qs, &iter, &key, &klen, &vval)) {
180       if(!strcmp(key, "cb")) continue;
181       noit_hash_store(&json, key, klen, strdup(vval ?(char *)vval : "true"));
182     }
183     /* Time */
184     noit_hash_store(&json, "script_id", 9, strdup(s_inc_id));
185     noit_hash_store(&json, "type", 4, strdup(type));
186     PROCESS_NEXT_FIELD(token,len);
187     noit_hash_store(&json, "time", 4, noit__strndup(token, len));
188     /* UUID */
189     PROCESS_NEXT_FIELD(token,len);
190     noit_check_extended_id_split(token, len, target, sizeof(target),
191                                  module, sizeof(module), name, sizeof(name),
192                                  uuid_str, sizeof(uuid_str));
193     if(*uuid_str)
194       noit_hash_store(&json, "id", 2,
195                       noit__strndup(uuid_str, strlen(uuid_str)));
196     if(*target)
197       noit_hash_store(&json, "check_target", 12,
198                       noit__strndup(target, strlen(target)));
199     if(*module)
200       noit_hash_store(&json, "check_module", 12,
201                       noit__strndup(module, strlen(module)));
202     if(*name)
203       noit_hash_store(&json, "check_name", 10,
204                       noit__strndup(name, strlen(name)));
205     if(buff[0] == 'M') {
206       /* name */
207       PROCESS_NEXT_FIELD(token,len);
208       noit_hash_store(&json, "metric_name", 11, noit__strndup(token, len));
209       /* type */
210       PROCESS_NEXT_FIELD(token,len);
211       noit_hash_store(&json, "metric_type", 11, noit__strndup(token, len));
212       /* value */
213       PROCESS_LAST_FIELD(token,len); /* value */
214       noit_hash_store(&json, "value", 5, noit__strndup(token, len));
215     }
216     else if(buff[0] == 'S') {
217       /* state */
218       PROCESS_NEXT_FIELD(token,len);
219       noit_hash_store(&json, "check_state", 11, noit__strndup(token, len));
220       /* availability */
221       PROCESS_NEXT_FIELD(token,len);
222       noit_hash_store(&json, "check_availability", 18, noit__strndup(token, len));
223       /* duration */
224       PROCESS_NEXT_FIELD(token,len);
225       noit_hash_store(&json, "check_duration_ms", 17, noit__strndup(token, len));
226       /* status */
227       PROCESS_LAST_FIELD(token,len);
228       noit_hash_store(&json, "status_message", 14, noit__strndup(token, len));
229     }
230
231     memset(&iter, 0, sizeof(iter));
232     while(noit_hash_next(&json, &iter, &key, &klen, &vval)) {
233       char *val = (char *)vval;
234       if(i++) ra_write(",", 1);
235       ra_write("\"", 1);
236       ra_write(key, klen);
237       ra_write("\":\"", 3);
238       while(*val) {
239         if(*val == '\"' || *val == '\\') {
240           ra_write((char *)"\\", 1);
241         }
242         if(isprint(*val)) {
243           ra_write((char *)val, 1);
244         }
245         else {
246           char od[5];
247           snprintf(od, sizeof(od), "\\%03o", *((unsigned char *)val));
248           ra_write(od, strlen(od));
249         }
250         val++;
251       }
252       ra_write("\"", 1);
253     }
254     snprintf(buffer, sizeof(buffer), "});</script>\n");
255     ra_write(buffer, strlen(buffer));
256
257     if(noit_http_response_flush(ctx, noit_false) == noit_false) BAIL_HTTP_WRITE;
258   }
259
260   noit_hash_destroy(&json, NULL, free);
261   return 0;
262
263  bad_row:
264   BAIL_HTTP_WRITE;
265 }
266 int
267 stratcon_realtime_uri_parse(realtime_context *rc, const char *uri) {
268   int len, cnt = 0;
269   const char *cp, *interest;
270   char *copy, *brk;
271   if(strncmp(uri, "/data/", 6)) return 0;
272   cp = uri + 6;
273   len = strlen(cp);
274   copy = alloca(len + 1);
275   if(!copy) return 0;
276   memcpy(copy, cp, len);
277   copy[len] = '\0';
278
279   for (interest = strtok_r(copy, "/", &brk);
280        interest;
281        interest = strtok_r(NULL, "/", &brk)) {
282     uuid_t in_uuid;
283     struct realtime_tracker *node;
284     char *interval;
285
286     interval = strchr(interest, '@');
287     if(!interval)
288       interval = "5000";
289     else
290       *interval++ = '\0';
291     if(uuid_parse(interest, in_uuid)) continue;
292     node = calloc(1, sizeof(*node));
293     node->rc = rc;
294     uuid_copy(node->checkid, in_uuid);
295     node->interval = atoi(interval);
296     node->next = rc->checklist;
297     rc->checklist = node;
298     cnt++;
299   }
300   return cnt;
301 }
302 static void
303 free_realtime_recv_ctx(void *vctx) {
304   realtime_recv_ctx_t *rrctx = vctx;
305   noit_http_session_ctx *ctx = rrctx->ctx;
306   realtime_context *rc = noit_http_session_dispatcher_closure(ctx);
307
308   if(noit_http_session_ref_dec(ctx) == 1) {
309     noit_http_response_end(ctx);
310     clear_realtime_context(rc);
311     noit_http_session_trigger(ctx, EVENTER_WRITE | EVENTER_EXCEPTION);
312   }
313   free(rrctx);
314 }
315 #define Eread(a,b) e->opset->read(e->fd, (a), (b), &mask, e)
316 static int
317 __read_on_ctx(eventer_t e, realtime_recv_ctx_t *ctx, int *newmask) {
318   int len, mask;
319   while(ctx->bytes_read < ctx->bytes_expected) {
320     len = Eread(ctx->buffer + ctx->bytes_read,
321                 ctx->bytes_expected - ctx->bytes_read);
322     if(len < 0) {
323       *newmask = mask;
324       return -1;
325     }
326     /* if we get 0 inside SSL, and there was a real error, we
327      * will actually get a -1 here.
328      * if(len == 0) return ctx->bytes_read;
329      */
330     ctx->bytes_read += len;
331   }
332   assert(ctx->bytes_read == ctx->bytes_expected);
333   return ctx->bytes_read;
334 }
335 #define FULLREAD(e,ctx,size) do { \
336   int mask, len; \
337   if(!ctx->bytes_expected) { \
338     ctx->bytes_expected = size; \
339     if(ctx->buffer) free(ctx->buffer); \
340     ctx->buffer = malloc(size + 1); \
341     if(ctx->buffer == NULL) { \
342       noitL(noit_error, "malloc(%lu) failed.\n", (unsigned long)size + 1); \
343       goto socket_error; \
344     } \
345     ctx->buffer[size] = '\0'; \
346   } \
347   len = __read_on_ctx(e, ctx, &mask); \
348   if(len < 0) { \
349     if(errno == EAGAIN) return mask | EVENTER_EXCEPTION; \
350     noitL(noit_error, "SSL read error: %s\n", strerror(errno)); \
351     goto socket_error; \
352   } \
353   ctx->bytes_read = 0; \
354   ctx->bytes_expected = 0; \
355   if(len != size) { \
356     noitL(noit_error, "SSL short read [%d] (%d/%lu).  Reseting connection.\n", \
357           ctx->state, len, (unsigned long)size); \
358     goto socket_error; \
359   } \
360 } while(0)
361
362 int
363 stratcon_realtime_recv_handler(eventer_t e, int mask, void *closure,
364                                struct timeval *now) {
365   static u_int32_t livestream_cmd = 0;
366   noit_connection_ctx_t *nctx = closure;
367   realtime_recv_ctx_t *ctx = nctx->consumer_ctx;
368   int len;
369   u_int32_t nint;
370   char uuid_str[37];
371
372   if(!livestream_cmd) livestream_cmd = htonl(NOIT_LIVESTREAM_DATA_FEED);
373
374   if(mask & EVENTER_EXCEPTION || nctx->wants_shutdown) {
375  socket_error:
376     ctx->state = REALTIME_HTTP_WANT_INITIATE;
377     ctx->count = 0;
378     ctx->bytes_read = 0;
379     ctx->bytes_written = 0;
380     ctx->bytes_expected = 0;
381     if(ctx->buffer) free(ctx->buffer);
382     ctx->buffer = NULL;
383     noit_connection_ctx_dealloc(nctx);
384     eventer_remove_fd(e->fd);
385     e->opset->close(e->fd, &mask, e);
386     return 0;
387   }
388
389 #define full_nb_write(data, wlen) do { \
390   if(!ctx->bytes_expected) { \
391     ctx->bytes_written = 0; \
392     ctx->bytes_expected = wlen; \
393   } \
394   while(ctx->bytes_written < ctx->bytes_expected) { \
395     while(-1 == (len = e->opset->write(e->fd, ((char *)data) + ctx->bytes_written, \
396                                        ctx->bytes_expected - ctx->bytes_written, \
397                                        &mask, e)) && errno == EINTR); \
398     if(len < 0) { \
399       if(errno == EAGAIN) return mask | EVENTER_EXCEPTION; \
400       goto socket_error; \
401     } \
402     ctx->bytes_written += len; \
403   } \
404   if(ctx->bytes_written != ctx->bytes_expected) { \
405     noitL(noit_error, "short write on initiating stream [%d != %d].\n", \
406           ctx->bytes_written, ctx->bytes_expected); \
407     goto socket_error; \
408   } \
409   ctx->bytes_expected = 0; \
410 } while(0)
411
412   noit_connection_update_timeout(nctx);
413   while(1) {
414     u_int32_t net_body_len;
415
416     switch(ctx->state) {
417       case REALTIME_HTTP_WANT_INITIATE:
418         full_nb_write(&livestream_cmd, sizeof(livestream_cmd));
419         ctx->state = REALTIME_HTTP_WANT_SEND_INTERVAL;
420       case REALTIME_HTTP_WANT_SEND_INTERVAL:
421         nint = htonl(ctx->rt->interval);
422         full_nb_write(&nint, sizeof(nint));
423         ctx->state = REALTIME_HTTP_WANT_SEND_UUID;
424       case REALTIME_HTTP_WANT_SEND_UUID:
425         uuid_unparse_lower(ctx->rt->checkid, uuid_str);
426         full_nb_write(uuid_str, 36);
427         ctx->state = REALTIME_HTTP_WANT_HEADER;
428       case REALTIME_HTTP_WANT_HEADER:
429         FULLREAD(e, ctx, sizeof(u_int32_t));
430         memcpy(&net_body_len, ctx->buffer, sizeof(u_int32_t));
431         ctx->body_len = ntohl(net_body_len);
432         free(ctx->buffer); ctx->buffer = NULL;
433         ctx->state = REALTIME_HTTP_WANT_BODY;
434         break;
435       case REALTIME_HTTP_WANT_BODY:
436         FULLREAD(e, ctx, ctx->body_len);
437         if(stratcon_line_to_javascript(ctx->ctx, ctx->buffer, ctx->hack_inc_id++)) goto socket_error;
438         free(ctx->buffer); ctx->buffer = NULL;
439         ctx->state = REALTIME_HTTP_WANT_HEADER;
440         break;
441     }
442   }
443
444 }
445
446 int
447 stratcon_realtime_http_postresolve(eventer_t e, int mask, void *closure,
448                                    struct timeval *now) {
449   noit_http_session_ctx *ctx = closure;
450   realtime_context *rc = noit_http_session_dispatcher_closure(ctx);
451   struct realtime_tracker *node;
452
453   for(node = rc->checklist; node; node = node->next) {
454     if(node->noit) {
455       realtime_recv_ctx_t *rrctx;
456       rrctx = calloc(1, sizeof(*rrctx));
457       rrctx->ctx = ctx;
458       rrctx->rt = node;
459       stratcon_streamer_connection(NULL, node->noit,
460                                    stratcon_realtime_recv_handler,
461                                    NULL, rrctx,
462                                    free_realtime_recv_ctx);
463     }
464     else
465       noit_http_session_ref_dec(ctx);
466   }
467   if(noit_http_session_ref_cnt(ctx) == 1) {
468     noit_http_response_end(ctx);
469     clear_realtime_context(rc);
470     noit_http_session_trigger(ctx, EVENTER_WRITE);
471   }
472   return 0;
473 }
474 int
475 stratcon_request_dispatcher(noit_http_session_ctx *ctx) {
476   const char *key, *value;
477   realtime_context *rc = noit_http_session_dispatcher_closure(ctx);
478   int klen;
479   noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
480   noit_http_request *req = noit_http_session_request(ctx);
481
482   if(rc->setup == RC_INITIAL) {
483     eventer_t completion;
484     struct realtime_tracker *node;
485     char c[1024];
486     int num_interests;
487     const char *uri_str = noit_http_request_uri_str(req);
488     noit_hash_table *headers = noit_http_request_headers_table(req);
489
490     num_interests = stratcon_realtime_uri_parse(rc, uri_str);
491     if(num_interests == 0) {
492       noit_http_response_status_set(ctx, 404, "OK");
493       noit_http_response_option_set(ctx, NOIT_HTTP_CLOSE);
494       noit_http_response_end(ctx);
495       return 0;
496     }
497
498     noitL(noit_error, "http: %s %s %s\n",
499           noit_http_request_method_str(req), uri_str,
500           noit_http_request_protocol_str(req));
501     while(noit_hash_next_str(headers, &iter, &key, &klen, &value)) {
502       noitL(noit_error, "http: [%s: %s]\n", key, value);
503     }
504     noit_http_response_status_set(ctx, 200, "OK");
505     noit_http_response_option_set(ctx, NOIT_HTTP_CHUNKED);
506     /*noit_http_response_option_set(ctx, NOIT_HTTP_GZIP);*/
507     /*noit_http_response_option_set(ctx, NOIT_HTTP_DEFLATE);*/
508     noit_http_response_header_set(ctx, "Content-Type", "text/html");
509
510     snprintf(c, sizeof(c),
511              "<html><head><script>document.domain='%s';</script></head><body>\n",
512              rc->document_domain);
513     noit_http_response_append(ctx, c, strlen(c));
514
515     /* this dumb crap is to make some browsers happy (Safari) */
516     memset(c, ' ', sizeof(c));
517     noit_http_response_append(ctx, c, sizeof(c));
518     noit_http_response_flush(ctx, noit_false);
519
520     rc->setup = RC_REQ_RECV;
521     /* Each interest references the ctx */
522     for(node = rc->checklist; node; node = node->next) {
523       char uuid_str[UUID_STR_LEN+1];
524       noit_http_session_ref_inc(ctx);
525       uuid_unparse_lower(node->checkid, uuid_str);
526       noitL(noit_error, "Resolving uuid: %s\n", uuid_str);
527     }
528     completion = eventer_alloc();
529     completion->mask = EVENTER_TIMER;
530     completion->callback = stratcon_realtime_http_postresolve;
531     completion->closure = ctx;
532     gettimeofday(&completion->whence, NULL);
533     stratcon_datastore_push(DS_OP_FIND_COMPLETE, NULL, NULL,
534                             rc->checklist, completion);
535   }
536   return EVENTER_EXCEPTION;
537 }
538 int
539 stratcon_realtime_http_handler(eventer_t e, int mask, void *closure,
540                                struct timeval *now) {
541   int done = 0, rv;
542   acceptor_closure_t *ac = closure;
543   noit_http_session_ctx *http_ctx = ac->service_ctx;
544   rv = noit_http_session_drive(e, mask, http_ctx, now, &done);
545   if(done) acceptor_closure_free(ac);
546   return rv;
547 }
548 static int
549 rest_stream_data(noit_http_rest_closure_t *restc,
550                  int npats, char **pats) {
551   /* We're here and want to subvert the rest system */
552   const char *document_domain = NULL;
553   noit_http_session_ctx *ctx = restc->http_ctx;
554   noit_http_connection *conn = noit_http_session_connection(ctx);
555   eventer_t e;
556   acceptor_closure_t *ac = restc->ac;
557
558   /* Rewire the handler */
559   if(ac->service_ctx_free)
560     ac->service_ctx_free(ac->service_ctx);
561   ac->service_ctx = ctx;
562   ac->service_ctx_free = noit_http_ctx_acceptor_free;
563
564   if(!noit_hash_retr_str(ac->config,
565                          "document_domain", strlen("document_domain"),
566                          &document_domain)) {
567     noitL(noit_error, "Document domain not set!  Realtime streaming will be broken\n");
568     document_domain = "";
569   }
570
571   noit_http_process_querystring(noit_http_session_request(ctx));
572   /* Rewire the http context */
573   e = noit_http_connection_event(conn);
574   e->callback = stratcon_realtime_http_handler;
575   noit_http_session_set_dispatcher(ctx, stratcon_request_dispatcher,
576                                    alloc_realtime_context(document_domain));
577   return stratcon_request_dispatcher(ctx);
578 }
579
580 void
581 stratcon_realtime_http_init(const char *toplevel) {
582   eventer_name_callback("stratcon_realtime_http",
583                         stratcon_realtime_http_handler);
584   eventer_name_callback("stratcon_realtime_recv",
585                         stratcon_realtime_recv_handler);
586   assert(noit_http_rest_register_auth(
587     "GET", "/data/",
588            "^((?:" UUID_REGEX "(?:@\\d+)?)(?:/" UUID_REGEX "(?:@\\d+)?)*)$",
589     rest_stream_data, noit_http_rest_access
590   ) == 0);
591   assert(noit_http_rest_register_auth(
592     "GET", "/", "^(.*)$", noit_rest_simple_file_handler, noit_http_rest_access
593   ) == 0);
594 }
Note: See TracBrowser for help on using the browser.