root/src/stratcon_realtime_http.c

Revision 65abbae9594e84d43262cb5176eb757e960360e6, 19.9 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 3 years ago)

the actually causes a warning in gcc version 4.1.2 20080704 (Red Hat 4.1.2-48)

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