Changeset 49e329e9ec43712076e6d8fa719ed3cebd9f66e7

Show
Ignore:
Timestamp:
12/05/08 04:21:49 (5 years ago)
Author:
Theo Schlossnagle <jesus@omniti.com>
git-committer:
Theo Schlossnagle <jesus@omniti.com> 1228450909 +0000
git-parent:

[4ad439d9108f1e34cf90ae8ba2709acc7b1f9b08]

git-author:
Theo Schlossnagle <jesus@omniti.com> 1228450909 +0000
Message:

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

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • src/noit_http.c

    rdf2e1eb r49e329e  
    1111#include <ctype.h> 
    1212#include <assert.h> 
     13#include <zlib.h> 
    1314 
    1415#define REQ_PAT "\r\n\r\n" 
     
    1920                      strdup(a), strlen(a), strdup(b), free, free) 
    2021static const char _hexchars[16] = 
    21   {'0','1','2','3','4','5','6','7','8','9','a','b','c','e','f'}; 
     22  {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; 
    2223 
    2324struct bchain *bchain_alloc(size_t size) { 
     
    3031  return n; 
    3132} 
     33#define RELEASE_BCHAIN(a) do { \ 
     34  while(a) { \ 
     35    struct bchain *__b; \ 
     36    __b = a; \ 
     37    a = __b->next; \ 
     38    bchain_free(__b); \ 
     39  } \ 
     40} while(0) 
    3241struct bchain *bchain_from_data(void *d, size_t size) { 
    3342  struct bchain *n; 
     
    134143static int 
    135144_http_perform_write(noit_http_session_ctx *ctx, int *mask) { 
    136   int len
     145  int len, tlen = 0
    137146  struct bchain **head, *b; 
    138147 choose_bucket: 
     
    144153  if(!b) { 
    145154    if(ctx->res.closed) ctx->res.complete = noit_true; 
    146     return EVENTER_EXCEPTION; 
     155    *mask = EVENTER_EXCEPTION; 
     156    return tlen; 
    147157  } 
    148158 
    149159  if(ctx->res.output_raw_offset >= b->size) { 
    150160    *head = b->next; 
    151     free(b); 
     161    bchain_free(b); 
    152162    b = *head; 
    153163    if(b) b->prev = NULL; 
     
    161171                b->size - ctx->res.output_raw_offset, 
    162172                mask, ctx->conn.e); 
    163   if(len == -1 && errno == EAGAIN) return (*mask | EVENTER_EXCEPTION); 
     173  if(len == -1 && errno == EAGAIN) { 
     174    *mask |= EVENTER_EXCEPTION; 
     175    return tlen; 
     176  } 
    164177  if(len == -1) { 
    165178    /* socket error */ 
    166179    ctx->conn.e->opset->close(ctx->conn.e->fd, mask, ctx->conn.e); 
    167180    ctx->conn.e = NULL; 
    168     return 0
     181    return -1
    169182  } 
    170183  ctx->res.output_raw_offset += len; 
     184  tlen += len; 
    171185  goto choose_bucket; 
    172186} 
     
    252266        next_str += 2; 
    253267      } 
    254       if(*curr_str == '\0') break; /* our CRLFCRLF... end of req */ 
     268      if(req->method_str && *curr_str == '\0') 
     269        break; /* our CRLFCRLF... end of req */ 
    255270#define FAIL do { *err = noit_true; return noit_false; } while(0) 
    256271      if(!req->method_str) { /* request line */ 
     
    266281        req->method = _method_enum(req->method_str); 
    267282        req->protocol = _protocol_enum(req->protocol_str); 
     283        if(req->protocol == NOIT_HTTP11) req->opts |= NOIT_HTTP_CHUNKED; 
    268284      } 
    269285      else { /* request headers */ 
     
    271287        if(_extract_header(curr_str, &name, &value) == noit_false) FAIL; 
    272288        if(!name && !last_name) FAIL; 
     289        if(!strcmp(name ? name : last_name, "accept-encoding")) { 
     290          if(strstr(value, "gzip")) req->opts |= NOIT_HTTP_GZIP; 
     291          if(strstr(value, "deflate")) req->opts |= NOIT_HTTP_DEFLATE; 
     292        } 
    273293        if(name) 
    274294          noit_hash_replace(&req->headers, name, strlen(name), (void *)value, 
     
    306326noit_http_complete_request(noit_http_session_ctx *ctx, int mask) { 
    307327  struct bchain *in; 
    308   noit_boolean rv, err
     328  noit_boolean rv, err = noit_false
    309329 
    310330  if(mask & EVENTER_EXCEPTION) { 
     
    355375  return EVENTER_READ | EVENTER_EXCEPTION; 
    356376} 
    357  
     377void 
     378noit_http_request_release(noit_http_session_ctx *ctx) { 
     379  noit_hash_destroy(&ctx->req.headers, NULL, NULL); 
     380  RELEASE_BCHAIN(ctx->req.first_input); 
     381  memset(&ctx->req, 0, sizeof(ctx->req)); 
     382
     383void 
     384noit_http_response_release(noit_http_session_ctx *ctx) { 
     385  noit_hash_destroy(&ctx->res.headers, free, free); 
     386  if(ctx->res.status_reason) free(ctx->res.status_reason); 
     387  RELEASE_BCHAIN(ctx->res.leader); 
     388  RELEASE_BCHAIN(ctx->res.output); 
     389  RELEASE_BCHAIN(ctx->res.output_raw); 
     390  memset(&ctx->res, 0, sizeof(ctx->res)); 
     391
    358392int 
    359 noit_http_session_drive(eventer_t e, int mask, void *closure, 
     393noit_http_session_drive(eventer_t e, int origmask, void *closure, 
    360394                        struct timeval *now) { 
    361395  noit_http_session_ctx *ctx = closure; 
    362396  int rv; 
     397  int mask = origmask; 
    363398 next_req: 
    364399  if(ctx->req.complete != noit_true) { 
    365     mask = noit_http_complete_request(ctx, mask); 
     400    mask = noit_http_complete_request(ctx, origmask); 
    366401    if(ctx->req.complete != noit_true) return mask; 
    367402  } 
    368   rv = ctx->dispatcher(ctx); 
     403 
     404  /* only dispatch if the response is not complete */ 
     405  if(ctx->res.complete == noit_false) rv = ctx->dispatcher(ctx); 
     406 
    369407  _http_perform_write(ctx, &mask); 
    370408  if(ctx->res.complete == noit_true && 
     
    373411    ctx->conn.e->opset->close(ctx->conn.e->fd, &mask, ctx->conn.e); 
    374412    ctx->conn.e = NULL; 
     413    goto release; 
    375414    return 0; 
     415  } 
     416  if(ctx->res.complete == noit_true) { 
     417    noit_http_request_release(ctx); 
     418    noit_http_response_release(ctx); 
    376419  } 
    377420  if(ctx->req.complete == noit_false) goto next_req; 
     
    380423  } 
    381424  return 0; 
     425 release: 
     426  noit_http_request_release(ctx); 
     427  noit_http_response_release(ctx); 
     428  return 0; 
    382429} 
    383430 
    384431noit_http_session_ctx * 
    385 noit_http_session_ctx_new(noit_http_dispatch_func f, eventer_t e) { 
     432noit_http_session_ctx_new(noit_http_dispatch_func f, void *c, eventer_t e) { 
    386433  noit_http_session_ctx *ctx; 
    387434  ctx = calloc(1, sizeof(*ctx)); 
     
    389436  ctx->conn.e = e; 
    390437  ctx->dispatcher = f; 
     438  ctx->dispatcher_closure = c; 
    391439  ctx->drive = noit_http_session_drive; 
    392440  return ctx; 
     
    426474        (NOIT_HTTP_GZIP | NOIT_HTTP_DEFLATE)) 
    427475    return noit_false; 
     476 
     477  /* Check out "accept" set */ 
     478  if(!(opt & ctx->req.opts)) return noit_false; 
     479 
    428480  ctx->res.output_options |= opt; 
    429481  if(ctx->res.output_options & NOIT_HTTP_CHUNKED) 
     
    540592  } 
    541593  else if(opts & NOIT_HTTP_DEFLATE) { 
     594    uLongf olen; 
     595    olen = out->allocd - out->start; 
     596    if(Z_OK != compress2((Bytef *)(out->buff + out->start), &olen, 
     597                         (Bytef *)(in->buff + in->start), (uLong)in->size, 
     598                         9)) { 
     599      noitL(noit_error, "zlib compress2 error\n"); 
     600      return noit_false; 
     601    } 
     602    out->size += olen; 
    542603  } 
    543604  else { 
     
    563624  if(hexlen == 0) hexlen = 1; 
    564625 
    565   out = bchain_alloc(hexlen + 4 + in->size); 
     626  ilen = in->size; 
     627  if(opts & NOIT_HTTP_GZIP) ilen = compressBound(ilen); 
     628  else if(opts & NOIT_HTTP_DEFLATE) ilen = compressBound(ilen); 
     629  out = bchain_alloc(hexlen + 4 + ilen); 
    566630  /* if we're chunked, let's give outselved hexlen + 2 prefix space */ 
    567631  if(opts & NOIT_HTTP_CHUNKED) out->start = hexlen + 2; 
  • src/noit_http.h

    r55168c7 r49e329e  
    5555  char *uri_str; 
    5656  char *protocol_str; 
     57  u_int32_t opts; 
    5758  noit_http_method method; 
    5859  noit_http_protocol protocol; 
     
    8788  noit_http_response res; 
    8889  noit_http_dispatch_func dispatcher; 
     90  void *dispatcher_closure; 
    8991  eventer_func_t drive; 
    9092} noit_http_session_ctx; 
    9193 
    9294API_EXPORT(noit_http_session_ctx *) 
    93   noit_http_session_ctx_new(noit_http_dispatch_func, eventer_t); 
     95  noit_http_session_ctx_new(noit_http_dispatch_func, void *, eventer_t); 
    9496 
    9597API_EXPORT(int) 
  • src/stratcon_realtime_http.c

    r55168c7 r49e329e  
    1414#include "noit_http.h" 
    1515 
     16typedef struct { 
     17  int setup; 
     18} realtime_context; 
     19 
     20static realtime_context *alloc_realtime_context() { 
     21  realtime_context *ctx; 
     22  return calloc(sizeof(*ctx), 1); 
     23} 
     24int 
     25stratcon_realtime_ticker(eventer_t old, int mask, void *closure, 
     26                         struct timeval *now) { 
     27  int f; 
     28  char buffer[100]; 
     29  noit_http_session_ctx *ctx = closure; 
     30  f = rand() % 10; 
     31 
     32  if(!f) { 
     33    noit_http_response_end(ctx); 
     34    memset(ctx->dispatcher_closure, 0, sizeof(realtime_context)); 
     35    if(ctx->conn.e) eventer_trigger(ctx->conn.e, EVENTER_WRITE); 
     36    return 0; 
     37  } 
     38 
     39  eventer_t e = eventer_alloc(); 
     40  gettimeofday(&e->whence, NULL); 
     41  snprintf(buffer, sizeof(buffer), "[%lu] Ticker...<br />\n", e->whence.tv_sec); 
     42  noit_http_response_append(ctx, buffer, strlen(buffer)); 
     43  noit_http_response_flush(ctx, false); 
     44 
     45  fprintf(stderr, " Next tick in %d seconds\n", f); 
     46  e->mask = EVENTER_TIMER; 
     47  e->whence.tv_sec += f; 
     48  e->callback = stratcon_realtime_ticker; 
     49  e->closure = closure; 
     50  eventer_add(e); 
     51  return 0; 
     52} 
    1653int 
    1754stratcon_request_dispatcher(noit_http_session_ctx *ctx) { 
    1855  const char *key, *value; 
     56  realtime_context *rc = ctx->dispatcher_closure; 
    1957  int klen; 
    2058  noit_hash_iter iter = NOIT_HASH_ITER_ZERO; 
    2159  noit_http_request *req = &ctx->req; 
    2260 
    23   noitL(noit_error, "http: %s %s %s\n", 
    24         req->method_str, req->uri_str, req->protocol_str); 
    25   while(noit_hash_next(&req->headers, &iter, &key, &klen, (void **)&value)) { 
    26     noitL(noit_error, "http: [%s: %s]\n", key, value); 
     61  if(strcmp(ctx->req.uri_str, "/data")) { 
     62    noit_http_response_status_set(ctx, 404, "OK"); 
     63    noit_http_response_option_set(ctx, NOIT_HTTP_CLOSE); 
     64    noit_http_response_end(ctx); 
     65    return 0; 
    2766  } 
    28   noit_http_response_status_set(ctx, 200, "OK"); 
    29   noit_http_response_option_set(ctx, NOIT_HTTP_CHUNKED); 
    30   noit_http_response_append(ctx, "Hello there!", 12); 
    31   noit_http_response_flush(ctx, false); 
    32   noit_http_response_append(ctx, "Hello there again!", 18); 
    33   noit_http_response_end(ctx); 
    34   ctx->conn.needs_close = noit_true; 
    35   return 0; 
     67  if(!rc->setup) { 
     68    const char *c = "<html><body><div id=\"foo\">Here</div>\n"; 
     69    noitL(noit_error, "http: %s %s %s\n", 
     70          req->method_str, req->uri_str, req->protocol_str); 
     71    while(noit_hash_next(&req->headers, &iter, &key, &klen, (void **)&value)) { 
     72      noitL(noit_error, "http: [%s: %s]\n", key, value); 
     73    } 
     74    noit_http_response_status_set(ctx, 200, "OK"); 
     75    noit_http_response_option_set(ctx, NOIT_HTTP_CHUNKED); 
     76    noit_http_response_option_set(ctx, NOIT_HTTP_DEFLATE); 
     77    noit_http_response_header_set(ctx, "Content-Type", "text/html"); 
     78    noit_http_response_append(ctx, c, strlen(c)); 
     79    noit_http_response_flush(ctx, false); 
     80    stratcon_realtime_ticker(NULL, 0, ctx, NULL); 
     81    rc->setup = 1; 
     82  } 
     83  return EVENTER_EXCEPTION; 
    3684} 
    3785 
     
    4391  if(!http_ctx) { 
    4492    http_ctx = ac->service_ctx = 
    45       noit_http_session_ctx_new(stratcon_request_dispatcher, e); 
     93      noit_http_session_ctx_new(stratcon_request_dispatcher, 
     94                                alloc_realtime_context(), 
     95                                e); 
    4696  } 
    4797  return http_ctx->drive(e, mask, http_ctx, now);