Show
Ignore:
Timestamp:
01/05/11 05:20:58 (8 years ago)
Author:
Theo Schlossnagle <jesus@omniti.com>
git-committer:
Theo Schlossnagle <jesus@omniti.com> 1294204858 +0000
git-parent:

[6de024fe1a245773c4b8c107f9063f2f40e5c344]

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

implement and prefer gzip

Files:

Legend:

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

    r6de024f r84b15c2  
    9595  noit_boolean complete;       /* complete, drained and disposable */ 
    9696  size_t bytes_written;        /* tracks total bytes written */ 
     97  z_stream *gzip; 
    9798}; 
    9899 
     
    112113static noit_log_stream_t http_io = NULL; 
    113114static noit_log_stream_t http_access = NULL; 
     115 
     116static const char gzip_header[10] = 
     117  { '\037', '\213', Z_DEFLATED, 0, 0, 0, 0, 0, 0, 0x03 }; 
    114118 
    115119#define CTX_ADD_HEADER(a,b) \ 
     
    739743  RELEASE_BCHAIN(ctx->res.output); 
    740744  RELEASE_BCHAIN(ctx->res.output_raw); 
     745  if(ctx->res.gzip) { 
     746    deflateEnd(ctx->res.gzip); 
     747    free(ctx->res.gzip); 
     748  } 
    741749  memset(&ctx->res, 0, sizeof(ctx->res)); 
    742750} 
     
    10841092  return len; 
    10851093} 
    1086 static int memgzip2(Bytef *dest, uLongf *destLen, 
    1087                     const Bytef *source, uLong sourceLen, int level) { 
     1094static int memgzip2(noit_http_response *res, Bytef *dest, uLongf *destLen, 
     1095                    const Bytef *source, uLong sourceLen, int level, 
     1096                    int deflate_option, noit_boolean *done) { 
    10881097  z_stream stream; 
    1089   int err; 
    1090  
    1091   memset(&stream, 0, sizeof(stream)); 
    1092   stream.next_in = (Bytef*)source; 
    1093   stream.avail_in = (uInt)sourceLen; 
    1094   stream.next_out = dest; 
    1095   stream.avail_out = (uInt)*destLen; 
    1096   if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; 
    1097  
    1098   err = deflateInit2(&stream, level, Z_DEFLATED, 15+16, 8, 
    1099                      Z_DEFAULT_STRATEGY); 
    1100   if (err != Z_OK) return err; 
    1101  
    1102   err = deflate(&stream, Z_FINISH); 
    1103   if (err != Z_STREAM_END) { 
    1104     deflateEnd(&stream); 
     1098  int err, skip=0, expect = Z_OK; 
     1099  if(!res->gzip) { 
     1100    res->gzip = calloc(1, sizeof(*res->gzip)); 
     1101    err = deflateInit2(res->gzip, level, Z_DEFLATED, -15, 9, 
     1102                       Z_DEFAULT_STRATEGY); 
     1103    if (err != Z_OK) { 
     1104      noitL(noit_error, "memgzip2() -> deflateInit2: %d\n", err); 
     1105      return err; 
     1106    } 
     1107 
     1108    memcpy(dest, gzip_header, sizeof(gzip_header)); 
     1109    skip = sizeof(gzip_header); 
     1110    *destLen -= skip; 
     1111  } 
     1112  res->gzip->next_in = (Bytef*)source; 
     1113  res->gzip->avail_in = (uInt)sourceLen; 
     1114  res->gzip->next_out = dest + skip; 
     1115  res->gzip->avail_out = (uInt)*destLen; 
     1116  if ((uLong)res->gzip->avail_out != *destLen) return Z_BUF_ERROR; 
     1117 
     1118  err = deflate(res->gzip, deflate_option); 
     1119 
     1120  if(deflate_option == Z_FINISH) expect = Z_STREAM_END; 
     1121  if (err != expect) { 
     1122    noitL(noit_error, "memgzip2() -> deflate: got %d, need %d\n", err, expect); 
     1123    deflateEnd(res->gzip); 
     1124    free(res->gzip); 
     1125    res->gzip = NULL; 
    11051126    return err == Z_OK ? Z_BUF_ERROR : err; 
    11061127  } 
    1107   *destLen = stream.total_out
    1108  
    1109   err = deflateEnd(&stream); 
    1110   return err
     1128  if(done) *done = (err == Z_STREAM_END) ? noit_true : noit_false
     1129  *destLen = res->gzip->total_out + skip; 
     1130 
     1131  return Z_OK
    11111132} 
    11121133static noit_boolean 
    1113 _http_encode_chain(struct bchain *out, struct bchain *in, int opts) { 
     1134_http_encode_chain(noit_http_response *res, 
     1135                   struct bchain *out, void *inbuff, int inlen, 
     1136                   noit_boolean final, noit_boolean *done) { 
     1137  int opts = res->output_options; 
    11141138  /* implement gzip and deflate! */ 
     1139  if(done && final) *done = noit_true; 
    11151140  if(opts & NOIT_HTTP_GZIP) { 
    11161141    uLongf olen; 
     1142    int err; 
    11171143    olen = out->allocd - out->start; 
    1118     if(Z_OK != memgzip2((Bytef *)(out->buff + out->start), &olen, 
    1119                         (Bytef *)(in->buff + in->start), (uLong)in->size, 
    1120                         9)) { 
    1121       noitL(noit_error, "zlib compress2 error\n"); 
     1144    err = memgzip2(res, (Bytef *)(out->buff + out->start), &olen, 
     1145                   (Bytef *)(inbuff), (uLong)inlen, 
     1146                   9, final ? Z_FINISH : Z_NO_FLUSH, done); 
     1147    if(Z_OK != err) { 
     1148      noitL(noit_error, "zlib compress2 error %d\n", err); 
    11221149      return noit_false; 
    11231150    } 
     
    11281155    olen = out->allocd - out->start; 
    11291156    if(Z_OK != compress2((Bytef *)(out->buff + out->start), &olen, 
    1130                          (Bytef *)(in->buff + in->start), (uLong)in->size
     1157                         (Bytef *)(inbuff), (uLong)inlen
    11311158                         9)) { 
    11321159      noitL(noit_error, "zlib compress2 error\n"); 
     
    11361163  } 
    11371164  else { 
    1138     if(in->size > out->allocd - out->start) return noit_false; 
    1139     memcpy(out->buff + out->start, in->buff + in->start, in->size); 
    1140     out->size += in->size
     1165    if(inlen > out->allocd - out->start) return noit_false; 
     1166    memcpy(out->buff + out->start, inbuff, inlen); 
     1167    out->size += inlen
    11411168  } 
    11421169  return noit_true; 
     
    11731200  /* if we're chunked, let's give outselved hexlen + 2 prefix space */ 
    11741201  if(opts & NOIT_HTTP_CHUNKED) out->start = hexlen + 2; 
    1175   if(_http_encode_chain(out, in, opts) == noit_false) { 
     1202  if(_http_encode_chain(&ctx->res, out,in->buff + in->start, in->size, 
     1203                        noit_false, NULL) == noit_false) { 
    11761204    free(out); 
    11771205    return NULL; 
    11781206  } 
    1179   /* Too long! Out "larger" assumption is bad */ 
    1180   if(opts & NOIT_HTTP_CHUNKED) { 
     1207  if(out->size == 0) { 
     1208    FREE_BCHAIN(out); 
     1209    out = ALLOC_BCHAIN(0); 
     1210    noitL(noit_error, "_http_encode_chain() -> 0...\n"); 
     1211  } 
     1212  if((out->size > 0) && (opts & NOIT_HTTP_CHUNKED)) { 
    11811213    ilen = out->size; 
    11821214    assert(out->start+out->size+2 <= out->allocd); 
     
    12021234  return out; 
    12031235} 
     1236void 
     1237raw_finalize_encoding(noit_http_response *res) { 
     1238  void *buff; 
     1239  buff = alloca(2048); 
     1240  uLong olen = 2048; 
     1241 
     1242  if(res->output_options & NOIT_HTTP_GZIP) { 
     1243    int err = Z_OK; 
     1244    noit_boolean finished = noit_false; 
     1245    struct bchain *r = res->output_raw; 
     1246    while(r && r->next) r = r->next; 
     1247    while(finished == noit_false) { 
     1248      int hexlen, ilen; 
     1249      struct bchain *out = ALLOC_BCHAIN(DEFAULT_BCHAINSIZE); 
     1250 
     1251      /* The link size is the len(data) + 4 + ceil(log(len(data))/log(16)) */ 
     1252      ilen = out->allocd; 
     1253      hexlen = 0; 
     1254      while(ilen) { ilen >>= 4; hexlen++; } 
     1255      if(hexlen == 0) hexlen = 1; 
     1256 
     1257      out->start += hexlen + 2; 
     1258      if(_http_encode_chain(res, out, "", 0, noit_true, 
     1259                            &finished) == noit_false) { 
     1260        FREE_BCHAIN(out); 
     1261        break; 
     1262      } 
     1263 
     1264      ilen = out->size; 
     1265      assert(out->start+out->size+2 <= out->allocd); 
     1266      out->buff[out->start + out->size++] = '\r'; 
     1267      out->buff[out->start + out->size++] = '\n'; 
     1268      out->start = 0; 
     1269      /* terminate */ 
     1270      out->size += 2; 
     1271      out->buff[hexlen] = '\r'; 
     1272      out->buff[hexlen+1] = '\n'; 
     1273      /* backfill */ 
     1274      out->size += hexlen; 
     1275      while(hexlen > 0) { 
     1276        out->buff[hexlen - 1] = _hexchars[ilen & 0xf]; 
     1277        ilen >>= 4; 
     1278        hexlen--; 
     1279      } 
     1280      while(out->buff[out->start] == '0') { 
     1281        out->start++; 
     1282        out->size--; 
     1283      } 
     1284      if(r == NULL) 
     1285        res->output_raw = out; 
     1286      else { 
     1287        r->next = out; 
     1288        out->prev = r; 
     1289      } 
     1290      r = out; 
     1291    } 
     1292 
     1293    deflateEnd(res->gzip); 
     1294    free(res->gzip); 
     1295    res->gzip = NULL; 
     1296  } 
     1297} 
    12041298noit_boolean 
    12051299noit_http_response_flush(noit_http_session_ctx *ctx, noit_boolean final) { 
     
    12421336    struct bchain *n; 
    12431337    ctx->res.closed = noit_true; 
     1338    raw_finalize_encoding(&ctx->res); 
     1339    if(r) while(r->next) r = r->next; 
    12441340    if(ctx->res.output_options & NOIT_HTTP_CHUNKED) 
    12451341      n = bchain_from_data("0\r\n\r\n", 5);