[Reconnoiter-devel] [reconnoiter commit] r537 - trunk/src

svn-commit at lists.omniti.com svn-commit at lists.omniti.com
Thu Dec 4 23:21:49 EST 2008


Author: jesus
Date: 2008-12-04 23:21:49 -0500 (Thu, 04 Dec 2008)
New Revision: 537

Modified:
   trunk/src/noit_http.c
   trunk/src/noit_http.h
   trunk/src/stratcon_realtime_http.c
Log:
fix off-by-one in hex output for chunked encoding, support for deflate, deflate and non-deflate works with curl, but only non-deflate (regular chunked) works with firefox.  refs #64

Modified: trunk/src/noit_http.c
===================================================================
--- trunk/src/noit_http.c	2008-12-04 22:54:42 UTC (rev 536)
+++ trunk/src/noit_http.c	2008-12-05 04:21:49 UTC (rev 537)
@@ -10,6 +10,7 @@
 #include <errno.h>
 #include <ctype.h>
 #include <assert.h>
+#include <zlib.h>
 
 #define REQ_PAT "\r\n\r\n"
 #define REQ_PATSIZE 4
@@ -18,7 +19,7 @@
     noit_hash_replace(&ctx->res.headers, \
                       strdup(a), strlen(a), strdup(b), free, free)
 static const char _hexchars[16] =
-  {'0','1','2','3','4','5','6','7','8','9','a','b','c','e','f'};
+  {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
 
 struct bchain *bchain_alloc(size_t size) {
   struct bchain *n;
@@ -29,6 +30,14 @@
   n->allocd = size;
   return n;
 }
+#define RELEASE_BCHAIN(a) do { \
+  while(a) { \
+    struct bchain *__b; \
+    __b = a; \
+    a = __b->next; \
+    bchain_free(__b); \
+  } \
+} while(0)
 struct bchain *bchain_from_data(void *d, size_t size) {
   struct bchain *n;
   n = bchain_alloc(size);
@@ -133,7 +142,7 @@
 }
 static int
 _http_perform_write(noit_http_session_ctx *ctx, int *mask) {
-  int len;
+  int len, tlen = 0;
   struct bchain **head, *b;
  choose_bucket:
   head = ctx->res.leader ? &ctx->res.leader : &ctx->res.output_raw;
@@ -143,12 +152,13 @@
   if(ctx->res.output_started == noit_false) return EVENTER_EXCEPTION;
   if(!b) {
     if(ctx->res.closed) ctx->res.complete = noit_true;
-    return EVENTER_EXCEPTION;
+    *mask = EVENTER_EXCEPTION;
+    return tlen;
   }
 
   if(ctx->res.output_raw_offset >= b->size) {
     *head = b->next;
-    free(b);
+    bchain_free(b);
     b = *head;
     if(b) b->prev = NULL;
     ctx->res.output_raw_offset = 0;
@@ -160,14 +170,18 @@
                 b->buff + b->start + ctx->res.output_raw_offset,
                 b->size - ctx->res.output_raw_offset,
                 mask, ctx->conn.e);
-  if(len == -1 && errno == EAGAIN) return (*mask | EVENTER_EXCEPTION);
+  if(len == -1 && errno == EAGAIN) {
+    *mask |= EVENTER_EXCEPTION;
+    return tlen;
+  }
   if(len == -1) {
     /* socket error */
     ctx->conn.e->opset->close(ctx->conn.e->fd, mask, ctx->conn.e);
     ctx->conn.e = NULL;
-    return 0;
+    return -1;
   }
   ctx->res.output_raw_offset += len;
+  tlen += len;
   goto choose_bucket;
 }
 static noit_boolean
@@ -251,7 +265,8 @@
         *((char *)next_str) = '\0';
         next_str += 2;
       }
-      if(*curr_str == '\0') break; /* our CRLFCRLF... end of req */
+      if(req->method_str && *curr_str == '\0')
+        break; /* our CRLFCRLF... end of req */
 #define FAIL do { *err = noit_true; return noit_false; } while(0)
       if(!req->method_str) { /* request line */
         req->method_str = (char *)curr_str;
@@ -265,11 +280,16 @@
         req->protocol_str++;
         req->method = _method_enum(req->method_str);
         req->protocol = _protocol_enum(req->protocol_str);
+        if(req->protocol == NOIT_HTTP11) req->opts |= NOIT_HTTP_CHUNKED;
       }
       else { /* request headers */
         const char *name, *value;
         if(_extract_header(curr_str, &name, &value) == noit_false) FAIL;
         if(!name && !last_name) FAIL;
+        if(!strcmp(name ? name : last_name, "accept-encoding")) {
+          if(strstr(value, "gzip")) req->opts |= NOIT_HTTP_GZIP;
+          if(strstr(value, "deflate")) req->opts |= NOIT_HTTP_DEFLATE;
+        }
         if(name)
           noit_hash_replace(&req->headers, name, strlen(name), (void *)value,
                             NULL, NULL);
@@ -305,7 +325,7 @@
 int
 noit_http_complete_request(noit_http_session_ctx *ctx, int mask) {
   struct bchain *in;
-  noit_boolean rv, err;
+  noit_boolean rv, err = noit_false;
 
   if(mask & EVENTER_EXCEPTION) {
    full_error:
@@ -354,40 +374,68 @@
   }
   return EVENTER_READ | EVENTER_EXCEPTION;
 }
-
+void
+noit_http_request_release(noit_http_session_ctx *ctx) {
+  noit_hash_destroy(&ctx->req.headers, NULL, NULL);
+  RELEASE_BCHAIN(ctx->req.first_input);
+  memset(&ctx->req, 0, sizeof(ctx->req));
+}
+void
+noit_http_response_release(noit_http_session_ctx *ctx) {
+  noit_hash_destroy(&ctx->res.headers, free, free);
+  if(ctx->res.status_reason) free(ctx->res.status_reason);
+  RELEASE_BCHAIN(ctx->res.leader);
+  RELEASE_BCHAIN(ctx->res.output);
+  RELEASE_BCHAIN(ctx->res.output_raw);
+  memset(&ctx->res, 0, sizeof(ctx->res));
+}
 int
-noit_http_session_drive(eventer_t e, int mask, void *closure,
+noit_http_session_drive(eventer_t e, int origmask, void *closure,
                         struct timeval *now) {
   noit_http_session_ctx *ctx = closure;
   int rv;
+  int mask = origmask;
  next_req:
   if(ctx->req.complete != noit_true) {
-    mask = noit_http_complete_request(ctx, mask);
+    mask = noit_http_complete_request(ctx, origmask);
     if(ctx->req.complete != noit_true) return mask;
   }
-  rv = ctx->dispatcher(ctx);
+
+  /* only dispatch if the response is not complete */
+  if(ctx->res.complete == noit_false) rv = ctx->dispatcher(ctx);
+
   _http_perform_write(ctx, &mask);
   if(ctx->res.complete == noit_true &&
      ctx->conn.e &&
      ctx->conn.needs_close == noit_true) {
     ctx->conn.e->opset->close(ctx->conn.e->fd, &mask, ctx->conn.e);
     ctx->conn.e = NULL;
+    goto release;
     return 0;
   }
+  if(ctx->res.complete == noit_true) {
+    noit_http_request_release(ctx);
+    noit_http_response_release(ctx);
+  }
   if(ctx->req.complete == noit_false) goto next_req;
   if(ctx->conn.e) {
     return mask;
   }
   return 0;
+ release:
+  noit_http_request_release(ctx);
+  noit_http_response_release(ctx);
+  return 0;
 }
 
 noit_http_session_ctx *
-noit_http_session_ctx_new(noit_http_dispatch_func f, eventer_t e) {
+noit_http_session_ctx_new(noit_http_dispatch_func f, void *c, eventer_t e) {
   noit_http_session_ctx *ctx;
   ctx = calloc(1, sizeof(*ctx));
   ctx->req.complete = noit_false;
   ctx->conn.e = e;
   ctx->dispatcher = f;
+  ctx->dispatcher_closure = c;
   ctx->drive = noit_http_session_drive;
   return ctx;
 }
@@ -425,6 +473,10 @@
       (NOIT_HTTP_GZIP | NOIT_HTTP_DEFLATE)) ==
         (NOIT_HTTP_GZIP | NOIT_HTTP_DEFLATE))
     return noit_false;
+
+  /* Check out "accept" set */
+  if(!(opt & ctx->req.opts)) return noit_false;
+
   ctx->res.output_options |= opt;
   if(ctx->res.output_options & NOIT_HTTP_CHUNKED)
     CTX_ADD_HEADER("Transfer-Encoding", "chunked");
@@ -539,6 +591,15 @@
   if(opts & NOIT_HTTP_GZIP) {
   }
   else if(opts & NOIT_HTTP_DEFLATE) {
+    uLongf olen;
+    olen = out->allocd - out->start;
+    if(Z_OK != compress2((Bytef *)(out->buff + out->start), &olen,
+                         (Bytef *)(in->buff + in->start), (uLong)in->size,
+                         9)) {
+      noitL(noit_error, "zlib compress2 error\n");
+      return noit_false;
+    }
+    out->size += olen;
   }
   else {
     if(in->size > out->allocd - out->start) return noit_false;
@@ -562,7 +623,10 @@
   while(ilen) { ilen >>= 4; hexlen++; }
   if(hexlen == 0) hexlen = 1;
 
-  out = bchain_alloc(hexlen + 4 + in->size);
+  ilen = in->size;
+  if(opts & NOIT_HTTP_GZIP) ilen = compressBound(ilen);
+  else if(opts & NOIT_HTTP_DEFLATE) ilen = compressBound(ilen);
+  out = bchain_alloc(hexlen + 4 + ilen);
   /* if we're chunked, let's give outselved hexlen + 2 prefix space */
   if(opts & NOIT_HTTP_CHUNKED) out->start = hexlen + 2;
   if(_http_encode_chain(out, in, opts) == noit_false) {

Modified: trunk/src/noit_http.h
===================================================================
--- trunk/src/noit_http.h	2008-12-04 22:54:42 UTC (rev 536)
+++ trunk/src/noit_http.h	2008-12-05 04:21:49 UTC (rev 537)
@@ -54,6 +54,7 @@
   char *method_str;
   char *uri_str;
   char *protocol_str;
+  u_int32_t opts;
   noit_http_method method;
   noit_http_protocol protocol;
   noit_hash_table headers;
@@ -86,11 +87,12 @@
   noit_http_request req;
   noit_http_response res;
   noit_http_dispatch_func dispatcher;
+  void *dispatcher_closure;
   eventer_func_t drive;
 } noit_http_session_ctx;
 
 API_EXPORT(noit_http_session_ctx *)
-  noit_http_session_ctx_new(noit_http_dispatch_func, eventer_t);
+  noit_http_session_ctx_new(noit_http_dispatch_func, void *, eventer_t);
 
 API_EXPORT(int)
   noit_http_session_drive(eventer_t, int, void *, struct timeval *);

Modified: trunk/src/stratcon_realtime_http.c
===================================================================
--- trunk/src/stratcon_realtime_http.c	2008-12-04 22:54:42 UTC (rev 536)
+++ trunk/src/stratcon_realtime_http.c	2008-12-05 04:21:49 UTC (rev 537)
@@ -13,26 +13,74 @@
 #include "noit_listener.h"c
 #include "noit_http.h"
 
+typedef struct {
+  int setup;
+} realtime_context;
+
+static realtime_context *alloc_realtime_context() {
+  realtime_context *ctx;
+  return calloc(sizeof(*ctx), 1);
+}
 int
+stratcon_realtime_ticker(eventer_t old, int mask, void *closure,
+                         struct timeval *now) {
+  int f;
+  char buffer[100];
+  noit_http_session_ctx *ctx = closure;
+  f = rand() % 10;
+
+  if(!f) {
+    noit_http_response_end(ctx);
+    memset(ctx->dispatcher_closure, 0, sizeof(realtime_context));
+    if(ctx->conn.e) eventer_trigger(ctx->conn.e, EVENTER_WRITE);
+    return 0;
+  }
+
+  eventer_t e = eventer_alloc();
+  gettimeofday(&e->whence, NULL);
+  snprintf(buffer, sizeof(buffer), "[%lu] Ticker...<br />\n", e->whence.tv_sec);
+  noit_http_response_append(ctx, buffer, strlen(buffer));
+  noit_http_response_flush(ctx, false);
+
+  fprintf(stderr, " Next tick in %d seconds\n", f);
+  e->mask = EVENTER_TIMER;
+  e->whence.tv_sec += f;
+  e->callback = stratcon_realtime_ticker;
+  e->closure = closure;
+  eventer_add(e);
+  return 0;
+}
+int
 stratcon_request_dispatcher(noit_http_session_ctx *ctx) {
   const char *key, *value;
+  realtime_context *rc = ctx->dispatcher_closure;
   int klen;
   noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
   noit_http_request *req = &ctx->req;
 
-  noitL(noit_error, "http: %s %s %s\n",
-        req->method_str, req->uri_str, req->protocol_str);
-  while(noit_hash_next(&req->headers, &iter, &key, &klen, (void **)&value)) {
-    noitL(noit_error, "http: [%s: %s]\n", key, value);
+  if(strcmp(ctx->req.uri_str, "/data")) {
+    noit_http_response_status_set(ctx, 404, "OK");
+    noit_http_response_option_set(ctx, NOIT_HTTP_CLOSE);
+    noit_http_response_end(ctx);
+    return 0;
   }
-  noit_http_response_status_set(ctx, 200, "OK");
-  noit_http_response_option_set(ctx, NOIT_HTTP_CHUNKED);
-  noit_http_response_append(ctx, "Hello there!", 12);
-  noit_http_response_flush(ctx, false);
-  noit_http_response_append(ctx, "Hello there again!", 18);
-  noit_http_response_end(ctx);
-  ctx->conn.needs_close = noit_true;
-  return 0;
+  if(!rc->setup) {
+    const char *c = "<html><body><div id=\"foo\">Here</div>\n";
+    noitL(noit_error, "http: %s %s %s\n",
+          req->method_str, req->uri_str, req->protocol_str);
+    while(noit_hash_next(&req->headers, &iter, &key, &klen, (void **)&value)) {
+      noitL(noit_error, "http: [%s: %s]\n", key, value);
+    }
+    noit_http_response_status_set(ctx, 200, "OK");
+    noit_http_response_option_set(ctx, NOIT_HTTP_CHUNKED);
+    noit_http_response_option_set(ctx, NOIT_HTTP_DEFLATE);
+    noit_http_response_header_set(ctx, "Content-Type", "text/html");
+    noit_http_response_append(ctx, c, strlen(c));
+    noit_http_response_flush(ctx, false);
+    stratcon_realtime_ticker(NULL, 0, ctx, NULL);
+    rc->setup = 1;
+  }
+  return EVENTER_EXCEPTION;
 }
 
 int
@@ -42,7 +90,9 @@
   noit_http_session_ctx *http_ctx = ac->service_ctx;
   if(!http_ctx) {
     http_ctx = ac->service_ctx =
-      noit_http_session_ctx_new(stratcon_request_dispatcher, e);
+      noit_http_session_ctx_new(stratcon_request_dispatcher,
+                                alloc_realtime_context(),
+                                e);
   }
   return http_ctx->drive(e, mask, http_ctx, now);
 }



More information about the Reconnoiter-devel mailing list