Changeset 7e47bd8ddd24e8c8c76a3f1a7ae94710d5bc4664

Show
Ignore:
Timestamp:
09/11/09 06:06:38 (5 years ago)
Author:
Theo Schlossnagle <jesus@omniti.com>
git-committer:
Theo Schlossnagle <jesus@omniti.com> 1252649198 +0000
git-parent:

[69aafdd19db047e49b9a7473ad1f51d22fa84427]

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

support HTTP POST... and use wicked black magic to supply an HTTPS interface over the existing console while maintaining backward compatibility, refs #171

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • src/Makefile.in

    r69aafdd r7e47bd8  
    4040        noit_module.o noit_conf.o noit_conf_checks.o noit_tokenizer.o \ 
    4141        noit_capabilities_listener.o noit_xml.o \ 
    42         noit_jlog_listener.o noit_livestream_listener.o noit_filters.o 
     42        noit_jlog_listener.o noit_livestream_listener.o noit_filters.o \ 
     43        noit_http.o noit_rest.o 
    4344 
    4445STRATCON_OBJS=stratcond.o noit_listener.o \ 
  • src/noit_http.c

    r88a7178 r7e47bd8  
    4242#define REQ_PAT "\r\n\r\n" 
    4343#define REQ_PATSIZE 4 
     44#define HEADER_CONTENT_LENGTH "content-length" 
     45#define HEADER_EXPECT "expect" 
    4446 
    4547#define CTX_ADD_HEADER(a,b) \ 
     
    6668  } \ 
    6769} while(0) 
    68 struct bchain *bchain_from_data(void *d, size_t size) { 
     70struct bchain *bchain_from_data(const void *d, size_t size) { 
    6971  struct bchain *n; 
    7072  n = bchain_alloc(size); 
     
    8688   case 'H': 
    8789    if(!strcasecmp(s, "HEAD")) return NOIT_HTTP_HEAD; 
     90    break; 
     91   case 'P': 
     92    if(!strcasecmp(s, "POST")) return NOIT_HTTP_POST; 
    8893    break; 
    8994   default: 
     
    177182 
    178183  if(!ctx->conn.e) return 0; 
     184#if 0 
    179185  if(ctx->res.output_started == noit_false) return EVENTER_EXCEPTION; 
     186#endif 
    180187  if(!b) { 
    181188    if(ctx->res.closed) ctx->res.complete = noit_true; 
     
    213220} 
    214221static noit_boolean 
    215 noit_http_request_finalize(noit_http_request *req, noit_boolean *err) { 
     222noit_http_request_finalize_headers(noit_http_request *req, noit_boolean *err) { 
    216223  int start; 
     224  void *vval; 
    217225  const char *mstr, *last_name = NULL; 
    218226  struct bchain *b; 
    219227 
     228if(req->first_input && req->first_input->size) { 
     229noitL(noit_error, "HTTP REQ (headers): ===>%.*s<===\n", 
     230req->first_input->size, req->first_input->buff + req->first_input->start); 
     231} 
     232  if(req->state != NOIT_HTTP_REQ_HEADERS) return noit_false; 
    220233  if(!req->current_input) req->current_input = req->first_input; 
    221234  if(!req->current_input) return noit_false; 
     
    265278             req->current_input->start + req->current_offset, 
    266279           req->first_input->size); 
    267     if(req->last_input == req->current_request_chain
     280    if(req->last_input == req->current_input
    268281      req->last_input = req->first_input; 
    269282  } 
     
    347360    } while(next_str); 
    348361  } 
     362 
     363  /* headers are done... we could need to read a payload */ 
     364  if(noit_hash_retrieve(&req->headers, 
     365                        HEADER_CONTENT_LENGTH, 
     366                        sizeof(HEADER_CONTENT_LENGTH)-1, &vval)) { 
     367    const char *val = vval; 
     368    req->has_payload = noit_true; 
     369    req->content_length = strtoll(val, NULL, 10); 
     370  } 
     371  if(noit_hash_retrieve(&req->headers, HEADER_EXPECT, 
     372                        sizeof(HEADER_EXPECT)-1, &vval)) { 
     373    const char *val = vval; 
     374    if(strncmp(val, "100-", 4) || /* Bad expect header */ 
     375       req->has_payload == noit_false) /* expect, but no content length */ 
     376      FAIL; 
     377    /* We need to tell the client to "go-ahead" -- HTTP sucks */ 
     378    req->state = NOIT_HTTP_REQ_EXPECT; 
     379    return noit_false; 
     380  } 
     381  if(req->content_length > 0) { 
     382    /* switch modes... let's go read the payload */ 
     383    req->state = NOIT_HTTP_REQ_PAYLOAD; 
     384    return noit_false; 
     385  } 
     386 
    349387  req->complete = noit_true; 
    350388  return noit_true; 
     389} 
     390static noit_boolean 
     391noit_http_request_finalize_payload(noit_http_request *req, noit_boolean *err) { 
     392  req->complete = noit_true; 
     393  return noit_true; 
     394} 
     395static noit_boolean 
     396noit_http_request_finalize(noit_http_request *req, noit_boolean *err) { 
     397  if(req->state == NOIT_HTTP_REQ_HEADERS) 
     398    if(noit_http_request_finalize_headers(req, err)) return noit_true; 
     399  if(req->state == NOIT_HTTP_REQ_EXPECT) return noit_false; 
     400  if(req->state == NOIT_HTTP_REQ_PAYLOAD) 
     401    if(noit_http_request_finalize_payload(req, err)) return noit_true; 
     402  return noit_false; 
    351403} 
    352404int 
     
    391443                                   in->allocd - in->size - in->start, 
    392444                                   &mask, ctx->conn.e); 
     445noitL(noit_error, "HTTP REQ (drive read %d)\n", len); 
    393446    if(len == -1 && errno == EAGAIN) return mask; 
    394447    if(len <= 0) goto full_error; 
    395448    if(len > 0) in->size += len; 
    396449    rv = noit_http_request_finalize(&ctx->req, &err); 
    397     if(len == -1 || err == noit_true) { 
    398       goto full_error; 
    399     } 
    400     if(rv == noit_true) return EVENTER_WRITE | EVENTER_EXCEPTION; 
     450    if(len == -1 || err == noit_true) goto full_error; 
     451    if(ctx->req.state == NOIT_HTTP_REQ_EXPECT) { 
     452      const char *expect; 
     453      ctx->req.state = NOIT_HTTP_REQ_PAYLOAD; 
     454      assert(ctx->res.leader == NULL); 
     455      expect = "HTTP/1.1 100 Continue\r\n\r\n"; 
     456      ctx->res.leader = bchain_from_data(expect, strlen(expect)); 
     457      _http_perform_write(ctx, &mask); 
     458      if(ctx->res.leader != NULL) return mask; 
     459    } 
     460    if(rv == noit_true) return mask | EVENTER_WRITE | EVENTER_EXCEPTION; 
    401461  } 
    402462  return EVENTER_READ | EVENTER_EXCEPTION; 
    403463} 
     464noit_boolean 
     465noit_http_session_prime_input(noit_http_session_ctx *ctx, 
     466                              const void *data, size_t len) { 
     467  if(ctx->req.first_input != NULL) return noit_false; 
     468  if(len > DEFAULT_BCHAINSIZE) return noit_false; 
     469  ctx->req.first_input = ctx->req.last_input = 
     470      bchain_alloc(DEFAULT_BCHAINSIZE); 
     471  memcpy(ctx->req.first_input->buff, data, len); 
     472  ctx->req.first_input->size = len; 
     473  return noit_true; 
     474} 
     475 
    404476void 
    405477noit_http_request_release(noit_http_session_ctx *ctx) { 
    406478  noit_hash_destroy(&ctx->req.headers, NULL, NULL); 
    407   RELEASE_BCHAIN(ctx->req.first_input); 
     479  /* If we expected a payload, we expect a trailing \r\n */ 
     480  if(ctx->req.has_payload) { 
     481    int drained, mask; 
     482    ctx->drainage = ctx->req.content_length - ctx->req.content_length_read; 
     483    /* best effort, we'll drain it before the next request anyway */ 
     484    drained = noit_http_session_req_consume(ctx, NULL, ctx->drainage, &mask); 
     485    ctx->drainage -= drained; 
     486  } 
     487  RELEASE_BCHAIN(ctx->req.current_request_chain); 
    408488  memset(&ctx->req, 0, sizeof(ctx->req)); 
    409489} 
     
    426506} 
    427507int 
     508noit_http_session_req_consume(noit_http_session_ctx *ctx, 
     509                              void *buf, size_t len, int *mask) { 
     510  size_t bytes_read = 0; 
     511  /* We attempt to consume from the first_input */ 
     512  struct bchain *in, *tofree; 
     513  len = MIN(len, ctx->req.content_length - ctx->req.content_length_read); 
     514  while(bytes_read < len) { 
     515    int crlen = 0; 
     516    in = ctx->req.first_input; 
     517    while(in && bytes_read < len) { 
     518      int partial_len = MIN(in->size, len - bytes_read); 
     519      bytes_read += partial_len; 
     520      if(buf) memcpy(buf+bytes_read, in->buff+in->start, partial_len); 
     521noitL(noit_error, "HTTP REQ (consume) : ===>%.*s<===\n", 
     522partial_len, in->buff+in->start); 
     523      ctx->req.content_length_read += partial_len; 
     524      in->start += partial_len; 
     525      in->size -= partial_len; 
     526      if(in->size == 0) { 
     527        tofree = in; 
     528        ctx->req.first_input = in = in->next; 
     529        tofree->next = NULL; 
     530        RELEASE_BCHAIN(tofree); 
     531        if(in == NULL) { 
     532          ctx->req.last_input = NULL; 
     533          return bytes_read; 
     534        } 
     535      } 
     536    } 
     537    while(bytes_read + crlen < len) { 
     538      int rlen; 
     539      in = ctx->req.last_input; 
     540      if(!in) 
     541        in = ctx->req.first_input = ctx->req.last_input = 
     542            bchain_alloc(DEFAULT_BCHAINSIZE); 
     543      else if(in->start + in->size >= in->allocd) { 
     544        in->next = bchain_alloc(DEFAULT_BCHAINSIZE); 
     545        in = ctx->req.last_input = in->next; 
     546      } 
     547      /* pull next chunk */ 
     548      rlen = ctx->conn.e->opset->read(ctx->conn.e->fd, 
     549                                      in->buff + in->start + in->size, 
     550                                      in->allocd - in->size - in->start, 
     551                                      mask, ctx->conn.e); 
     552noitL(noit_error, "HTTP REQ (consume read %d)\n", rlen); 
     553      if(rlen == -1 && errno == EAGAIN) { 
     554         /* We'd block to read more, but we have data, 
     555          * so do a short read */ 
     556         if(ctx->req.first_input->size) break; 
     557         /* We've got nothing... */ 
     558         return -1; 
     559      } 
     560      if(rlen <= 0) return -1; 
     561      in->size += rlen; 
     562      crlen += rlen; 
     563    } 
     564  } 
     565  /* NOT REACHED */ 
     566  return bytes_read; 
     567} 
     568int 
    428569noit_http_session_drive(eventer_t e, int origmask, void *closure, 
    429570                        struct timeval *now) { 
     
    431572  int rv; 
    432573  int mask = origmask; 
     574 
     575  /* Drainage -- this is as nasty as it sounds  
     576   * The last request could have unread upload content, we would have 
     577   * noted that in noit_http_request_release. 
     578   */ 
     579  while(ctx->drainage > 0) { 
     580    int len; 
     581    len = noit_http_session_req_consume(ctx, NULL, ctx->drainage, &mask); 
     582    if(len == -1 && errno == EAGAIN) return mask; 
     583    if(len <= 0) goto abort_drive; 
     584    ctx->drainage -= len; 
     585  } 
     586 
    433587 next_req: 
    434588  if(ctx->req.complete != noit_true) { 
     589    int maybe_write_mask; 
    435590    mask = noit_http_complete_request(ctx, origmask); 
    436     if(ctx->req.complete != noit_true) return mask; 
     591    _http_perform_write(ctx, &maybe_write_mask); 
     592    if(ctx->req.complete != noit_true) return mask | maybe_write_mask; 
    437593  } 
    438594 
     
    444600     ctx->conn.e && 
    445601     ctx->conn.needs_close == noit_true) { 
     602   abort_drive: 
    446603    ctx->conn.e->opset->close(ctx->conn.e->fd, &mask, ctx->conn.e); 
    447604    ctx->conn.e = NULL; 
     
    455612  if(ctx->req.complete == noit_false) goto next_req; 
    456613  if(ctx->conn.e) { 
    457     return mask
     614    return mask | rv
    458615  } 
    459616  return 0; 
     
    684841                                struct bchain *in) { 
    685842  struct bchain *out; 
    686   int ilen, hexlen; 
     843  int ilen, maxlen, hexlen; 
    687844  int opts = ctx->res.output_options; 
    688845 
    689846  /* a chunked header looks like: hex*\r\ndata\r\n */ 
    690847  /* let's assume that content never gets "larger" */ 
     848  if(opts & NOIT_HTTP_GZIP) maxlen = deflateBound(NULL, in->size); 
     849  else if(opts & NOIT_HTTP_DEFLATE) maxlen = compressBound(in->size); 
     850 
    691851  /* So, the link size is the len(data) + 4 + ceil(log(len(data))/log(16)) */ 
    692   ilen = in->size
     852  ilen = maxlen
    693853  hexlen = 0; 
    694854  while(ilen) { ilen >>= 4; hexlen++; } 
    695855  if(hexlen == 0) hexlen = 1; 
    696856 
    697   ilen = in->size; 
    698   if(opts & NOIT_HTTP_GZIP) ilen = deflateBound(NULL, ilen); 
    699   else if(opts & NOIT_HTTP_DEFLATE) ilen = compressBound(ilen); 
    700   out = bchain_alloc(hexlen + 4 + ilen); 
     857  out = bchain_alloc(hexlen + 4 + maxlen); 
    701858  /* if we're chunked, let's give outselved hexlen + 2 prefix space */ 
    702859  if(opts & NOIT_HTTP_CHUNKED) out->start = hexlen + 2; 
  • src/noit_http.h

    r88a7178 r7e47bd8  
    4040 
    4141typedef enum { 
    42   NOIT_HTTP_OTHER, NOIT_HTTP_GET, NOIT_HTTP_HEAD 
     42  NOIT_HTTP_OTHER, NOIT_HTTP_GET, NOIT_HTTP_HEAD, NOIT_HTTP_POST 
    4343} noit_http_method; 
    4444typedef enum { 
     
    7979  size_t         current_offset; /* analyzing. */ 
    8080 
     81  enum { NOIT_HTTP_REQ_HEADERS = 0, 
     82         NOIT_HTTP_REQ_EXPECT, 
     83         NOIT_HTTP_REQ_PAYLOAD } state; 
    8184  struct bchain *current_request_chain; 
     85  noit_boolean has_payload; 
     86  int64_t content_length; 
     87  int64_t content_length_read; 
    8288  char *method_str; 
    8389  char *uri_str; 
     
    113119typedef struct noit_http_session_ctx { 
    114120  noit_atomic32_t ref_cnt; 
     121  int64_t drainage; 
    115122  noit_http_connection conn; 
    116123  noit_http_request req; 
     
    130137 
    131138API_EXPORT(noit_boolean) 
     139  noit_http_session_prime_input(noit_http_session_ctx *, const void *, size_t); 
     140API_EXPORT(int) 
     141  noit_http_session_req_consume(noit_http_session_ctx *ctx, 
     142                                void *buf, size_t len, int *mask); 
     143API_EXPORT(noit_boolean) 
    132144  noit_http_response_status_set(noit_http_session_ctx *, int, const char *); 
    133145API_EXPORT(noit_boolean) 
  • src/noitd.c

    rb9a4230 r7e47bd8  
    5252#include "noit_console.h" 
    5353#include "noit_jlog_listener.h" 
     54#include "noit_rest.h" 
    5455#include "noit_livestream_listener.h" 
    5556#include "noit_capabilities_listener.h" 
     
    181182  noit_capabilities_listener_init(); 
    182183  noit_jlog_listener_init(); 
     184  noit_http_rest_init(); 
    183185  noit_livestream_listener_init(); 
    184186