# HG changeset patch # User Igor Sysoev # Date 1064555121 0 # Node ID d57c6835225c257a6a974bbe74ab520fa6167635 # Parent b27548f540adf98c777cbec26da9e624e22c28e8 nginx-0.0.1-2003-09-26-09:45:21 import diff --git a/src/core/ngx_hunk.c b/src/core/ngx_hunk.c --- a/src/core/ngx_hunk.c +++ b/src/core/ngx_hunk.c @@ -99,6 +99,30 @@ ngx_hunk_t *ngx_create_hunk_after(ngx_po } +int ngx_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **ch, ngx_chain_t *in) +{ + ngx_chain_t *ce, **le; + + le = ch; + + for (ce = *ch; ce; ce = ce->next) { + le = &ce->next; + } + + while (in) { + ngx_test_null(ce, ngx_alloc_chain_entry(pool), NGX_ERROR); + + ce->hunk = in->hunk; + ce->next = NULL; + *le = ce; + le = &ce->next; + in = in->next; + } + + return NGX_OK; +} + + void ngx_chain_update_chains(ngx_chain_t **free, ngx_chain_t **busy, ngx_chain_t **out) { diff --git a/src/core/ngx_hunk.h b/src/core/ngx_hunk.h --- a/src/core/ngx_hunk.h +++ b/src/core/ngx_hunk.h @@ -86,5 +86,10 @@ ngx_hunk_t *ngx_create_temp_hunk(ngx_poo chain->next = NULL; \ } while (0); +int ngx_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **ch, ngx_chain_t *in); +void ngx_chain_update_chains(ngx_chain_t **free, ngx_chain_t **busy, + ngx_chain_t **out); + + #endif /* _NGX_HUNK_H_INCLUDED_ */ diff --git a/src/core/ngx_modules.c b/src/core/ngx_modules.c --- a/src/core/ngx_modules.c +++ b/src/core/ngx_modules.c @@ -33,6 +33,7 @@ extern ngx_module_t ngx_http_output_fil extern ngx_module_t ngx_http_header_filter_module; extern ngx_module_t ngx_http_chunked_filter_module; +extern ngx_module_t ngx_http_gzip_filter_module; extern ngx_module_t ngx_http_range_filter_module; extern ngx_module_t ngx_http_charset_filter_module; @@ -81,7 +82,7 @@ ngx_module_t *ngx_modules[] = { &ngx_http_header_filter_module, &ngx_http_chunked_filter_module, - /* &ngx_http_gzip_filter_module, */ + &ngx_http_gzip_filter_module, &ngx_http_range_filter_module, /* &ngx_http_ssi_filter_module, */ &ngx_http_charset_filter_module, diff --git a/src/http/modules/ngx_http_gzip_filter.c b/src/http/modules/ngx_http_gzip_filter.c --- a/src/http/modules/ngx_http_gzip_filter.c +++ b/src/http/modules/ngx_http_gzip_filter.c @@ -7,8 +7,9 @@ typedef struct { + int enable; int hunk_size; - int max_hunks; + int hunks; int no_buffer; } ngx_http_gzip_conf_t; @@ -21,13 +22,56 @@ typedef struct { ngx_chain_t **last_out; ngx_hunk_t *in_hunk; ngx_hunk_t *out_hunk; + int hunks; + + int length; void *alloc; + int flush; + u_int crc32; z_stream zstream; } ngx_http_gzip_ctx_t; +ngx_inline static int ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx); static int ngx_http_gzip_filter_init(ngx_cycle_t *cycle); +static void *ngx_http_gzip_create_conf(ngx_conf_t *cf); +static char *ngx_http_gzip_merge_conf(ngx_conf_t *cf, + void *parent, void *child); + + +static ngx_command_t ngx_http_gzip_filter_commands[] = { + + {ngx_string("gzip"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_gzip_conf_t, enable), + NULL}, + + {ngx_string("gzip_hunk_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_gzip_conf_t, hunk_size), + NULL}, + + {ngx_string("gzip_hunks"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_gzip_conf_t, hunks), + NULL}, + + {ngx_string("gzip_no_buffer"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_gzip_conf_t, no_buffer), + NULL}, + + ngx_null_command +}; static ngx_http_module_t ngx_http_gzip_filter_module_ctx = { @@ -37,23 +81,39 @@ static ngx_http_module_t ngx_http_gzip_ NULL, /* create server configuration */ NULL, /* merge server configuration */ - NULL, /* create location configuration */ - NULL, /* merge location configuration */ + ngx_http_gzip_create_conf, /* create location configuration */ + ngx_http_gzip_merge_conf, /* merge location configuration */ }; ngx_module_t ngx_http_gzip_filter_module = { NGX_MODULE, &ngx_http_gzip_filter_module_ctx, /* module context */ - NULL, /* module directives */ + ngx_http_gzip_filter_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ ngx_http_gzip_filter_init, /* init module */ NULL /* init child */ }; -static const char gzheader[10] = - { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 }; +static char gzheader[10] = { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 }; + +#if (HAVE_LITTLE_ENDIAN) + +struct gztrailer { + u_int crc32; + u_int zlen; +}; + +#else /* HAVE_BIG_ENDIAN */ + +struct gztrailer { + unsigned char crc32[4]; + unsigned char zlen[4]; +}; + +#endif + static int (*next_header_filter) (ngx_http_request_t *r); @@ -62,18 +122,35 @@ static int (*next_body_filter) (ngx_http static int ngx_http_gzip_header_filter(ngx_http_request_t *r) { + ngx_http_gzip_ctx_t *ctx; + ngx_http_gzip_conf_t *conf; + if (r->headers_out.status != NGX_HTTP_OK - || (ngx_strncasecmp(r->headers_out.content_type->value.data, + || r->header_only + /* || r->content_encoding */ + /* || r->accept_encoding == NULL */ + || r->main) + { + return next_header_filter(r); + } + + conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module); + + if (!conf->enable + /* TODO: conf->version */ + /* TODO: "text/" -> custom types */ + || ngx_strncasecmp(r->headers_out.content_type->value.data, "text/", 5) != 0) { return next_header_filter(r); } ngx_http_create_ctx(r, ctx, ngx_http_gzip_filter_module, - sizeof(ngx_http_gzip_filter_ctx_t), NGX_ERROR); + sizeof(ngx_http_gzip_ctx_t), NGX_ERROR); ctx->length = r->headers_out.content_length; r->headers_out.content_length = -1; + r->filter |= NGX_HTTP_FILTER_NEED_IN_MEMORY; return next_header_filter(r); } @@ -81,13 +158,17 @@ static int ngx_http_gzip_header_filter(n static int ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { + int rc, zin, zout; + struct gztrailer *trailer; + ngx_hunk_t *h; + ngx_chain_t *ce; ngx_http_gzip_ctx_t *ctx; ngx_http_gzip_conf_t *conf; ctx = ngx_http_get_module_ctx(r, ngx_http_gzip_filter_module); if (ctx == NULL) { - next_body_filter(r, in); + return next_body_filter(r, in); } conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module); @@ -96,14 +177,14 @@ static int ngx_http_gzip_body_filter(ngx #if 0 ngx_test_null(ctx->alloc, ngx_alloc(200K, r->log), NGX_ERROR); #else - ctx->alloc = ~NULL; + ctx->alloc = (void *) ~NULL; #endif rc = deflateInit2(&ctx->zstream, /**/ 1, Z_DEFLATED, /**/ -MAX_WBITS, /**/ MAX_MEM_LEVEL - 1, Z_DEFAULT_STRATEGY); if (rc != Z_OK) { - ngx_log_error(NGX_LOG_ALERT, r->log, 0, + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "deflateInit2() failed: %d", rc); return ngx_http_gzip_error(ctx); } @@ -126,100 +207,153 @@ static int ngx_http_gzip_body_filter(ngx } if (in) { - add_to_chain(ctx->in, in) + if (ngx_chain_add_copy(r->pool, &ctx->in, in) == NGX_ERROR) { + return ngx_http_gzip_error(ctx); + } } - for ( ;; ) { - + while (ctx->in || ctx->out + || ctx->zstream.avail_in || ctx->zstream.avail_out + || ctx->flush != Z_NO_FLUSH) + { for ( ;; ) { - if (ctx->flush == Z_NO_FLUSH - && ctx->zstream->avail_in == 0 - && ctx->in) - { + if (ctx->in + && ctx->zstream.avail_in == 0 + && ctx->flush == Z_NO_FLUSH) + { ctx->in_hunk = ctx->in->hunk; ctx->in = ctx->in->next; - ctx->zstream->next_in = ctx->in_hunk->pos; - ctx->zstream->avail_in = ctx->in_hunk->last - ctx->in_hunk->pos; + ctx->zstream.avail_in = ctx->in_hunk->last - ctx->in_hunk->pos; + + if (ctx->zstream.avail_in == 0) { + continue; + } + + ctx->zstream.next_in = ctx->in_hunk->pos; + + ctx->crc32 = crc32(ctx->crc32, ctx->zstream.next_in, + ctx->zstream.avail_in); if (ctx->in_hunk->type & NGX_HUNK_LAST) { ctx->flush = Z_FINISH; } else if (ctx->in_hunk->type & NGX_HUNK_FLUSH) { - ctx->flush = Z_SYNC_FINISH; + ctx->flush = Z_SYNC_FLUSH; } } - if (ctx->zstream->avail_out == 0) { + if (ctx->zstream.avail_out == 0) { if (ctx->free) { ctx->out_hunk = ctx->free->hunk; ctx->free = ctx->free->next; - } else if (ctx->max_hunks < ctx->cur_hunks) { + } else if (ctx->hunks < conf->hunks) { ngx_test_null(ctx->out_hunk, - ngx_create_temp_hunk(r->pool, conf->size, + ngx_create_temp_hunk(r->pool, conf->hunk_size, 0, 0), ngx_http_gzip_error(ctx)); - ctx->cur_hunks++; + ctx->hunks++; } else { break; } - ctx->zstream->next_out = ctx->out_hunk->pos; - ctx->zstream->avail_out = conf->size; + ctx->zstream.next_out = ctx->out_hunk->pos; + ctx->zstream.avail_out = conf->hunk_size; } - rc = deflate(ctx->zstream, ctx->flush); + rc = deflate(&ctx->zstream, ctx->flush); if (rc != Z_OK && rc != Z_STREAM_END) { - ngx_log_error(NGX_LOG_ALERT, r->log, 0, + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "deflate() failed: %d, %d", ctx->flush, rc); return ngx_http_gzip_error(ctx); } - ctx->in_hunk->pos = ctx->zstream->next_in; +ngx_log_debug(r->connection->log, "deflate(): %d %d" _ ctx->flush _ rc); + + ctx->in_hunk->pos = ctx->zstream.next_in; - if (rc == Z_STREAM_END) { - deflateEnd(ctx->zstream); - ngx_free(); - } - - if (ctx->zstream->avail_out == 0) { - ctx->out_hunk->last += conf->size; - ngx_add_hunk_to_chain(*ctx->last_out, ctx->out_hunk, - r->pool, ngx_http_gzip_error(ctx)); + if (ctx->zstream.avail_out == 0) { + ctx->out_hunk->last += conf->hunk_size; + ngx_add_hunk_to_chain(ce, ctx->out_hunk, r->pool, + ngx_http_gzip_error(ctx)); + *ctx->last_out = ce; + ctx->last_out = &ce->next; } else { - ctx->out_hunk->last = ctx->zstream->next_out; + ctx->out_hunk->last = ctx->zstream.next_out; if (ctx->flush == Z_SYNC_FLUSH) { ctx->out_hunk->type |= NGX_HUNK_FLUSH; - ngx_add_hunk_to_chain(*ctx->last_out, ctx->out_hunk, - r->pool, ngx_http_gzip_error(ctx)); ctx->flush = Z_NO_FLUSH; + + ngx_add_hunk_to_chain(ce, ctx->out_hunk, r->pool, + ngx_http_gzip_error(ctx)); + *ctx->last_out = ce; + ctx->last_out = &ce->next; + break; } else if (ctx->flush == Z_FINISH) { - ctx->out_hunk->type |= NGX_HUNK_LAST; - ngx_add_hunk_to_chain(*ctx->last_out, ctx->out_hunk, - r->pool, ngx_http_gzip_error(ctx)); + /* rc == Z_STREAM_END */ + + zin = ctx->zstream.total_in; + zout = 10 + ctx->zstream.total_out + 8; + + ctx->flush = Z_NO_FLUSH; + + ngx_add_hunk_to_chain(ce, ctx->out_hunk, r->pool, + ngx_http_gzip_error(ctx)); + *ctx->last_out = ce; + ctx->last_out = &ce->next; + + if (ctx->zstream.avail_out >= 8) { + trailer = (struct gztrailer *) &ctx->zstream.avail_in; + ctx->out_hunk->type |= NGX_HUNK_LAST; + ctx->out_hunk->last += 8; + + } else { + /* STUB */ trailer = NULL; + } + +#if (HAVE_LITTLE_ENDIAN) + trailer->crc32 = ctx->crc32; + trailer->zlen = zin; +#else + /* STUB */ +#endif + + deflateEnd(&ctx->zstream); +#if 0 + ngx_free(); + set ctx = NULL; +#endif break; } else if (conf->no_buffer && ctx->in == NULL) { - ngx_add_hunk_to_chain(*ctx->last_out, ctx->out_hunk, - r->pool, ngx_http_gzip_error(ctx)); + ngx_add_hunk_to_chain(ce, ctx->out_hunk, r->pool, + ngx_http_gzip_error(ctx)); + *ctx->last_out = ce; + ctx->last_out = &ce->next; + break; } } } - if (next_body_filter(r, ctx->out) == NGX_ERROR) { + rc = next_body_filter(r, ctx->out); + if (rc == NGX_ERROR) { return ngx_http_gzip_error(ctx); } ngx_chain_update_chains(&ctx->free, &ctx->busy, &ctx->out); + ctx->last_out = &ctx->out; } + + /* STUB */ + return next_body_filter(r, NULL); } @@ -243,3 +377,36 @@ static int ngx_http_gzip_filter_init(ngx return NGX_OK; } + + +static void *ngx_http_gzip_create_conf(ngx_conf_t *cf) +{ + ngx_http_gzip_conf_t *conf; + + ngx_test_null(conf, + ngx_pcalloc(cf->pool, sizeof(ngx_http_gzip_conf_t)), + NGX_CONF_ERROR); + + conf->enable = NGX_CONF_UNSET; + conf->hunk_size = NGX_CONF_UNSET; + conf->hunks = NGX_CONF_UNSET; + conf->no_buffer = NGX_CONF_UNSET; + + return conf; +} + + +static char *ngx_http_gzip_merge_conf(ngx_conf_t *cf, + void *parent, void *child) +{ + ngx_http_gzip_conf_t *prev = parent; + ngx_http_gzip_conf_t *conf = child; + + ngx_conf_merge_value(conf->enable, prev->enable, 0); + ngx_conf_merge_size_value(conf->hunk_size, prev->hunk_size, + /* STUB: PAGE_SIZE */ 4096); + ngx_conf_merge_value(conf->hunks, prev->hunks, 4); + ngx_conf_merge_value(conf->no_buffer, prev->no_buffer, 0); + + return NGX_CONF_OK; +} diff --git a/src/os/unix/ngx_freebsd_config.h b/src/os/unix/ngx_freebsd_config.h --- a/src/os/unix/ngx_freebsd_config.h +++ b/src/os/unix/ngx_freebsd_config.h @@ -130,4 +130,8 @@ #endif +/* STUB */ +#define HAVE_LITTLE_ENDIAN 1 + + #endif /* _NGX_FREEBSD_CONFIG_H_INCLUDED_ */