# HG changeset patch # User Igor Sysoev # Date 1347393600 -14400 # Node ID 2e8a942c8872840b7994ee678727fca74d20b733 # Parent 0a9f545d4f4b2a82c7cbe44d76dc088994ba14ff nginx 1.3.6 *) Feature: the ngx_http_gunzip_filter_module. *) Feature: the "memcached_gzip_flag" directive. *) Feature: the "always" parameter of the "gzip_static" directive. *) Bugfix: in the "limit_req" directive; the bug had appeared in 1.1.14. Thanks to Charles Chen. *) Bugfix: nginx could not be built by gcc 4.7 with -O2 optimization if the --with-ipv6 option was used. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,19 @@ +Changes with nginx 1.3.6 12 Sep 2012 + + *) Feature: the ngx_http_gunzip_filter_module. + + *) Feature: the "memcached_gzip_flag" directive. + + *) Feature: the "always" parameter of the "gzip_static" directive. + + *) Bugfix: in the "limit_req" directive; the bug had appeared in 1.1.14. + Thanks to Charles Chen. + + *) Bugfix: nginx could not be built by gcc 4.7 with -O2 optimization if + the --with-ipv6 option was used. + + Changes with nginx 1.3.5 21 Aug 2012 *) Change: the ngx_http_mp4_module module no longer skips tracks in diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,19 @@ +Изменения в nginx 1.3.6 12.09.2012 + + *) Добавление: модуль ngx_http_gunzip_filter_module. + + *) Добавление: директива memcached_gzip_flag. + + *) Добавление: параметр always директивы gzip_static. + + *) Исправление: в директиве "limit_req"; ошибка появилась в 1.1.14. + Спасибо Charles Chen. + + *) Исправление: nginx не собирался gcc 4.7 с оптимизацией -O2 если + использовался параметр --with-ipv6. + + Изменения в nginx 1.3.5 21.08.2012 *) Изменение: модуль ngx_http_mp4_module больше не отфильтровывает diff --git a/auto/install b/auto/install --- a/auto/install +++ b/auto/install @@ -8,7 +8,7 @@ if [ $USE_PERL = YES ]; then cat << END >> $NGX_MAKEFILE install_perl_modules: - cd $NGX_OBJS/src/http/modules/perl && \${MAKE} install + cd $NGX_OBJS/src/http/modules/perl && \$(MAKE) install END NGX_INSTALL_PERL_MODULES=install_perl_modules diff --git a/auto/lib/libatomic/make b/auto/lib/libatomic/make --- a/auto/lib/libatomic/make +++ b/auto/lib/libatomic/make @@ -6,7 +6,7 @@ cat << END >> $NGX_MAKEFILE $NGX_LIBATOMIC/src/libatomic_ops.a: $NGX_LIBATOMIC/Makefile - cd $NGX_LIBATOMIC && \${MAKE} + cd $NGX_LIBATOMIC && \$(MAKE) $NGX_LIBATOMIC/Makefile: $NGX_MAKEFILE cd $NGX_LIBATOMIC && ./configure diff --git a/auto/lib/perl/make b/auto/lib/perl/make --- a/auto/lib/perl/make +++ b/auto/lib/perl/make @@ -12,7 +12,7 @@ cat << END $NGX_OBJS/src/http/modules/perl/Makefile cp -p src/http/modules/perl/nginx.* $NGX_OBJS/src/http/modules/perl/ - cd $NGX_OBJS/src/http/modules/perl && \${MAKE} + cd $NGX_OBJS/src/http/modules/perl && \$(MAKE) rm -rf $NGX_OBJS/install_perl diff --git a/auto/lib/zlib/makefile.bcc b/auto/lib/zlib/makefile.bcc --- a/auto/lib/zlib/makefile.bcc +++ b/auto/lib/zlib/makefile.bcc @@ -8,8 +8,10 @@ CFLAGS = -q -O2 -tWM -w-8004 -w-8012 $(C zlib.lib: cd $(ZLIB) - bcc32 -c $(CFLAGS) adler32.c crc32.c deflate.c trees.c zutil.c \ - compress.c + bcc32 -c $(CFLAGS) adler32.c crc32.c deflate.c \ + trees.c zutil.c compress.c \ + inflate.c inffast.c inftrees.c tlib zlib.lib +adler32.obj +crc32.obj +deflate.obj \ - +trees.obj +zutil.obj +compress.obj + +trees.obj +zutil.obj +compress.obj \ + +inflate.obj +inffast.obj +inftrees.obj diff --git a/auto/lib/zlib/makefile.msvc b/auto/lib/zlib/makefile.msvc --- a/auto/lib/zlib/makefile.msvc +++ b/auto/lib/zlib/makefile.msvc @@ -8,7 +8,10 @@ CFLAGS = -nologo -O2 -Ob1 -Oi -Gs $(LIBC zlib.lib: cd $(ZLIB) - cl -c $(CFLAGS) adler32.c crc32.c deflate.c trees.c zutil.c compress.c + cl -c $(CFLAGS) adler32.c crc32.c deflate.c \ + trees.c zutil.c compress.c \ + inflate.c inffast.c inftrees.c link -lib -out:zlib.lib adler32.obj crc32.obj deflate.obj \ - trees.obj zutil.obj compress.obj + trees.obj zutil.obj compress.obj \ + inflate.obj inffast.obj inftrees.obj diff --git a/auto/lib/zlib/makefile.owc b/auto/lib/zlib/makefile.owc --- a/auto/lib/zlib/makefile.owc +++ b/auto/lib/zlib/makefile.owc @@ -9,6 +9,6 @@ zlib.lib: cd $(ZLIB) wcl386 -c $(CFLAGS) adler32.c crc32.c deflate.c trees.c zutil.c & - compress.c + compress.c inflate.c inffast.c inftrees.c wlib -n zlib.lib adler32.obj crc32.obj deflate.obj trees.obj & - zutil.obj compress.obj + zutil.obj compress.obj inflate.obj inffast.obj inftrees.obj diff --git a/auto/modules b/auto/modules --- a/auto/modules +++ b/auto/modules @@ -109,6 +109,7 @@ fi # ngx_http_image_filter # ngx_http_sub_filter # ngx_http_addition_filter +# ngx_http_gunzip_filter # ngx_http_userid_filter # ngx_http_headers_filter # ngx_http_copy_filter @@ -166,6 +167,13 @@ if [ $HTTP_ADDITION = YES ]; then HTTP_SRCS="$HTTP_SRCS $HTTP_ADDITION_SRCS" fi +if [ $HTTP_GUNZIP = YES ]; then + have=NGX_HTTP_GZIP . auto/have + USE_ZLIB=YES + HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_GUNZIP_FILTER_MODULE" + HTTP_SRCS="$HTTP_SRCS $HTTP_GUNZIP_SRCS" +fi + if [ $HTTP_USERID = YES ]; then HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_USERID_FILTER_MODULE" HTTP_SRCS="$HTTP_SRCS $HTTP_USERID_SRCS" diff --git a/auto/options b/auto/options --- a/auto/options +++ b/auto/options @@ -94,6 +94,7 @@ HTTP_SECURE_LINK=NO HTTP_DEGRADATION=NO HTTP_FLV=NO HTTP_MP4=NO +HTTP_GUNZIP=NO HTTP_GZIP_STATIC=NO HTTP_UPSTREAM_IP_HASH=YES HTTP_UPSTREAM_LEAST_CONN=YES @@ -210,6 +211,7 @@ do --with-http_dav_module) HTTP_DAV=YES ;; --with-http_flv_module) HTTP_FLV=YES ;; --with-http_mp4_module) HTTP_MP4=YES ;; + --with-http_gunzip_module) HTTP_GUNZIP=YES ;; --with-http_gzip_static_module) HTTP_GZIP_STATIC=YES ;; --with-http_random_index_module) HTTP_RANDOM_INDEX=YES ;; --with-http_secure_link_module) HTTP_SECURE_LINK=YES ;; @@ -356,6 +358,7 @@ cat << END --with-http_dav_module enable ngx_http_dav_module --with-http_flv_module enable ngx_http_flv_module --with-http_mp4_module enable ngx_http_mp4_module + --with-http_gunzip_module enable ngx_http_gunzip_module --with-http_gzip_static_module enable ngx_http_gzip_static_module --with-http_random_index_module enable ngx_http_random_index_module --with-http_secure_link_module enable ngx_http_secure_link_module diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -331,6 +331,10 @@ HTTP_GZIP_FILTER_MODULE=ngx_http_gzip_fi HTTP_GZIP_SRCS=src/http/modules/ngx_http_gzip_filter_module.c +HTTP_GUNZIP_FILTER_MODULE=ngx_http_gunzip_filter_module +HTTP_GUNZIP_SRCS=src/http/modules/ngx_http_gunzip_filter_module.c + + HTTP_SSI_FILTER_MODULE=ngx_http_ssi_filter_module HTTP_SSI_DEPS=src/http/modules/ngx_http_ssi_filter_module.h HTTP_SSI_SRCS=src/http/modules/ngx_http_ssi_filter_module.c diff --git a/html/50x.html b/html/50x.html --- a/html/50x.html +++ b/html/50x.html @@ -1,18 +1,21 @@ + -The page is temporarily unavailable +Error - - - - - -
-The page you are looking for is temporarily unavailable.
-Please try again later. -
+ +

An error occurred.

+

Sorry, the page you are looking for is currently unavailable.
+Please try again later.

+

If you are the system administrator of this resource then you should check +the error log for details.

+

Faithfully yours, nginx.

diff --git a/html/index.html b/html/index.html --- a/html/index.html +++ b/html/index.html @@ -1,8 +1,25 @@ + Welcome to nginx! + - -

Welcome to nginx!

+ +

Welcome to nginx!

+

If you see this page, the nginx web server is successfully installed and +working. Further configuration is required.

+ +

For online documentation and support please refer to +nginx.org.
+Commercial support is available at +nginx.com.

+ +

Thank you for using nginx.

diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1003005 -#define NGINX_VERSION "1.3.5" +#define nginx_version 1003006 +#define NGINX_VERSION "1.3.6" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -12,7 +12,6 @@ static ngx_int_t ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last); static ngx_int_t ngx_conf_read_token(ngx_conf_t *cf); -static char *ngx_conf_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static ngx_int_t ngx_conf_test_full_name(ngx_str_t *name); static void ngx_conf_flush_files(ngx_cycle_t *cycle); @@ -731,7 +730,7 @@ ngx_conf_read_token(ngx_conf_t *cf) } -static char * +char * ngx_conf_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *rv; diff --git a/src/core/ngx_conf_file.h b/src/core/ngx_conf_file.h --- a/src/core/ngx_conf_file.h +++ b/src/core/ngx_conf_file.h @@ -317,6 +317,7 @@ char *ngx_conf_check_num_bounds(ngx_conf char *ngx_conf_param(ngx_conf_t *cf); char *ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename); +char *ngx_conf_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); ngx_int_t ngx_conf_full_name(ngx_cycle_t *cycle, ngx_str_t *name, diff --git a/src/core/ngx_slab.c b/src/core/ngx_slab.c --- a/src/core/ngx_slab.c +++ b/src/core/ngx_slab.c @@ -162,8 +162,8 @@ ngx_slab_alloc_locked(ngx_slab_pool_t *p ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0, "slab alloc: %uz", size); - page = ngx_slab_alloc_pages(pool, (size + ngx_pagesize - 1) - >> ngx_pagesize_shift); + page = ngx_slab_alloc_pages(pool, (size >> ngx_pagesize_shift) + + ((size % ngx_pagesize) ? 1 : 0)); if (page) { p = (page - pool->pages) << ngx_pagesize_shift; p += (uintptr_t) pool->start; diff --git a/src/http/modules/ngx_http_geo_module.c b/src/http/modules/ngx_http_geo_module.c --- a/src/http/modules/ngx_http_geo_module.c +++ b/src/http/modules/ngx_http_geo_module.c @@ -233,12 +233,21 @@ ngx_http_geo_addr(ngx_http_request_t *r, #if (NGX_HAVE_INET6) if (addr.sockaddr->sa_family == AF_INET6) { + u_char *p; + in_addr_t inaddr; struct in6_addr *inaddr6; inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr; if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { - return ntohl(*(in_addr_t *) &inaddr6->s6_addr[12]); + p = inaddr6->s6_addr; + + inaddr = p[12] << 24; + inaddr += p[13] << 16; + inaddr += p[14] << 8; + inaddr += p[15]; + + return inaddr; } } diff --git a/src/http/modules/ngx_http_geoip_module.c b/src/http/modules/ngx_http_geoip_module.c --- a/src/http/modules/ngx_http_geoip_module.c +++ b/src/http/modules/ngx_http_geoip_module.c @@ -226,12 +226,21 @@ ngx_http_geoip_addr(ngx_http_request_t * #if (NGX_HAVE_INET6) if (addr.sockaddr->sa_family == AF_INET6) { + u_char *p; + in_addr_t inaddr; struct in6_addr *inaddr6; inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr; if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { - return ntohl(*(in_addr_t *) &inaddr6->s6_addr[12]); + p = inaddr6->s6_addr; + + inaddr = p[12] << 24; + inaddr += p[13] << 16; + inaddr += p[14] << 8; + inaddr += p[15]; + + return inaddr; } } diff --git a/src/http/modules/ngx_http_gunzip_filter_module.c b/src/http/modules/ngx_http_gunzip_filter_module.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_gunzip_filter_module.c @@ -0,0 +1,676 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Maxim Dounin + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + +#include + + +typedef struct { + ngx_flag_t enable; + ngx_bufs_t bufs; +} ngx_http_gunzip_conf_t; + + +typedef struct { + ngx_chain_t *in; + ngx_chain_t *free; + ngx_chain_t *busy; + ngx_chain_t *out; + ngx_chain_t **last_out; + + ngx_buf_t *in_buf; + ngx_buf_t *out_buf; + ngx_int_t bufs; + + unsigned started:1; + unsigned flush:4; + unsigned redo:1; + unsigned done:1; + unsigned nomem:1; + + z_stream zstream; + ngx_http_request_t *request; +} ngx_http_gunzip_ctx_t; + + +static ngx_int_t ngx_http_gunzip_filter_inflate_start(ngx_http_request_t *r, + ngx_http_gunzip_ctx_t *ctx); +static ngx_int_t ngx_http_gunzip_filter_add_data(ngx_http_request_t *r, + ngx_http_gunzip_ctx_t *ctx); +static ngx_int_t ngx_http_gunzip_filter_get_buf(ngx_http_request_t *r, + ngx_http_gunzip_ctx_t *ctx); +static ngx_int_t ngx_http_gunzip_filter_inflate(ngx_http_request_t *r, + ngx_http_gunzip_ctx_t *ctx); +static ngx_int_t ngx_http_gunzip_filter_inflate_end(ngx_http_request_t *r, + ngx_http_gunzip_ctx_t *ctx); + +static void *ngx_http_gunzip_filter_alloc(void *opaque, u_int items, + u_int size); +static void ngx_http_gunzip_filter_free(void *opaque, void *address); + +static ngx_int_t ngx_http_gunzip_filter_init(ngx_conf_t *cf); +static void *ngx_http_gunzip_create_conf(ngx_conf_t *cf); +static char *ngx_http_gunzip_merge_conf(ngx_conf_t *cf, + void *parent, void *child); + + +static ngx_command_t ngx_http_gunzip_filter_commands[] = { + + { ngx_string("gunzip"), + 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_gunzip_conf_t, enable), + NULL }, + + { ngx_string("gunzip_buffers"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, + ngx_conf_set_bufs_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_gunzip_conf_t, bufs), + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_gunzip_filter_module_ctx = { + NULL, /* preconfiguration */ + ngx_http_gunzip_filter_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_gunzip_create_conf, /* create location configuration */ + ngx_http_gunzip_merge_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_gunzip_filter_module = { + NGX_MODULE_V1, + &ngx_http_gunzip_filter_module_ctx, /* module context */ + ngx_http_gunzip_filter_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_http_output_header_filter_pt ngx_http_next_header_filter; +static ngx_http_output_body_filter_pt ngx_http_next_body_filter; + + +static ngx_int_t +ngx_http_gunzip_header_filter(ngx_http_request_t *r) +{ + ngx_http_gunzip_ctx_t *ctx; + ngx_http_gunzip_conf_t *conf; + + conf = ngx_http_get_module_loc_conf(r, ngx_http_gunzip_filter_module); + + /* TODO support multiple content-codings */ + /* TODO always gunzip - due to configuration or module request */ + /* TODO ignore content encoding? */ + + if (!conf->enable + || r->headers_out.content_encoding == NULL + || r->headers_out.content_encoding->value.len != 4 + || ngx_strncasecmp(r->headers_out.content_encoding->value.data, + (u_char *) "gzip", 4) != 0) + { + return ngx_http_next_header_filter(r); + } + + r->gzip_vary = 1; + + if (!r->gzip_tested) { + if (ngx_http_gzip_ok(r) == NGX_OK) { + return ngx_http_next_header_filter(r); + } + + } else if (!r->gzip_ok) { + return ngx_http_next_header_filter(r); + } + + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_gunzip_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_http_set_ctx(r, ctx, ngx_http_gunzip_filter_module); + + ctx->request = r; + + r->filter_need_in_memory = 1; + + r->headers_out.content_encoding->hash = 0; + r->headers_out.content_encoding = NULL; + + ngx_http_clear_content_length(r); + ngx_http_clear_accept_ranges(r); + + return ngx_http_next_header_filter(r); +} + + +static ngx_int_t +ngx_http_gunzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in) +{ + int rc; + ngx_chain_t *cl; + ngx_http_gunzip_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_gunzip_filter_module); + + if (ctx == NULL || ctx->done) { + return ngx_http_next_body_filter(r, in); + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http gunzip filter"); + + if (!ctx->started) { + if (ngx_http_gunzip_filter_inflate_start(r, ctx) != NGX_OK) { + goto failed; + } + } + + if (in) { + if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) { + goto failed; + } + } + + if (ctx->nomem) { + + /* flush busy buffers */ + + if (ngx_http_next_body_filter(r, NULL) == NGX_ERROR) { + goto failed; + } + + cl = NULL; + + ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &cl, + (ngx_buf_tag_t) &ngx_http_gunzip_filter_module); + ctx->nomem = 0; + } + + for ( ;; ) { + + /* cycle while we can write to a client */ + + for ( ;; ) { + + /* cycle while there is data to feed zlib and ... */ + + rc = ngx_http_gunzip_filter_add_data(r, ctx); + + if (rc == NGX_DECLINED) { + break; + } + + if (rc == NGX_AGAIN) { + continue; + } + + + /* ... there are buffers to write zlib output */ + + rc = ngx_http_gunzip_filter_get_buf(r, ctx); + + if (rc == NGX_DECLINED) { + break; + } + + if (rc == NGX_ERROR) { + goto failed; + } + + rc = ngx_http_gunzip_filter_inflate(r, ctx); + + if (rc == NGX_OK) { + break; + } + + if (rc == NGX_ERROR) { + goto failed; + } + + /* rc == NGX_AGAIN */ + } + + if (ctx->out == NULL) { + return ctx->busy ? NGX_AGAIN : NGX_OK; + } + + rc = ngx_http_next_body_filter(r, ctx->out); + + if (rc == NGX_ERROR) { + goto failed; + } + + ngx_chain_update_chains(r->pool, &ctx->free, &ctx->busy, &ctx->out, + (ngx_buf_tag_t) &ngx_http_gunzip_filter_module); + ctx->last_out = &ctx->out; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "gunzip out: %p", ctx->out); + + ctx->nomem = 0; + + if (ctx->done) { + return rc; + } + } + + /* unreachable */ + +failed: + + ctx->done = 1; + + return NGX_ERROR; +} + + +static ngx_int_t +ngx_http_gunzip_filter_inflate_start(ngx_http_request_t *r, + ngx_http_gunzip_ctx_t *ctx) +{ + int rc; + + ctx->zstream.next_in = Z_NULL; + ctx->zstream.avail_in = 0; + + ctx->zstream.zalloc = ngx_http_gunzip_filter_alloc; + ctx->zstream.zfree = ngx_http_gunzip_filter_free; + ctx->zstream.opaque = ctx; + + /* windowBits +16 to decode gzip, zlib 1.2.0.4+ */ + rc = inflateInit2(&ctx->zstream, MAX_WBITS + 16); + + if (rc != Z_OK) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "inflateInit2() failed: %d", rc); + return NGX_ERROR; + } + + ctx->started = 1; + + ctx->last_out = &ctx->out; + ctx->flush = Z_NO_FLUSH; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_gunzip_filter_add_data(ngx_http_request_t *r, + ngx_http_gunzip_ctx_t *ctx) +{ + if (ctx->zstream.avail_in || ctx->flush != Z_NO_FLUSH || ctx->redo) { + return NGX_OK; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "gunzip in: %p", ctx->in); + + if (ctx->in == NULL) { + return NGX_DECLINED; + } + + ctx->in_buf = ctx->in->buf; + ctx->in = ctx->in->next; + + ctx->zstream.next_in = ctx->in_buf->pos; + ctx->zstream.avail_in = ctx->in_buf->last - ctx->in_buf->pos; + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "gunzip in_buf:%p ni:%p ai:%ud", + ctx->in_buf, + ctx->zstream.next_in, ctx->zstream.avail_in); + + if (ctx->in_buf->last_buf || ctx->in_buf->last_in_chain) { + ctx->flush = Z_FINISH; + + } else if (ctx->in_buf->flush) { + ctx->flush = Z_SYNC_FLUSH; + + } else if (ctx->zstream.avail_in == 0) { + /* ctx->flush == Z_NO_FLUSH */ + return NGX_AGAIN; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_gunzip_filter_get_buf(ngx_http_request_t *r, + ngx_http_gunzip_ctx_t *ctx) +{ + ngx_http_gunzip_conf_t *conf; + + if (ctx->zstream.avail_out) { + return NGX_OK; + } + + conf = ngx_http_get_module_loc_conf(r, ngx_http_gunzip_filter_module); + + if (ctx->free) { + ctx->out_buf = ctx->free->buf; + ctx->free = ctx->free->next; + + ctx->out_buf->flush = 0; + + } else if (ctx->bufs < conf->bufs.num) { + + ctx->out_buf = ngx_create_temp_buf(r->pool, conf->bufs.size); + if (ctx->out_buf == NULL) { + return NGX_ERROR; + } + + ctx->out_buf->tag = (ngx_buf_tag_t) &ngx_http_gunzip_filter_module; + ctx->out_buf->recycled = 1; + ctx->bufs++; + + } else { + ctx->nomem = 1; + return NGX_DECLINED; + } + + ctx->zstream.next_out = ctx->out_buf->pos; + ctx->zstream.avail_out = conf->bufs.size; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_gunzip_filter_inflate(ngx_http_request_t *r, + ngx_http_gunzip_ctx_t *ctx) +{ + int rc; + ngx_buf_t *b; + ngx_chain_t *cl; + + ngx_log_debug6(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "inflate in: ni:%p no:%p ai:%ud ao:%ud fl:%d redo:%d", + ctx->zstream.next_in, ctx->zstream.next_out, + ctx->zstream.avail_in, ctx->zstream.avail_out, + ctx->flush, ctx->redo); + + rc = inflate(&ctx->zstream, ctx->flush); + + if (rc != Z_OK && rc != Z_STREAM_END && rc != Z_BUF_ERROR) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "inflate() failed: %d, %d", ctx->flush, rc); + return NGX_ERROR; + } + + ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "inflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d", + ctx->zstream.next_in, ctx->zstream.next_out, + ctx->zstream.avail_in, ctx->zstream.avail_out, + rc); + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "gunzip in_buf:%p pos:%p", + ctx->in_buf, ctx->in_buf->pos); + + if (ctx->zstream.next_in) { + ctx->in_buf->pos = ctx->zstream.next_in; + + if (ctx->zstream.avail_in == 0) { + ctx->zstream.next_in = NULL; + } + } + + ctx->out_buf->last = ctx->zstream.next_out; + + if (ctx->zstream.avail_out == 0) { + + /* zlib wants to output some more data */ + + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { + return NGX_ERROR; + } + + cl->buf = ctx->out_buf; + cl->next = NULL; + *ctx->last_out = cl; + ctx->last_out = &cl->next; + + ctx->redo = 1; + + return NGX_AGAIN; + } + + ctx->redo = 0; + + if (ctx->flush == Z_SYNC_FLUSH) { + + ctx->flush = Z_NO_FLUSH; + + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { + return NGX_ERROR; + } + + b = ctx->out_buf; + + if (ngx_buf_size(b) == 0) { + + b = ngx_calloc_buf(ctx->request->pool); + if (b == NULL) { + return NGX_ERROR; + } + + } else { + ctx->zstream.avail_out = 0; + } + + b->flush = 1; + + cl->buf = b; + cl->next = NULL; + *ctx->last_out = cl; + ctx->last_out = &cl->next; + + return NGX_OK; + } + + if (rc == Z_STREAM_END && ctx->flush == Z_FINISH + && ctx->zstream.avail_in == 0) + { + + if (ngx_http_gunzip_filter_inflate_end(r, ctx) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_OK; + } + + if (rc == Z_STREAM_END && ctx->zstream.avail_in > 0) { + + rc = inflateReset(&ctx->zstream); + + if (rc != Z_OK) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "inflateReset() failed: %d", rc); + return NGX_ERROR; + } + + ctx->redo = 1; + + return NGX_AGAIN; + } + + if (ctx->in == NULL) { + + b = ctx->out_buf; + + if (ngx_buf_size(b) == 0) { + return NGX_OK; + } + + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { + return NGX_ERROR; + } + + ctx->zstream.avail_out = 0; + + cl->buf = b; + cl->next = NULL; + *ctx->last_out = cl; + ctx->last_out = &cl->next; + + return NGX_OK; + } + + return NGX_AGAIN; +} + + +static ngx_int_t +ngx_http_gunzip_filter_inflate_end(ngx_http_request_t *r, + ngx_http_gunzip_ctx_t *ctx) +{ + int rc; + ngx_buf_t *b; + ngx_chain_t *cl; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "gunzip inflate end"); + + rc = inflateEnd(&ctx->zstream); + + if (rc != Z_OK) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "inflateEnd() failed: %d", rc); + return NGX_ERROR; + } + + b = ctx->out_buf; + + if (ngx_buf_size(b) == 0) { + + b = ngx_calloc_buf(ctx->request->pool); + if (b == NULL) { + return NGX_ERROR; + } + } + + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { + return NGX_ERROR; + } + + cl->buf = b; + cl->next = NULL; + *ctx->last_out = cl; + ctx->last_out = &cl->next; + + b->last_buf = (r == r->main) ? 1 : 0; + b->last_in_chain = 1; + b->sync = 1; + + ctx->done = 1; + + return NGX_OK; +} + + +static void * +ngx_http_gunzip_filter_alloc(void *opaque, u_int items, u_int size) +{ + ngx_http_gunzip_ctx_t *ctx = opaque; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ctx->request->connection->log, 0, + "gunzip alloc: n:%ud s:%ud", + items, size); + + return ngx_palloc(ctx->request->pool, items * size); +} + + +static void +ngx_http_gunzip_filter_free(void *opaque, void *address) +{ +#if 0 + ngx_http_gunzip_ctx_t *ctx = opaque; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->request->connection->log, 0, + "gunzip free: %p", address); +#endif +} + + +static void * +ngx_http_gunzip_create_conf(ngx_conf_t *cf) +{ + ngx_http_gunzip_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_gunzip_conf_t)); + if (conf == NULL) { + return NULL; + } + + /* + * set by ngx_pcalloc(): + * + * conf->bufs.num = 0; + */ + + conf->enable = NGX_CONF_UNSET; + + return conf; +} + + +static char * +ngx_http_gunzip_merge_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_gunzip_conf_t *prev = parent; + ngx_http_gunzip_conf_t *conf = child; + + ngx_conf_merge_value(conf->enable, prev->enable, 0); + + ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, + (128 * 1024) / ngx_pagesize, ngx_pagesize); + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_gunzip_filter_init(ngx_conf_t *cf) +{ + ngx_http_next_header_filter = ngx_http_top_header_filter; + ngx_http_top_header_filter = ngx_http_gunzip_header_filter; + + ngx_http_next_body_filter = ngx_http_top_body_filter; + ngx_http_top_body_filter = ngx_http_gunzip_body_filter; + + return NGX_OK; +} diff --git a/src/http/modules/ngx_http_gzip_static_module.c b/src/http/modules/ngx_http_gzip_static_module.c --- a/src/http/modules/ngx_http_gzip_static_module.c +++ b/src/http/modules/ngx_http_gzip_static_module.c @@ -10,8 +10,13 @@ #include +#define NGX_HTTP_GZIP_STATIC_OFF 0 +#define NGX_HTTP_GZIP_STATIC_ON 1 +#define NGX_HTTP_GZIP_STATIC_ALWAYS 2 + + typedef struct { - ngx_flag_t enable; + ngx_uint_t enable; } ngx_http_gzip_static_conf_t; @@ -22,14 +27,22 @@ static char *ngx_http_gzip_static_merge_ static ngx_int_t ngx_http_gzip_static_init(ngx_conf_t *cf); +static ngx_conf_enum_t ngx_http_gzip_static[] = { + { ngx_string("off"), NGX_HTTP_GZIP_STATIC_OFF }, + { ngx_string("on"), NGX_HTTP_GZIP_STATIC_ON }, + { ngx_string("always"), NGX_HTTP_GZIP_STATIC_ALWAYS }, + { ngx_null_string, 0 } +}; + + static ngx_command_t ngx_http_gzip_static_commands[] = { { ngx_string("gzip_static"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, + ngx_conf_set_enum_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_gzip_static_conf_t, enable), - NULL }, + &ngx_http_gzip_static }, ngx_null_command }; @@ -92,11 +105,17 @@ ngx_http_gzip_static_handler(ngx_http_re gzcf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_static_module); - if (!gzcf->enable) { + if (gzcf->enable == NGX_HTTP_GZIP_STATIC_OFF) { return NGX_DECLINED; } - rc = ngx_http_gzip_ok(r); + if (gzcf->enable == NGX_HTTP_GZIP_STATIC_ON) { + rc = ngx_http_gzip_ok(r); + + } else { + /* always */ + rc = NGX_OK; + } clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); @@ -169,10 +188,12 @@ ngx_http_gzip_static_handler(ngx_http_re return NGX_DECLINED; } - r->gzip_vary = 1; + if (gzcf->enable == NGX_HTTP_GZIP_STATIC_ON) { + r->gzip_vary = 1; - if (rc != NGX_OK) { - return NGX_DECLINED; + if (rc != NGX_OK) { + return NGX_DECLINED; + } } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", of.fd); @@ -274,7 +295,7 @@ ngx_http_gzip_static_create_conf(ngx_con return NULL; } - conf->enable = NGX_CONF_UNSET; + conf->enable = NGX_CONF_UNSET_UINT; return conf; } @@ -286,7 +307,8 @@ ngx_http_gzip_static_merge_conf(ngx_conf ngx_http_gzip_static_conf_t *prev = parent; ngx_http_gzip_static_conf_t *conf = child; - ngx_conf_merge_value(conf->enable, prev->enable, 0); + ngx_conf_merge_uint_value(conf->enable, prev->enable, + NGX_HTTP_GZIP_STATIC_OFF); return NGX_CONF_OK; } diff --git a/src/http/modules/ngx_http_limit_req_module.c b/src/http/modules/ngx_http_limit_req_module.c --- a/src/http/modules/ngx_http_limit_req_module.c +++ b/src/http/modules/ngx_http_limit_req_module.c @@ -444,17 +444,17 @@ ngx_http_limit_req_lookup(ngx_http_limit node->key = hash; - ngx_rbtree_insert(&ctx->sh->rbtree, node); - lr = (ngx_http_limit_req_node_t *) &node->color; - ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); - lr->len = (u_char) len; lr->excess = 0; ngx_memcpy(lr->data, data, len); + ngx_rbtree_insert(&ctx->sh->rbtree, node); + + ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); + if (account) { lr->last = now; lr->count = 0; diff --git a/src/http/modules/ngx_http_map_module.c b/src/http/modules/ngx_http_map_module.c --- a/src/http/modules/ngx_http_map_module.c +++ b/src/http/modules/ngx_http_map_module.c @@ -369,7 +369,7 @@ static char * ngx_http_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) { ngx_int_t rc, index; - ngx_str_t *value, file, name; + ngx_str_t *value, name; ngx_uint_t i, key; ngx_http_map_conf_ctx_t *ctx; ngx_http_variable_value_t *var, **vp; @@ -391,15 +391,7 @@ ngx_http_map(ngx_conf_t *cf, ngx_command } if (ngx_strcmp(value[0].data, "include") == 0) { - file = value[1]; - - if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK) { - return NGX_CONF_ERROR; - } - - ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data); - - return ngx_conf_parse(cf, &file); + return ngx_conf_include(cf, dummy, conf); } if (value[1].data[0] == '$') { diff --git a/src/http/modules/ngx_http_memcached_module.c b/src/http/modules/ngx_http_memcached_module.c --- a/src/http/modules/ngx_http_memcached_module.c +++ b/src/http/modules/ngx_http_memcached_module.c @@ -13,6 +13,7 @@ typedef struct { ngx_http_upstream_conf_t upstream; ngx_int_t index; + ngx_uint_t gzip_flag; } ngx_http_memcached_loc_conf_t; @@ -101,6 +102,13 @@ static ngx_command_t ngx_http_memcached offsetof(ngx_http_memcached_loc_conf_t, upstream.next_upstream), &ngx_http_memcached_next_upstream_masks }, + { ngx_string("memcached_gzip_flag"), + 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_memcached_loc_conf_t, gzip_flag), + NULL }, + ngx_null_command }; @@ -281,10 +289,13 @@ ngx_http_memcached_reinit_request(ngx_ht static ngx_int_t ngx_http_memcached_process_header(ngx_http_request_t *r) { - u_char *p, *len; - ngx_str_t line; - ngx_http_upstream_t *u; - ngx_http_memcached_ctx_t *ctx; + u_char *p, *start; + ngx_str_t line; + ngx_uint_t flags; + ngx_table_elt_t *h; + ngx_http_upstream_t *u; + ngx_http_memcached_ctx_t *ctx; + ngx_http_memcached_loc_conf_t *mlcf; u = r->upstream; @@ -309,6 +320,7 @@ found: p = u->buffer.pos; ctx = ngx_http_get_module_ctx(r, ngx_http_memcached_module); + mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module); if (ngx_strncmp(p, "VALUE ", sizeof("VALUE ") - 1) == 0) { @@ -329,23 +341,56 @@ found: goto no_valid; } - /* skip flags */ + /* flags */ + + start = p; while (*p) { if (*p++ == ' ') { - goto length; + if (mlcf->gzip_flag) { + goto flags; + } else { + goto length; + } } } goto no_valid; + flags: + + flags = ngx_atoi(start, p - start - 1); + + if (flags == (ngx_uint_t) NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "memcached sent invalid flags in response \"%V\" " + "for key \"%V\"", + &line, &ctx->key); + return NGX_HTTP_UPSTREAM_INVALID_HEADER; + } + + if (flags & mlcf->gzip_flag) { + h = ngx_list_push(&r->headers_out.headers); + if (h == NULL) { + return NGX_ERROR; + } + + h->hash = 1; + h->key.len = sizeof("Content-Encoding") - 1; + h->key.data = (u_char *) "Content-Encoding"; + h->value.len = sizeof("gzip") - 1; + h->value.data = (u_char *) "gzip"; + + r->headers_out.content_encoding = h; + } + length: - len = p; + start = p; while (*p && *p++ != CR) { /* void */ } - u->headers_in.content_length_n = ngx_atoof(len, p - len - 1); + u->headers_in.content_length_n = ngx_atoof(start, p - start - 1); if (u->headers_in.content_length_n == -1) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "memcached sent invalid length in response \"%V\" " @@ -550,6 +595,7 @@ ngx_http_memcached_create_loc_conf(ngx_c conf->upstream.pass_request_body = 0; conf->index = NGX_CONF_UNSET; + conf->gzip_flag = NGX_CONF_UNSET_UINT; return conf; } @@ -593,6 +639,8 @@ ngx_http_memcached_merge_loc_conf(ngx_co conf->index = prev->index; } + ngx_conf_merge_uint_value(conf->gzip_flag, prev->gzip_flag, 0); + return NGX_CONF_OK; } diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm --- a/src/http/modules/perl/nginx.pm +++ b/src/http/modules/perl/nginx.pm @@ -50,7 +50,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '1.3.5'; +our $VERSION = '1.3.6'; require XSLoader; XSLoader::load('nginx', $VERSION); diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -2776,7 +2776,15 @@ ngx_http_get_forwarded_addr(ngx_http_req if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { family = AF_INET; - inaddr = *(in_addr_t *) &inaddr6->s6_addr[12]; + + p = inaddr6->s6_addr; + + inaddr = p[12] << 24; + inaddr += p[13] << 16; + inaddr += p[14] << 8; + inaddr += p[15]; + + inaddr = htonl(inaddr); } } #endif @@ -3236,7 +3244,7 @@ ngx_http_core_type(ngx_conf_t *cf, ngx_c { ngx_http_core_loc_conf_t *clcf = conf; - ngx_str_t *value, *content_type, *old, file; + ngx_str_t *value, *content_type, *old; ngx_uint_t i, n, hash; ngx_hash_key_t *type; @@ -3249,15 +3257,8 @@ ngx_http_core_type(ngx_conf_t *cf, ngx_c " in \"include\" directive"); return NGX_CONF_ERROR; } - file = value[1]; - - if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK) { - return NGX_CONF_ERROR; - } - - ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data); - - return ngx_conf_parse(cf, &file); + + return ngx_conf_include(cf, dummy, conf); } content_type = ngx_palloc(cf->pool, sizeof(ngx_str_t)); diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c --- a/src/http/ngx_http_write_filter_module.c +++ b/src/http/ngx_http_write_filter_module.c @@ -185,18 +185,14 @@ ngx_http_write_filter(ngx_http_request_t } if (size == 0 && !(c->buffered & NGX_LOWLEVEL_BUFFERED)) { - if (last) { - r->out = NULL; - c->buffered &= ~NGX_HTTP_WRITE_BUFFERED; + if (last || flush) { + for (cl = r->out; cl; /* void */) { + ln = cl; + cl = cl->next; + ngx_free_chain(r->pool, ln); + } - return NGX_OK; - } - - if (flush) { - do { - r->out = r->out->next; - } while (r->out); - + r->out = NULL; c->buffered &= ~NGX_HTTP_WRITE_BUFFERED; return NGX_OK;