# HG changeset patch # User Igor Sysoev # Date 1321214400 -14400 # Node ID f200748c0ac857c5d0ad82be005c55513724b2d8 # Parent bec017127243c9287255589ed25ccf913e0d9a3e nginx 1.1.8 *) Change: the ngx_http_limit_zone_module was renamed to the ngx_http_limit_conn_module. *) Change: the "limit_zone" directive was superseded by the "limit_conn_zone" directive with a new syntax. *) Feature: support for multiple "limit_conn" limits on the same level. *) Feature: the "image_filter_sharpen" directive. *) Bugfix: a segmentation fault might occur in a worker process if resolver got a big DNS response. Thanks to Ben Hawkes. *) Bugfix: in cache key calculation if internal MD5 implementation was used; the bug had appeared in 1.0.4. *) Bugfix: the "If-Modified-Since", "If-Range", etc. client request header lines might be passed to backend while caching; or not passed without caching if caching was enabled in another part of the configuration. *) Bugfix: the module ngx_http_mp4_module sent incorrect "Content-Length" response header line if the "start" argument was used. Thanks to Piotr Sikora. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,15 +1,45 @@ +Changes with nginx 1.1.8 14 Nov 2011 + + *) Change: the ngx_http_limit_zone_module was renamed to the + ngx_http_limit_conn_module. + + *) Change: the "limit_zone" directive was superseded by the + "limit_conn_zone" directive with a new syntax. + + *) Feature: support for multiple "limit_conn" limits on the same level. + + *) Feature: the "image_filter_sharpen" directive. + + *) Bugfix: a segmentation fault might occur in a worker process if + resolver got a big DNS response. + Thanks to Ben Hawkes. + + *) Bugfix: in cache key calculation if internal MD5 implementation was + used; the bug had appeared in 1.0.4. + + *) Bugfix: the "If-Modified-Since", "If-Range", etc. client request + header lines might be passed to backend while caching; or not passed + without caching if caching was enabled in another part of the + configuration. + + *) Bugfix: the module ngx_http_mp4_module sent incorrect + "Content-Length" response header line if the "start" argument was + used. + Thanks to Piotr Sikora. + + Changes with nginx 1.1.7 31 Oct 2011 - *) Feature: support of several resolvers in the "resolver" directive. + *) Feature: support of several DNS servers in the "resolver" directive. Thanks to Kirill A. Korinskiy. - *) Bugfix: a segmentation fault occurred on start or while + *) Bugfix: a segmentation fault occurred on start or during reconfiguration if the "ssl" directive was used at http level and there was no "ssl_certificate" defined. - *) Bugfix: reduced memory consumption while proxying of big files if - they were buffered to disk. + *) Bugfix: reduced memory consumption while proxying big files if they + were buffered to disk. *) Bugfix: a segmentation fault might occur in a worker process if "proxy_http_version 1.1" directive was used. diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,34 @@ +Изменения в nginx 1.1.8 14.11.2011 + + *) Изменение: модуль ngx_http_limit_zone_module переименован в + ngx_http_limit_conn_module. + + *) Изменение: директива limit_zone заменена директивой limit_conn_zone с + новым синтаксисом. + + *) Добавление: поддержка ограничения по нескольким limit_conn на одном + уровне. + + *) Добавление: директива image_filter_sharpen. + + *) Исправление: в рабочем процессе мог произойти segmentation fault, + если resolver получил большой DNS-ответ. + Спасибо Ben Hawkes. + + *) Исправление: в вычислении ключа для кэширования, если использовалась + внутренняя реализация MD5; ошибка появилась в 1.0.4. + + *) Исправление: строки "If-Modified-Since", "If-Range" и им подобные в + заголовке запроса клиента могли передаваться бэкенду при кэшировании; + или не передаваться при выключенном кэшировании, если кэширование + было включено в другой части конфигурации. + + *) Исправление: модуль ngx_http_mp4_module выдавал неверную строку + "Content-Length" в заголовке ответа, использовался аргумент start. + Спасибо Piotr Sikora. + + Изменения в nginx 1.1.7 31.10.2011 *) Добавление: поддержка нескольких DNS серверов в директиве "resolver". diff --git a/auto/modules b/auto/modules --- a/auto/modules +++ b/auto/modules @@ -210,9 +210,9 @@ if [ $HTTP_ACCESS = YES ]; then HTTP_SRCS="$HTTP_SRCS $HTTP_ACCESS_SRCS" fi -if [ $HTTP_LIMIT_ZONE = YES ]; then - HTTP_MODULES="$HTTP_MODULES $HTTP_LIMIT_ZONE_MODULE" - HTTP_SRCS="$HTTP_SRCS $HTTP_LIMIT_ZONE_SRCS" +if [ $HTTP_LIMIT_CONN = YES ]; then + HTTP_MODULES="$HTTP_MODULES $HTTP_LIMIT_CONN_MODULE" + HTTP_SRCS="$HTTP_SRCS $HTTP_LIMIT_CONN_SRCS" fi if [ $HTTP_LIMIT_REQ = YES ]; then diff --git a/auto/options b/auto/options --- a/auto/options +++ b/auto/options @@ -85,7 +85,7 @@ HTTP_UWSGI=YES HTTP_SCGI=YES HTTP_PERL=NO HTTP_MEMCACHED=YES -HTTP_LIMIT_ZONE=YES +HTTP_LIMIT_CONN=YES HTTP_LIMIT_REQ=YES HTTP_EMPTY_GIF=YES HTTP_BROWSER=YES @@ -143,6 +143,8 @@ NGX_LIBATOMIC=NO NGX_CPU_CACHE_LINE= +NGX_POST_CONF_MSG= + opt= for option @@ -227,7 +229,13 @@ do --without-http_uwsgi_module) HTTP_UWSGI=NO ;; --without-http_scgi_module) HTTP_SCGI=NO ;; --without-http_memcached_module) HTTP_MEMCACHED=NO ;; - --without-http_limit_zone_module) HTTP_LIMIT_ZONE=NO ;; + --without-http_limit_zone_module) + HTTP_LIMIT_CONN=NO + NGX_POST_CONF_MSG="$NGX_POST_CONF_MSG +$0: warning: the \"--without-http_limit_zone_module\" option is deprecated, \ +use the \"--without-http_limit_conn_module\" option instead" + ;; + --without-http_limit_conn_module) HTTP_LIMIT_CONN=NO ;; --without-http_limit_req_module) HTTP_LIMIT_REQ=NO ;; --without-http_empty_gif_module) HTTP_EMPTY_GIF=NO ;; --without-http_browser_module) HTTP_BROWSER=NO ;; @@ -364,7 +372,7 @@ cat << END --without-http_uwsgi_module disable ngx_http_uwsgi_module --without-http_scgi_module disable ngx_http_scgi_module --without-http_memcached_module disable ngx_http_memcached_module - --without-http_limit_zone_module disable ngx_http_limit_zone_module + --without-http_limit_conn_module disable ngx_http_limit_conn_module --without-http_limit_req_module disable ngx_http_limit_req_module --without-http_empty_gif_module disable ngx_http_empty_gif_module --without-http_browser_module disable ngx_http_browser_module diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -435,8 +435,8 @@ HTTP_MEMCACHED_MODULE=ngx_http_memcached HTTP_MEMCACHED_SRCS=src/http/modules/ngx_http_memcached_module.c -HTTP_LIMIT_ZONE_MODULE=ngx_http_limit_zone_module -HTTP_LIMIT_ZONE_SRCS=src/http/modules/ngx_http_limit_zone_module.c +HTTP_LIMIT_CONN_MODULE=ngx_http_limit_conn_module +HTTP_LIMIT_CONN_SRCS=src/http/modules/ngx_http_limit_conn_module.c HTTP_LIMIT_REQ_MODULE=ngx_http_limit_req_module diff --git a/auto/summary b/auto/summary --- a/auto/summary +++ b/auto/summary @@ -111,3 +111,5 @@ fi if [ $HTTP_SCGI = YES ]; then echo " nginx http scgi temporary files: \"$NGX_HTTP_SCGI_TEMP_PATH\"" fi + +echo "$NGX_POST_CONF_MSG" diff --git a/conf/mime.types b/conf/mime.types --- a/conf/mime.types +++ b/conf/mime.types @@ -22,6 +22,7 @@ types { image/x-jng jng; image/x-ms-bmp bmp; image/svg+xml svg; + image/webp webp; application/java-archive jar war ear; application/mac-binhex40 hqx; @@ -69,6 +70,7 @@ types { video/mp4 mp4; video/mpeg mpeg mpg; video/quicktime mov; + video/webm webm; video/x-flv flv; video/x-m4v m4v; video/x-mng mng; diff --git a/src/core/nginx.c b/src/core/nginx.c --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -214,47 +214,49 @@ main(int argc, char *const *argv) } if (ngx_show_version) { - ngx_log_stderr(0, "nginx version: " NGINX_VER); + ngx_write_stderr("nginx version: " NGINX_VER NGX_LINEFEED); if (ngx_show_help) { - ngx_log_stderr(0, + ngx_write_stderr( "Usage: nginx [-?hvVtq] [-s signal] [-c filename] " - "[-p prefix] [-g directives]" CRLF CRLF - "Options:" CRLF - " -?,-h : this help" CRLF - " -v : show version and exit" CRLF + "[-p prefix] [-g directives]" NGX_LINEFEED + NGX_LINEFEED + "Options:" NGX_LINEFEED + " -?,-h : this help" NGX_LINEFEED + " -v : show version and exit" NGX_LINEFEED " -V : show version and configure options then exit" - CRLF - " -t : test configuration and exit" CRLF + NGX_LINEFEED + " -t : test configuration and exit" NGX_LINEFEED " -q : suppress non-error messages " - "during configuration testing" CRLF + "during configuration testing" NGX_LINEFEED " -s signal : send signal to a master process: " - "stop, quit, reopen, reload" CRLF + "stop, quit, reopen, reload" NGX_LINEFEED #ifdef NGX_PREFIX " -p prefix : set prefix path (default: " - NGX_PREFIX ")" CRLF + NGX_PREFIX ")" NGX_LINEFEED #else - " -p prefix : set prefix path (default: NONE)" CRLF + " -p prefix : set prefix path (default: NONE)" NGX_LINEFEED #endif " -c filename : set configuration file (default: " - NGX_CONF_PATH ")" CRLF + NGX_CONF_PATH ")" NGX_LINEFEED " -g directives : set global directives out of configuration " - "file" CRLF + "file" NGX_LINEFEED NGX_LINEFEED ); } if (ngx_show_configure) { + ngx_write_stderr( #ifdef NGX_COMPILER - ngx_log_stderr(0, "built by " NGX_COMPILER); + "built by " NGX_COMPILER NGX_LINEFEED #endif #if (NGX_SSL) #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME - ngx_log_stderr(0, "TLS SNI support enabled"); + "TLS SNI support enabled" NGX_LINEFEED #else - ngx_log_stderr(0, "TLS SNI support disabled"); + "TLS SNI support disabled" NGX_LINEFEED #endif #endif - ngx_log_stderr(0, "configure arguments:" NGX_CONFIGURE); + "configure arguments:" NGX_CONFIGURE NGX_LINEFEED); } if (!ngx_test_config) { diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,8 +8,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1001007 -#define NGINX_VERSION "1.1.7" +#define nginx_version 1001008 +#define NGINX_VERSION "1.1.8" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_log.h b/src/core/ngx_log.h --- a/src/core/ngx_log.h +++ b/src/core/ngx_log.h @@ -203,6 +203,22 @@ void ngx_cdecl ngx_log_stderr(ngx_err_t u_char *ngx_log_errno(u_char *buf, u_char *last, ngx_err_t err); +/* + * ngx_write_stderr() cannot be implemented as macro, since + * MSVC does not allow to use #ifdef inside macro parameters. + * + * ngx_write_fd() is used instead of ngx_write_console(), since + * CharToOemBuff() inside ngx_write_console() cannot be used with + * read only buffer as destination and CharToOemBuff() is not needed + * for ngx_write_stderr() anyway. + */ +static ngx_inline void +ngx_write_stderr(char *text) +{ + (void) ngx_write_fd(ngx_stderr, text, strlen(text)); +} + + extern ngx_module_t ngx_errlog_module; extern ngx_uint_t ngx_use_stderr; diff --git a/src/core/ngx_md5.c b/src/core/ngx_md5.c --- a/src/core/ngx_md5.c +++ b/src/core/ngx_md5.c @@ -47,7 +47,8 @@ ngx_md5_update(ngx_md5_t *ctx, const voi return; } - data = ngx_cpymem(&ctx->buffer[used], data, free); + ngx_memcpy(&ctx->buffer[used], data, free); + data = (u_char *) data + free; size -= free; (void) ngx_md5_body(ctx, ctx->buffer, 64); } diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c --- a/src/core/ngx_resolver.c +++ b/src/core/ngx_resolver.c @@ -1952,7 +1952,13 @@ done: n = *src++; for ( ;; ) { - if (n != 0xc0) { + if (n & 0xc0) { + n = ((n & 0x3f) << 8) + *src; + src = &buf[n]; + + n = *src++; + + } else { ngx_memcpy(dst, src, n); dst += n; src += n; @@ -1962,12 +1968,6 @@ done: if (n != 0) { *dst++ = '.'; } - - } else { - n = ((n & 0x3f) << 8) + *src; - src = &buf[n]; - - n = *src++; } if (n == 0) { diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -147,6 +147,9 @@ static ngx_int_t ngx_http_fastcgi_add_va static void *ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child); +static ngx_int_t ngx_http_fastcgi_merge_params(ngx_conf_t *cf, + ngx_http_fastcgi_loc_conf_t *conf, ngx_http_fastcgi_loc_conf_t *prev); + static ngx_int_t ngx_http_fastcgi_script_name_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_fastcgi_path_info_variable(ngx_http_request_t *r, @@ -436,7 +439,7 @@ static ngx_command_t ngx_http_fastcgi_c &ngx_http_upstream_ignore_headers_masks }, { ngx_string("fastcgi_catch_stderr"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_array_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_fastcgi_loc_conf_t, catch_stderr), @@ -2085,17 +2088,9 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf ngx_http_fastcgi_loc_conf_t *prev = parent; ngx_http_fastcgi_loc_conf_t *conf = child; - u_char *p; size_t size; - uintptr_t *code; - ngx_uint_t i; - ngx_array_t headers_names; - ngx_keyval_t *src; - ngx_hash_key_t *hk; ngx_hash_init_t hash; ngx_http_core_loc_conf_t *clcf; - ngx_http_script_compile_t sc; - ngx_http_script_copy_code_t *copy; if (conf->upstream.store != 0) { ngx_conf_merge_value(conf->upstream.store, @@ -2355,95 +2350,146 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf } #endif - if (conf->params_source == NULL) { - conf->flushes = prev->flushes; - conf->params_len = prev->params_len; - conf->params = prev->params; - conf->params_source = prev->params_source; - conf->headers_hash = prev->headers_hash; - + if (ngx_http_fastcgi_merge_params(cf, conf, prev) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_fastcgi_merge_params(ngx_conf_t *cf, + ngx_http_fastcgi_loc_conf_t *conf, ngx_http_fastcgi_loc_conf_t *prev) +{ + u_char *p; + size_t size; + uintptr_t *code; + ngx_uint_t i, nsrc; + ngx_array_t headers_names; #if (NGX_HTTP_CACHE) - - if (conf->params_source == NULL) { - - if ((conf->upstream.cache == NULL) - == (prev->upstream.cache == NULL)) - { - return NGX_CONF_OK; - } - - /* 6 is a number of ngx_http_fastcgi_cache_headers entries */ - conf->params_source = ngx_array_create(cf->pool, 6, - sizeof(ngx_keyval_t)); - if (conf->params_source == NULL) { - return NGX_CONF_ERROR; - } + ngx_array_t params_merged; +#endif + ngx_keyval_t *src; + ngx_hash_key_t *hk; + ngx_hash_init_t hash; + ngx_http_script_compile_t sc; + ngx_http_script_copy_code_t *copy; + + if (conf->params_source == NULL) { + conf->params_source = prev->params_source; + + if (prev->headers_hash.buckets +#if (NGX_HTTP_CACHE) + && ((conf->upstream.cache == NULL) == (prev->upstream.cache == NULL)) +#endif + ) + { + conf->flushes = prev->flushes; + conf->params_len = prev->params_len; + conf->params = prev->params; + conf->headers_hash = prev->headers_hash; + conf->header_params = prev->header_params; + + return NGX_OK; } -#else - - if (conf->params_source == NULL) { - return NGX_CONF_OK; - } - + } + + if (conf->params_source == NULL +#if (NGX_HTTP_CACHE) + && (conf->upstream.cache == NULL) #endif + ) + { + conf->headers_hash.buckets = (void *) 1; + return NGX_OK; } conf->params_len = ngx_array_create(cf->pool, 64, 1); if (conf->params_len == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } conf->params = ngx_array_create(cf->pool, 512, 1); if (conf->params == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t)) != NGX_OK) { - return NGX_CONF_ERROR; + return NGX_ERROR; } - src = conf->params_source->elts; + if (conf->params_source) { + src = conf->params_source->elts; + nsrc = conf->params_source->nelts; + + } else { + src = NULL; + nsrc = 0; + } #if (NGX_HTTP_CACHE) if (conf->upstream.cache) { ngx_keyval_t *h, *s; - for (h = ngx_http_fastcgi_cache_headers; h->key.len; h++) { - - for (i = 0; i < conf->params_source->nelts; i++) { + if (ngx_array_init(¶ms_merged, cf->temp_pool, 4, sizeof(ngx_keyval_t)) + != NGX_OK) + { + return NGX_ERROR; + } + + for (i = 0; i < nsrc; i++) { + + s = ngx_array_push(¶ms_merged); + if (s == NULL) { + return NGX_ERROR; + } + + *s = src[i]; + } + + h = ngx_http_fastcgi_cache_headers; + + while (h->key.len) { + + src = params_merged.elts; + nsrc = params_merged.nelts; + + for (i = 0; i < nsrc; i++) { if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) { goto next; } } - s = ngx_array_push(conf->params_source); + s = ngx_array_push(¶ms_merged); if (s == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } *s = *h; - src = conf->params_source->elts; - next: h++; } + + src = params_merged.elts; + nsrc = params_merged.nelts; } #endif - for (i = 0; i < conf->params_source->nelts; i++) { + for (i = 0; i < nsrc; i++) { if (src[i].key.len > sizeof("HTTP_") - 1 && ngx_strncmp(src[i].key.data, "HTTP_", sizeof("HTTP_") - 1) == 0) { hk = ngx_array_push(&headers_names); if (hk == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } hk->key.len = src[i].key.len - 5; @@ -2459,7 +2505,7 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf copy = ngx_array_push_n(conf->params_len, sizeof(ngx_http_script_copy_code_t)); if (copy == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code; @@ -2468,11 +2514,11 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf size = (sizeof(ngx_http_script_copy_code_t) + src[i].key.len + sizeof(uintptr_t) - 1) - & ~(sizeof(uintptr_t) - 1); + & ~(sizeof(uintptr_t) - 1); copy = ngx_array_push_n(conf->params, size); if (copy == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } copy->code = ngx_http_script_copy_code; @@ -2491,12 +2537,12 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf sc.values = &conf->params; if (ngx_http_script_compile(&sc) != NGX_OK) { - return NGX_CONF_ERROR; + return NGX_ERROR; } code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t)); if (code == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } *code = (uintptr_t) NULL; @@ -2504,7 +2550,7 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf code = ngx_array_push_n(conf->params, sizeof(uintptr_t)); if (code == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } *code = (uintptr_t) NULL; @@ -2512,12 +2558,11 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t)); if (code == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } *code = (uintptr_t) NULL; - conf->header_params = headers_names.nelts; hash.hash = &conf->headers_hash; @@ -2528,12 +2573,7 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf hash.pool = cf->pool; hash.temp_pool = NULL; - if (ngx_hash_init(&hash, headers_names.elts, headers_names.nelts) != NGX_OK) - { - return NGX_CONF_ERROR; - } - - return NGX_CONF_OK; + return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts); } diff --git a/src/http/modules/ngx_http_image_filter_module.c b/src/http/modules/ngx_http_image_filter_module.c --- a/src/http/modules/ngx_http_image_filter_module.c +++ b/src/http/modules/ngx_http_image_filter_module.c @@ -41,6 +41,7 @@ typedef struct { ngx_uint_t height; ngx_uint_t angle; ngx_uint_t jpeg_quality; + ngx_uint_t sharpen; ngx_flag_t transparency; @@ -48,6 +49,7 @@ typedef struct { ngx_http_complex_value_t *hcv; ngx_http_complex_value_t *acv; ngx_http_complex_value_t *jqcv; + ngx_http_complex_value_t *shcv; size_t buffer_size; } ngx_http_image_filter_conf_t; @@ -105,6 +107,8 @@ static char *ngx_http_image_filter(ngx_c void *conf); static char *ngx_http_image_filter_jpeg_quality(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_http_image_filter_sharpen(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static ngx_int_t ngx_http_image_filter_init(ngx_conf_t *cf); @@ -124,6 +128,13 @@ static ngx_command_t ngx_http_image_fil 0, NULL }, + { ngx_string("image_filter_sharpen"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_image_filter_sharpen, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + { ngx_string("image_filter_transparency"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -724,7 +735,7 @@ static ngx_buf_t * ngx_http_image_resize(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx) { int sx, sy, dx, dy, ox, oy, ax, ay, size, - colors, palette, transparent, + colors, palette, transparent, sharpen, red, green, blue, t; u_char *out; ngx_buf_t *b; @@ -948,6 +959,11 @@ transparent: gdImageColorTransparent(dst, gdImageColorExact(dst, red, green, blue)); } + sharpen = ngx_http_image_filter_get_value(r, conf->shcv, conf->sharpen); + if (sharpen > 0) { + gdImageSharpen(dst, sharpen); + } + out = ngx_http_image_out(r, ctx->type, dst, &size); ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -1156,6 +1172,7 @@ ngx_http_image_filter_create_conf(ngx_co conf->filter = NGX_CONF_UNSET_UINT; conf->jpeg_quality = NGX_CONF_UNSET_UINT; + conf->sharpen = NGX_CONF_UNSET_UINT; conf->angle = NGX_CONF_UNSET_UINT; conf->transparency = NGX_CONF_UNSET; conf->buffer_size = NGX_CONF_UNSET_SIZE; @@ -1191,6 +1208,12 @@ ngx_http_image_filter_merge_conf(ngx_con conf->jqcv = prev->jqcv; } + ngx_conf_merge_uint_value(conf->sharpen, prev->sharpen, 0); + + if (conf->shcv == NULL) { + conf->shcv = prev->shcv; + } + ngx_conf_merge_uint_value(conf->angle, prev->angle, 0); if (conf->acv == NULL) { conf->acv = prev->acv; @@ -1401,6 +1424,53 @@ ngx_http_image_filter_jpeg_quality(ngx_c } +static char * +ngx_http_image_filter_sharpen(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + ngx_http_image_filter_conf_t *imcf = conf; + + ngx_str_t *value; + ngx_int_t n; + ngx_http_complex_value_t cv; + ngx_http_compile_complex_value_t ccv; + + value = cf->args->elts; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &cv; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cv.lengths == NULL) { + n = ngx_http_image_filter_value(&value[1]); + + if (n < 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } + + imcf->sharpen = (ngx_uint_t) n; + + } else { + imcf->shcv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t)); + if (imcf->shcv == NULL) { + return NGX_CONF_ERROR; + } + + *imcf->shcv = cv; + } + + return NGX_CONF_OK; +} + + static ngx_int_t ngx_http_image_filter_init(ngx_conf_t *cf) { diff --git a/src/http/modules/ngx_http_limit_conn_module.c b/src/http/modules/ngx_http_limit_conn_module.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_limit_conn_module.c @@ -0,0 +1,751 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +typedef struct { + u_char color; + u_char len; + u_short conn; + u_char data[1]; +} ngx_http_limit_conn_node_t; + + +typedef struct { + ngx_shm_zone_t *shm_zone; + ngx_rbtree_node_t *node; +} ngx_http_limit_conn_cleanup_t; + + +typedef struct { + ngx_rbtree_t *rbtree; + ngx_int_t index; + ngx_str_t var; +} ngx_http_limit_conn_ctx_t; + + +typedef struct { + ngx_shm_zone_t *shm_zone; + ngx_uint_t conn; +} ngx_http_limit_conn_limit_t; + + +typedef struct { + ngx_array_t limits; + ngx_uint_t log_level; +} ngx_http_limit_conn_conf_t; + + +static ngx_rbtree_node_t *ngx_http_limit_conn_lookup(ngx_rbtree_t *rbtree, + ngx_http_variable_value_t *vv, uint32_t hash); +static void ngx_http_limit_conn_cleanup(void *data); +static ngx_inline void ngx_http_limit_conn_cleanup_all(ngx_pool_t *pool); + +static void *ngx_http_limit_conn_create_conf(ngx_conf_t *cf); +static char *ngx_http_limit_conn_merge_conf(ngx_conf_t *cf, void *parent, + void *child); +static char *ngx_http_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_http_limit_zone(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static ngx_int_t ngx_http_limit_conn_init(ngx_conf_t *cf); + + +static ngx_conf_deprecated_t ngx_conf_deprecated_limit_zone = { + ngx_conf_deprecated, "limit_zone", "limit_conn_zone" +}; + + +static ngx_conf_enum_t ngx_http_limit_conn_log_levels[] = { + { ngx_string("info"), NGX_LOG_INFO }, + { ngx_string("notice"), NGX_LOG_NOTICE }, + { ngx_string("warn"), NGX_LOG_WARN }, + { ngx_string("error"), NGX_LOG_ERR }, + { ngx_null_string, 0 } +}; + + +static ngx_command_t ngx_http_limit_conn_commands[] = { + + { ngx_string("limit_conn_zone"), + NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE2, + ngx_http_limit_conn_zone, + 0, + 0, + NULL }, + + { ngx_string("limit_zone"), + NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE3, + ngx_http_limit_zone, + 0, + 0, + NULL }, + + { ngx_string("limit_conn"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, + ngx_http_limit_conn, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("limit_conn_log_level"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_enum_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_limit_conn_conf_t, log_level), + &ngx_http_limit_conn_log_levels }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_limit_conn_module_ctx = { + NULL, /* preconfiguration */ + ngx_http_limit_conn_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_limit_conn_create_conf, /* create location configration */ + ngx_http_limit_conn_merge_conf /* merge location configration */ +}; + + +ngx_module_t ngx_http_limit_conn_module = { + NGX_MODULE_V1, + &ngx_http_limit_conn_module_ctx, /* module context */ + ngx_http_limit_conn_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_int_t +ngx_http_limit_conn_handler(ngx_http_request_t *r) +{ + size_t len, n; + uint32_t hash; + ngx_uint_t i; + ngx_slab_pool_t *shpool; + ngx_rbtree_node_t *node; + ngx_pool_cleanup_t *cln; + ngx_http_variable_value_t *vv; + ngx_http_limit_conn_ctx_t *ctx; + ngx_http_limit_conn_node_t *lc; + ngx_http_limit_conn_conf_t *lccf; + ngx_http_limit_conn_limit_t *limits; + ngx_http_limit_conn_cleanup_t *lccln; + + if (r->main->limit_conn_set) { + return NGX_DECLINED; + } + + r->main->limit_conn_set = 1; + + lccf = ngx_http_get_module_loc_conf(r, ngx_http_limit_conn_module); + limits = lccf->limits.elts; + + for (i = 0; i < lccf->limits.nelts; i++) { + ctx = limits[i].shm_zone->data; + + vv = ngx_http_get_indexed_variable(r, ctx->index); + + if (vv == NULL || vv->not_found) { + continue; + } + + len = vv->len; + + if (len == 0) { + continue; + } + + if (len > 255) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "the value of the \"%V\" variable " + "is more than 255 bytes: \"%v\"", + &ctx->var, vv); + continue; + } + + hash = ngx_crc32_short(vv->data, len); + + shpool = (ngx_slab_pool_t *) limits[i].shm_zone->shm.addr; + + ngx_shmtx_lock(&shpool->mutex); + + node = ngx_http_limit_conn_lookup(ctx->rbtree, vv, hash); + + if (node == NULL) { + + n = offsetof(ngx_rbtree_node_t, color) + + offsetof(ngx_http_limit_conn_node_t, data) + + len; + + node = ngx_slab_alloc_locked(shpool, n); + + if (node == NULL) { + ngx_shmtx_unlock(&shpool->mutex); + ngx_http_limit_conn_cleanup_all(r->pool); + return NGX_HTTP_SERVICE_UNAVAILABLE; + } + + lc = (ngx_http_limit_conn_node_t *) &node->color; + + node->key = hash; + lc->len = (u_char) len; + lc->conn = 1; + ngx_memcpy(lc->data, vv->data, len); + + ngx_rbtree_insert(ctx->rbtree, node); + + } else { + + lc = (ngx_http_limit_conn_node_t *) &node->color; + + if ((ngx_uint_t) lc->conn >= limits[i].conn) { + + ngx_shmtx_unlock(&shpool->mutex); + + ngx_log_error(lccf->log_level, r->connection->log, 0, + "limiting connections by zone \"%V\"", + &limits[i].shm_zone->shm.name); + + ngx_http_limit_conn_cleanup_all(r->pool); + return NGX_HTTP_SERVICE_UNAVAILABLE; + } + + lc->conn++; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "limit zone: %08XD %d", node->key, lc->conn); + + ngx_shmtx_unlock(&shpool->mutex); + + cln = ngx_pool_cleanup_add(r->pool, + sizeof(ngx_http_limit_conn_cleanup_t)); + if (cln == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + cln->handler = ngx_http_limit_conn_cleanup; + lccln = cln->data; + + lccln->shm_zone = limits[i].shm_zone; + lccln->node = node; + } + + return NGX_DECLINED; +} + + +static void +ngx_http_limit_conn_rbtree_insert_value(ngx_rbtree_node_t *temp, + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) +{ + ngx_rbtree_node_t **p; + ngx_http_limit_conn_node_t *lcn, *lcnt; + + for ( ;; ) { + + if (node->key < temp->key) { + + p = &temp->left; + + } else if (node->key > temp->key) { + + p = &temp->right; + + } else { /* node->key == temp->key */ + + lcn = (ngx_http_limit_conn_node_t *) &node->color; + lcnt = (ngx_http_limit_conn_node_t *) &temp->color; + + p = (ngx_memn2cmp(lcn->data, lcnt->data, lcn->len, lcnt->len) < 0) + ? &temp->left : &temp->right; + } + + if (*p == sentinel) { + break; + } + + temp = *p; + } + + *p = node; + node->parent = temp; + node->left = sentinel; + node->right = sentinel; + ngx_rbt_red(node); +} + + +static ngx_rbtree_node_t * +ngx_http_limit_conn_lookup(ngx_rbtree_t *rbtree, ngx_http_variable_value_t *vv, + uint32_t hash) +{ + ngx_int_t rc; + ngx_rbtree_node_t *node, *sentinel; + ngx_http_limit_conn_node_t *lcn; + + node = rbtree->root; + sentinel = rbtree->sentinel; + + while (node != sentinel) { + + if (hash < node->key) { + node = node->left; + continue; + } + + if (hash > node->key) { + node = node->right; + continue; + } + + /* hash == node->key */ + + do { + lcn = (ngx_http_limit_conn_node_t *) &node->color; + + rc = ngx_memn2cmp(vv->data, lcn->data, + (size_t) vv->len, (size_t) lcn->len); + if (rc == 0) { + return node; + } + + node = (rc < 0) ? node->left : node->right; + + } while (node != sentinel && hash == node->key); + + break; + } + + return NULL; +} + + +static void +ngx_http_limit_conn_cleanup(void *data) +{ + ngx_http_limit_conn_cleanup_t *lccln = data; + + ngx_slab_pool_t *shpool; + ngx_rbtree_node_t *node; + ngx_http_limit_conn_ctx_t *ctx; + ngx_http_limit_conn_node_t *lc; + + ctx = lccln->shm_zone->data; + shpool = (ngx_slab_pool_t *) lccln->shm_zone->shm.addr; + node = lccln->node; + lc = (ngx_http_limit_conn_node_t *) &node->color; + + ngx_shmtx_lock(&shpool->mutex); + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, lccln->shm_zone->shm.log, 0, + "limit zone cleanup: %08XD %d", node->key, lc->conn); + + lc->conn--; + + if (lc->conn == 0) { + ngx_rbtree_delete(ctx->rbtree, node); + ngx_slab_free_locked(shpool, node); + } + + ngx_shmtx_unlock(&shpool->mutex); +} + + +static ngx_inline void +ngx_http_limit_conn_cleanup_all(ngx_pool_t *pool) +{ + ngx_pool_cleanup_t *cln; + + cln = pool->cleanup; + + while (cln && cln->handler == ngx_http_limit_conn_cleanup) { + ngx_http_limit_conn_cleanup(cln->data); + cln = cln->next; + } + + pool->cleanup = cln; +} + + +static ngx_int_t +ngx_http_limit_conn_init_zone(ngx_shm_zone_t *shm_zone, void *data) +{ + ngx_http_limit_conn_ctx_t *octx = data; + + size_t len; + ngx_slab_pool_t *shpool; + ngx_rbtree_node_t *sentinel; + ngx_http_limit_conn_ctx_t *ctx; + + ctx = shm_zone->data; + + if (octx) { + if (ngx_strcmp(ctx->var.data, octx->var.data) != 0) { + ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0, + "limit_conn_zone \"%V\" uses the \"%V\" variable " + "while previously it used the \"%V\" variable", + &shm_zone->shm.name, &ctx->var, &octx->var); + return NGX_ERROR; + } + + ctx->rbtree = octx->rbtree; + + return NGX_OK; + } + + shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; + + if (shm_zone->shm.exists) { + ctx->rbtree = shpool->data; + + return NGX_OK; + } + + ctx->rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t)); + if (ctx->rbtree == NULL) { + return NGX_ERROR; + } + + shpool->data = ctx->rbtree; + + sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t)); + if (sentinel == NULL) { + return NGX_ERROR; + } + + ngx_rbtree_init(ctx->rbtree, sentinel, + ngx_http_limit_conn_rbtree_insert_value); + + len = sizeof(" in limit_conn_zone \"\"") + shm_zone->shm.name.len; + + shpool->log_ctx = ngx_slab_alloc(shpool, len); + if (shpool->log_ctx == NULL) { + return NGX_ERROR; + } + + ngx_sprintf(shpool->log_ctx, " in limit_conn_zone \"%V\"%Z", + &shm_zone->shm.name); + + return NGX_OK; +} + + +static void * +ngx_http_limit_conn_create_conf(ngx_conf_t *cf) +{ + ngx_http_limit_conn_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_conn_conf_t)); + if (conf == NULL) { + return NULL; + } + + /* + * set by ngx_pcalloc(): + * + * conf->limits.elts = NULL; + */ + + conf->log_level = NGX_CONF_UNSET_UINT; + + return conf; +} + + +static char * +ngx_http_limit_conn_merge_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_limit_conn_conf_t *prev = parent; + ngx_http_limit_conn_conf_t *conf = child; + + if (conf->limits.elts == NULL) { + *conf = *prev; + } + + ngx_conf_merge_uint_value(conf->log_level, prev->log_level, NGX_LOG_ERR); + + return NGX_CONF_OK; +} + + +static char * +ngx_http_limit_conn_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + u_char *p; + ssize_t size; + ngx_str_t *value, name, s; + ngx_uint_t i; + ngx_shm_zone_t *shm_zone; + ngx_http_limit_conn_ctx_t *ctx; + + value = cf->args->elts; + + ctx = NULL; + size = 0; + name.len = 0; + + for (i = 1; i < cf->args->nelts; i++) { + + if (ngx_strncmp(value[i].data, "zone=", 5) == 0) { + + name.data = value[i].data + 5; + + p = (u_char *) ngx_strchr(name.data, ':'); + + if (p == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid zone size \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + name.len = p - name.data; + + s.data = p + 1; + s.len = value[i].data + value[i].len - s.data; + + size = ngx_parse_size(&s); + + if (size == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid zone size \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + if (size < (ssize_t) (8 * ngx_pagesize)) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "zone \"%V\" is too small", &value[i]); + return NGX_CONF_ERROR; + } + + continue; + } + + if (value[i].data[0] == '$') { + + value[i].len--; + value[i].data++; + + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_conn_ctx_t)); + if (ctx == NULL) { + return NGX_CONF_ERROR; + } + + ctx->index = ngx_http_get_variable_index(cf, &value[i]); + if (ctx->index == NGX_ERROR) { + return NGX_CONF_ERROR; + } + + ctx->var = value[i]; + + continue; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + if (name.len == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"%V\" must have \"zone\" parameter", + &cmd->name); + return NGX_CONF_ERROR; + } + + if (ctx == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "no variable is defined for %V \"%V\"", + &cmd->name, &name); + return NGX_CONF_ERROR; + } + + shm_zone = ngx_shared_memory_add(cf, &name, size, + &ngx_http_limit_conn_module); + if (shm_zone == NULL) { + return NGX_CONF_ERROR; + } + + if (shm_zone->data) { + ctx = shm_zone->data; + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%V \"%V\" is already bound to variable \"%V\"", + &cmd->name, &name, &ctx->var); + return NGX_CONF_ERROR; + } + + shm_zone->init = ngx_http_limit_conn_init_zone; + shm_zone->data = ctx; + + return NGX_CONF_OK; +} + + +static char * +ngx_http_limit_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ssize_t n; + ngx_str_t *value; + ngx_shm_zone_t *shm_zone; + ngx_http_limit_conn_ctx_t *ctx; + + ngx_conf_deprecated(cf, &ngx_conf_deprecated_limit_zone, NULL); + + value = cf->args->elts; + + if (value[2].data[0] != '$') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid variable name \"%V\"", &value[2]); + return NGX_CONF_ERROR; + } + + value[2].len--; + value[2].data++; + + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_conn_ctx_t)); + if (ctx == NULL) { + return NGX_CONF_ERROR; + } + + ctx->index = ngx_http_get_variable_index(cf, &value[2]); + if (ctx->index == NGX_ERROR) { + return NGX_CONF_ERROR; + } + + ctx->var = value[2]; + + n = ngx_parse_size(&value[3]); + + if (n == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid size of limit_zone \"%V\"", &value[3]); + return NGX_CONF_ERROR; + } + + if (n < (ngx_int_t) (8 * ngx_pagesize)) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "limit_zone \"%V\" is too small", &value[1]); + return NGX_CONF_ERROR; + } + + + shm_zone = ngx_shared_memory_add(cf, &value[1], n, + &ngx_http_limit_conn_module); + if (shm_zone == NULL) { + return NGX_CONF_ERROR; + } + + if (shm_zone->data) { + ctx = shm_zone->data; + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "limit_zone \"%V\" is already bound to variable \"%V\"", + &value[1], &ctx->var); + return NGX_CONF_ERROR; + } + + shm_zone->init = ngx_http_limit_conn_init_zone; + shm_zone->data = ctx; + + return NGX_CONF_OK; +} + + +static char * +ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_shm_zone_t *shm_zone; + ngx_http_limit_conn_conf_t *lccf = conf; + ngx_http_limit_conn_limit_t *limit, *limits; + + ngx_str_t *value; + ngx_int_t n; + ngx_uint_t i; + + value = cf->args->elts; + + shm_zone = ngx_shared_memory_add(cf, &value[1], 0, + &ngx_http_limit_conn_module); + if (shm_zone == NULL) { + return NGX_CONF_ERROR; + } + + limits = lccf->limits.elts; + + if (limits == NULL) { + if (ngx_array_init(&lccf->limits, cf->pool, 1, + sizeof(ngx_http_limit_conn_limit_t)) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + } + + for (i = 0; i < lccf->limits.nelts; i++) { + if (shm_zone == limits[i].shm_zone) { + return "is duplicate"; + } + } + + n = ngx_atoi(value[2].data, value[2].len); + if (n <= 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid number of connections \"%V\"", &value[2]); + return NGX_CONF_ERROR; + } + + if (n > 65535) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "connection limit must be less 65536"); + return NGX_CONF_ERROR; + } + + limit = ngx_array_push(&lccf->limits); + limit->conn = n; + limit->shm_zone = shm_zone; + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_limit_conn_init(ngx_conf_t *cf) +{ + ngx_http_handler_pt *h; + ngx_http_core_main_conf_t *cmcf; + + cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); + + h = ngx_array_push(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_limit_conn_handler; + + return NGX_OK; +} diff --git a/src/http/modules/ngx_http_limit_zone_module.c b/src/http/modules/ngx_http_limit_zone_module.c deleted file mode 100644 --- a/src/http/modules/ngx_http_limit_zone_module.c +++ /dev/null @@ -1,556 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#include -#include -#include - - -typedef struct { - u_char color; - u_char len; - u_short conn; - u_char data[1]; -} ngx_http_limit_zone_node_t; - - -typedef struct { - ngx_shm_zone_t *shm_zone; - ngx_rbtree_node_t *node; -} ngx_http_limit_zone_cleanup_t; - - -typedef struct { - ngx_rbtree_t *rbtree; - ngx_int_t index; - ngx_str_t var; -} ngx_http_limit_zone_ctx_t; - - -typedef struct { - ngx_shm_zone_t *shm_zone; - ngx_uint_t conn; - ngx_uint_t log_level; -} ngx_http_limit_zone_conf_t; - - -static void ngx_http_limit_zone_cleanup(void *data); - -static void *ngx_http_limit_zone_create_conf(ngx_conf_t *cf); -static char *ngx_http_limit_zone_merge_conf(ngx_conf_t *cf, void *parent, - void *child); -static char *ngx_http_limit_zone(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); -static char *ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); -static ngx_int_t ngx_http_limit_zone_init(ngx_conf_t *cf); - - -static ngx_conf_enum_t ngx_http_limit_conn_log_levels[] = { - { ngx_string("info"), NGX_LOG_INFO }, - { ngx_string("notice"), NGX_LOG_NOTICE }, - { ngx_string("warn"), NGX_LOG_WARN }, - { ngx_string("error"), NGX_LOG_ERR }, - { ngx_null_string, 0 } -}; - - -static ngx_command_t ngx_http_limit_zone_commands[] = { - - { ngx_string("limit_zone"), - NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE3, - ngx_http_limit_zone, - 0, - 0, - NULL }, - - { ngx_string("limit_conn"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, - ngx_http_limit_conn, - NGX_HTTP_LOC_CONF_OFFSET, - 0, - NULL }, - - { ngx_string("limit_conn_log_level"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_enum_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_limit_zone_conf_t, log_level), - &ngx_http_limit_conn_log_levels }, - - ngx_null_command -}; - - -static ngx_http_module_t ngx_http_limit_zone_module_ctx = { - NULL, /* preconfiguration */ - ngx_http_limit_zone_init, /* postconfiguration */ - - NULL, /* create main configuration */ - NULL, /* init main configuration */ - - NULL, /* create server configuration */ - NULL, /* merge server configuration */ - - ngx_http_limit_zone_create_conf, /* create location configration */ - ngx_http_limit_zone_merge_conf /* merge location configration */ -}; - - -ngx_module_t ngx_http_limit_zone_module = { - NGX_MODULE_V1, - &ngx_http_limit_zone_module_ctx, /* module context */ - ngx_http_limit_zone_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_int_t -ngx_http_limit_zone_handler(ngx_http_request_t *r) -{ - size_t len, n; - uint32_t hash; - ngx_int_t rc; - ngx_slab_pool_t *shpool; - ngx_rbtree_node_t *node, *sentinel; - ngx_pool_cleanup_t *cln; - ngx_http_variable_value_t *vv; - ngx_http_limit_zone_ctx_t *ctx; - ngx_http_limit_zone_node_t *lz; - ngx_http_limit_zone_conf_t *lzcf; - ngx_http_limit_zone_cleanup_t *lzcln; - - if (r->main->limit_zone_set) { - return NGX_DECLINED; - } - - lzcf = ngx_http_get_module_loc_conf(r, ngx_http_limit_zone_module); - - if (lzcf->shm_zone == NULL) { - return NGX_DECLINED; - } - - ctx = lzcf->shm_zone->data; - - vv = ngx_http_get_indexed_variable(r, ctx->index); - - if (vv == NULL || vv->not_found) { - return NGX_DECLINED; - } - - len = vv->len; - - if (len == 0) { - return NGX_DECLINED; - } - - if (len > 255) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "the value of the \"%V\" variable " - "is more than 255 bytes: \"%v\"", - &ctx->var, vv); - return NGX_DECLINED; - } - - r->main->limit_zone_set = 1; - - hash = ngx_crc32_short(vv->data, len); - - cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_limit_zone_cleanup_t)); - if (cln == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - shpool = (ngx_slab_pool_t *) lzcf->shm_zone->shm.addr; - - ngx_shmtx_lock(&shpool->mutex); - - node = ctx->rbtree->root; - sentinel = ctx->rbtree->sentinel; - - while (node != sentinel) { - - if (hash < node->key) { - node = node->left; - continue; - } - - if (hash > node->key) { - node = node->right; - continue; - } - - /* hash == node->key */ - - do { - lz = (ngx_http_limit_zone_node_t *) &node->color; - - rc = ngx_memn2cmp(vv->data, lz->data, len, (size_t) lz->len); - - if (rc == 0) { - if ((ngx_uint_t) lz->conn < lzcf->conn) { - lz->conn++; - goto done; - } - - ngx_shmtx_unlock(&shpool->mutex); - - ngx_log_error(lzcf->log_level, r->connection->log, 0, - "limiting connections by zone \"%V\"", - &lzcf->shm_zone->shm.name); - - return NGX_HTTP_SERVICE_UNAVAILABLE; - } - - node = (rc < 0) ? node->left : node->right; - - } while (node != sentinel && hash == node->key); - - break; - } - - n = offsetof(ngx_rbtree_node_t, color) - + offsetof(ngx_http_limit_zone_node_t, data) - + len; - - node = ngx_slab_alloc_locked(shpool, n); - if (node == NULL) { - ngx_shmtx_unlock(&shpool->mutex); - return NGX_HTTP_SERVICE_UNAVAILABLE; - } - - lz = (ngx_http_limit_zone_node_t *) &node->color; - - node->key = hash; - lz->len = (u_char) len; - lz->conn = 1; - ngx_memcpy(lz->data, vv->data, len); - - ngx_rbtree_insert(ctx->rbtree, node); - -done: - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "limit zone: %08XD %d", node->key, lz->conn); - - ngx_shmtx_unlock(&shpool->mutex); - - cln->handler = ngx_http_limit_zone_cleanup; - lzcln = cln->data; - - lzcln->shm_zone = lzcf->shm_zone; - lzcln->node = node; - - return NGX_DECLINED; -} - - -static void -ngx_http_limit_zone_rbtree_insert_value(ngx_rbtree_node_t *temp, - ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) -{ - ngx_rbtree_node_t **p; - ngx_http_limit_zone_node_t *lzn, *lznt; - - for ( ;; ) { - - if (node->key < temp->key) { - - p = &temp->left; - - } else if (node->key > temp->key) { - - p = &temp->right; - - } else { /* node->key == temp->key */ - - lzn = (ngx_http_limit_zone_node_t *) &node->color; - lznt = (ngx_http_limit_zone_node_t *) &temp->color; - - p = (ngx_memn2cmp(lzn->data, lznt->data, lzn->len, lznt->len) < 0) - ? &temp->left : &temp->right; - } - - if (*p == sentinel) { - break; - } - - temp = *p; - } - - *p = node; - node->parent = temp; - node->left = sentinel; - node->right = sentinel; - ngx_rbt_red(node); -} - - -static void -ngx_http_limit_zone_cleanup(void *data) -{ - ngx_http_limit_zone_cleanup_t *lzcln = data; - - ngx_slab_pool_t *shpool; - ngx_rbtree_node_t *node; - ngx_http_limit_zone_ctx_t *ctx; - ngx_http_limit_zone_node_t *lz; - - ctx = lzcln->shm_zone->data; - shpool = (ngx_slab_pool_t *) lzcln->shm_zone->shm.addr; - node = lzcln->node; - lz = (ngx_http_limit_zone_node_t *) &node->color; - - ngx_shmtx_lock(&shpool->mutex); - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, lzcln->shm_zone->shm.log, 0, - "limit zone cleanup: %08XD %d", node->key, lz->conn); - - lz->conn--; - - if (lz->conn == 0) { - ngx_rbtree_delete(ctx->rbtree, node); - ngx_slab_free_locked(shpool, node); - } - - ngx_shmtx_unlock(&shpool->mutex); -} - - -static ngx_int_t -ngx_http_limit_zone_init_zone(ngx_shm_zone_t *shm_zone, void *data) -{ - ngx_http_limit_zone_ctx_t *octx = data; - - size_t len; - ngx_slab_pool_t *shpool; - ngx_rbtree_node_t *sentinel; - ngx_http_limit_zone_ctx_t *ctx; - - ctx = shm_zone->data; - - if (octx) { - if (ngx_strcmp(ctx->var.data, octx->var.data) != 0) { - ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0, - "limit_zone \"%V\" uses the \"%V\" variable " - "while previously it used the \"%V\" variable", - &shm_zone->shm.name, &ctx->var, &octx->var); - return NGX_ERROR; - } - - ctx->rbtree = octx->rbtree; - - return NGX_OK; - } - - shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; - - if (shm_zone->shm.exists) { - ctx->rbtree = shpool->data; - - return NGX_OK; - } - - ctx->rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t)); - if (ctx->rbtree == NULL) { - return NGX_ERROR; - } - - shpool->data = ctx->rbtree; - - sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t)); - if (sentinel == NULL) { - return NGX_ERROR; - } - - ngx_rbtree_init(ctx->rbtree, sentinel, - ngx_http_limit_zone_rbtree_insert_value); - - len = sizeof(" in limit_zone \"\"") + shm_zone->shm.name.len; - - shpool->log_ctx = ngx_slab_alloc(shpool, len); - if (shpool->log_ctx == NULL) { - return NGX_ERROR; - } - - ngx_sprintf(shpool->log_ctx, " in limit_zone \"%V\"%Z", - &shm_zone->shm.name); - - return NGX_OK; -} - - -static void * -ngx_http_limit_zone_create_conf(ngx_conf_t *cf) -{ - ngx_http_limit_zone_conf_t *conf; - - conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_zone_conf_t)); - if (conf == NULL) { - return NULL; - } - - /* - * set by ngx_pcalloc(): - * - * conf->shm_zone = NULL; - * conf->conn = 0; - */ - - conf->log_level = NGX_CONF_UNSET_UINT; - - return conf; -} - - -static char * -ngx_http_limit_zone_merge_conf(ngx_conf_t *cf, void *parent, void *child) -{ - ngx_http_limit_zone_conf_t *prev = parent; - ngx_http_limit_zone_conf_t *conf = child; - - if (conf->shm_zone == NULL) { - *conf = *prev; - } - - ngx_conf_merge_uint_value(conf->log_level, prev->log_level, NGX_LOG_ERR); - - return NGX_CONF_OK; -} - - -static char * -ngx_http_limit_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ssize_t n; - ngx_str_t *value; - ngx_shm_zone_t *shm_zone; - ngx_http_limit_zone_ctx_t *ctx; - - value = cf->args->elts; - - if (value[2].data[0] != '$') { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid variable name \"%V\"", &value[2]); - return NGX_CONF_ERROR; - } - - value[2].len--; - value[2].data++; - - ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_zone_ctx_t)); - if (ctx == NULL) { - return NGX_CONF_ERROR; - } - - ctx->index = ngx_http_get_variable_index(cf, &value[2]); - if (ctx->index == NGX_ERROR) { - return NGX_CONF_ERROR; - } - - ctx->var = value[2]; - - n = ngx_parse_size(&value[3]); - - if (n == NGX_ERROR) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid size of limit_zone \"%V\"", &value[3]); - return NGX_CONF_ERROR; - } - - if (n < (ngx_int_t) (8 * ngx_pagesize)) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "limit_zone \"%V\" is too small", &value[1]); - return NGX_CONF_ERROR; - } - - - shm_zone = ngx_shared_memory_add(cf, &value[1], n, - &ngx_http_limit_zone_module); - if (shm_zone == NULL) { - return NGX_CONF_ERROR; - } - - if (shm_zone->data) { - ctx = shm_zone->data; - - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "limit_zone \"%V\" is already bound to variable \"%V\"", - &value[1], &ctx->var); - return NGX_CONF_ERROR; - } - - shm_zone->init = ngx_http_limit_zone_init_zone; - shm_zone->data = ctx; - - return NGX_CONF_OK; -} - - -static char * -ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_http_limit_zone_conf_t *lzcf = conf; - - ngx_int_t n; - ngx_str_t *value; - - if (lzcf->shm_zone) { - return "is duplicate"; - } - - value = cf->args->elts; - - lzcf->shm_zone = ngx_shared_memory_add(cf, &value[1], 0, - &ngx_http_limit_zone_module); - if (lzcf->shm_zone == NULL) { - return NGX_CONF_ERROR; - } - - n = ngx_atoi(value[2].data, value[2].len); - if (n <= 0) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid number of connections \"%V\"", &value[2]); - return NGX_CONF_ERROR; - } - - if (n > 65535) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "connection limit must be less 65536"); - return NGX_CONF_ERROR; - } - - lzcf->conn = n; - - return NGX_CONF_OK; -} - - -static ngx_int_t -ngx_http_limit_zone_init(ngx_conf_t *cf) -{ - ngx_http_handler_pt *h; - ngx_http_core_main_conf_t *cmcf; - - cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); - - h = ngx_array_push(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers); - if (h == NULL) { - return NGX_ERROR; - } - - *h = ngx_http_limit_zone_handler; - - return NGX_OK; -} diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -1066,7 +1066,6 @@ ngx_http_mp4_update_mdat_atom(ngx_http_m atom_data_size = mp4->mdat_data.buf->file_last - start_offset; mp4->mdat_data.buf->file_pos = start_offset; - mp4->content_length += atom_data_size; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0, "mdat new offset @%O:%O", start_offset, atom_data_size); @@ -1083,6 +1082,8 @@ ngx_http_mp4_update_mdat_atom(ngx_http_m atom_header_size = sizeof(ngx_mp4_atom_header_t); } + mp4->content_length += atom_header_size + atom_data_size; + ngx_mp4_set_32value(atom_header, atom_size); ngx_mp4_set_atom_name(atom_header, 'm', 'd', 'a', 't'); diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -543,6 +543,7 @@ static ngx_keyval_t ngx_http_proxy_cach { ngx_string("Connection"), ngx_string("close") }, { ngx_string("Keep-Alive"), ngx_string("") }, { ngx_string("Expect"), ngx_string("") }, + { ngx_string("Upgrade"), ngx_string("") }, { ngx_string("If-Modified-Since"), ngx_string("") }, { ngx_string("If-Unmodified-Since"), ngx_string("") }, { ngx_string("If-None-Match"), ngx_string("") }, @@ -2493,7 +2494,6 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t u_char *p; size_t size; - ngx_keyval_t *s; ngx_hash_init_t hash; ngx_http_core_loc_conf_t *clcf; ngx_http_proxy_redirect_t *pr; @@ -2841,22 +2841,6 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t if (ngx_http_script_compile(&sc) != NGX_OK) { return NGX_CONF_ERROR; } - - if (conf->headers_source == NULL) { - conf->headers_source = ngx_array_create(cf->pool, 4, - sizeof(ngx_keyval_t)); - if (conf->headers_source == NULL) { - return NGX_CONF_ERROR; - } - } - - s = ngx_array_push(conf->headers_source); - if (s == NULL) { - return NGX_CONF_ERROR; - } - - ngx_str_set(&s->key, "Content-Length"); - ngx_str_set(&s->value, "$proxy_internal_body_length"); } if (ngx_http_proxy_merge_headers(cf, conf, prev) != NGX_OK) { @@ -2875,7 +2859,7 @@ ngx_http_proxy_merge_headers(ngx_conf_t size_t size; uintptr_t *code; ngx_uint_t i; - ngx_array_t headers_names; + ngx_array_t headers_names, headers_merged; ngx_keyval_t *src, *s, *h; ngx_hash_key_t *hk; ngx_hash_init_t hash; @@ -2891,6 +2875,8 @@ ngx_http_proxy_merge_headers(ngx_conf_t } if (conf->headers_set_hash.buckets + && ((conf->body_source.data == NULL) + == (prev->body_source.data == NULL)) #if (NGX_HTTP_CACHE) && ((conf->upstream.cache == NULL) == (prev->upstream.cache == NULL)) #endif @@ -2906,6 +2892,12 @@ ngx_http_proxy_merge_headers(ngx_conf_t return NGX_ERROR; } + if (ngx_array_init(&headers_merged, cf->temp_pool, 4, sizeof(ngx_keyval_t)) + != NGX_OK) + { + return NGX_ERROR; + } + if (conf->headers_source == NULL) { conf->headers_source = ngx_array_create(cf->pool, 4, sizeof(ngx_keyval_t)); @@ -2925,8 +2917,6 @@ ngx_http_proxy_merge_headers(ngx_conf_t } - src = conf->headers_source->elts; - #if (NGX_HTTP_CACHE) h = conf->upstream.cache ? ngx_http_proxy_cache_headers: @@ -2937,31 +2927,51 @@ ngx_http_proxy_merge_headers(ngx_conf_t #endif + src = conf->headers_source->elts; + for (i = 0; i < conf->headers_source->nelts; i++) { + + s = ngx_array_push(&headers_merged); + if (s == NULL) { + return NGX_ERROR; + } + + *s = src[i]; + } + while (h->key.len) { - for (i = 0; i < conf->headers_source->nelts; i++) { + src = headers_merged.elts; + for (i = 0; i < headers_merged.nelts; i++) { if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) { goto next; } } - s = ngx_array_push(conf->headers_source); + s = ngx_array_push(&headers_merged); if (s == NULL) { return NGX_ERROR; } *s = *h; - src = conf->headers_source->elts; - next: h++; } - - src = conf->headers_source->elts; - for (i = 0; i < conf->headers_source->nelts; i++) { + if (conf->body_source.data) { + s = ngx_array_push(&headers_merged); + if (s == NULL) { + return NGX_ERROR; + } + + ngx_str_set(&s->key, "Content-Length"); + ngx_str_set(&s->value, "$proxy_internal_body_length"); + } + + + src = headers_merged.elts; + for (i = 0; i < headers_merged.nelts; i++) { hk = ngx_array_push(&headers_names); if (hk == NULL) { diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c --- a/src/http/modules/ngx_http_scgi_module.c +++ b/src/http/modules/ngx_http_scgi_module.c @@ -43,6 +43,8 @@ static void ngx_http_scgi_finalize_reque static void *ngx_http_scgi_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_scgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child); +static ngx_int_t ngx_http_scgi_merge_params(ngx_conf_t *cf, + ngx_http_scgi_loc_conf_t *conf, ngx_http_scgi_loc_conf_t *prev); static char *ngx_http_scgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_scgi_store(ngx_conf_t *cf, ngx_command_t *cmd, @@ -1059,17 +1061,9 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t ngx_http_scgi_loc_conf_t *prev = parent; ngx_http_scgi_loc_conf_t *conf = child; - u_char *p; size_t size; - uintptr_t *code; - ngx_uint_t i; - ngx_array_t headers_names; - ngx_keyval_t *src; - ngx_hash_key_t *hk; ngx_hash_init_t hash; ngx_http_core_loc_conf_t *clcf; - ngx_http_script_compile_t sc; - ngx_http_script_copy_code_t *copy; if (conf->upstream.store != 0) { ngx_conf_merge_value(conf->upstream.store, prev->upstream.store, 0); @@ -1307,95 +1301,146 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t } } - if (conf->params_source == NULL) { - conf->flushes = prev->flushes; - conf->params_len = prev->params_len; - conf->params = prev->params; - conf->params_source = prev->params_source; - conf->headers_hash = prev->headers_hash; + if (ngx_http_scgi_merge_params(cf, conf, prev) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + +static ngx_int_t +ngx_http_scgi_merge_params(ngx_conf_t *cf, ngx_http_scgi_loc_conf_t *conf, + ngx_http_scgi_loc_conf_t *prev) +{ + u_char *p; + size_t size; + uintptr_t *code; + ngx_uint_t i, nsrc; + ngx_array_t headers_names; #if (NGX_HTTP_CACHE) - - if (conf->params_source == NULL) { + ngx_array_t params_merged; +#endif + ngx_keyval_t *src; + ngx_hash_key_t *hk; + ngx_hash_init_t hash; + ngx_http_script_compile_t sc; + ngx_http_script_copy_code_t *copy; - if ((conf->upstream.cache == NULL) - == (prev->upstream.cache == NULL)) - { - return NGX_CONF_OK; - } + if (conf->params_source == NULL) { + conf->params_source = prev->params_source; - /* 6 is a number of ngx_http_scgi_cache_headers entries */ - conf->params_source = ngx_array_create(cf->pool, 6, - sizeof(ngx_keyval_t)); - if (conf->params_source == NULL) { - return NGX_CONF_ERROR; - } + if (prev->headers_hash.buckets +#if (NGX_HTTP_CACHE) + && ((conf->upstream.cache == NULL) == (prev->upstream.cache == NULL)) +#endif + ) + { + conf->flushes = prev->flushes; + conf->params_len = prev->params_len; + conf->params = prev->params; + conf->headers_hash = prev->headers_hash; + conf->header_params = prev->header_params; + + return NGX_OK; } -#else + } - if (conf->params_source == NULL) { - return NGX_CONF_OK; - } - + if (conf->params_source == NULL +#if (NGX_HTTP_CACHE) + && (conf->upstream.cache == NULL) #endif + ) + { + conf->headers_hash.buckets = (void *) 1; + return NGX_OK; } conf->params_len = ngx_array_create(cf->pool, 64, 1); if (conf->params_len == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } conf->params = ngx_array_create(cf->pool, 512, 1); if (conf->params == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t)) != NGX_OK) { - return NGX_CONF_ERROR; + return NGX_ERROR; } - src = conf->params_source->elts; + if (conf->params_source) { + src = conf->params_source->elts; + nsrc = conf->params_source->nelts; + + } else { + src = NULL; + nsrc = 0; + } #if (NGX_HTTP_CACHE) if (conf->upstream.cache) { ngx_keyval_t *h, *s; - for (h = ngx_http_scgi_cache_headers; h->key.len; h++) { + if (ngx_array_init(¶ms_merged, cf->temp_pool, 4, sizeof(ngx_keyval_t)) + != NGX_OK) + { + return NGX_ERROR; + } + + for (i = 0; i < nsrc; i++) { - for (i = 0; i < conf->params_source->nelts; i++) { + s = ngx_array_push(¶ms_merged); + if (s == NULL) { + return NGX_ERROR; + } + + *s = src[i]; + } + + h = ngx_http_scgi_cache_headers; + + while (h->key.len) { + + src = params_merged.elts; + nsrc = params_merged.nelts; + + for (i = 0; i < nsrc; i++) { if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) { goto next; } } - s = ngx_array_push(conf->params_source); + s = ngx_array_push(¶ms_merged); if (s == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } *s = *h; - src = conf->params_source->elts; - next: h++; } + + src = params_merged.elts; + nsrc = params_merged.nelts; } #endif - for (i = 0; i < conf->params_source->nelts; i++) { + for (i = 0; i < nsrc; i++) { if (src[i].key.len > sizeof("HTTP_") - 1 && ngx_strncmp(src[i].key.data, "HTTP_", sizeof("HTTP_") - 1) == 0) { hk = ngx_array_push(&headers_names); if (hk == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } hk->key.len = src[i].key.len - 5; @@ -1411,7 +1456,7 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t copy = ngx_array_push_n(conf->params_len, sizeof(ngx_http_script_copy_code_t)); if (copy == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code; @@ -1424,7 +1469,7 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t copy = ngx_array_push_n(conf->params, size); if (copy == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } copy->code = ngx_http_script_copy_code; @@ -1443,12 +1488,12 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t sc.values = &conf->params; if (ngx_http_script_compile(&sc) != NGX_OK) { - return NGX_CONF_ERROR; + return NGX_ERROR; } code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t)); if (code == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } *code = (uintptr_t) NULL; @@ -1456,7 +1501,7 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t code = ngx_array_push_n(conf->params, sizeof(uintptr_t)); if (code == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } *code = (uintptr_t) NULL; @@ -1464,14 +1509,14 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t)); if (code == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } *code = (uintptr_t) NULL; code = ngx_array_push_n(conf->params, sizeof(uintptr_t)); if (code == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } *code = (uintptr_t) NULL; @@ -1486,12 +1531,7 @@ ngx_http_scgi_merge_loc_conf(ngx_conf_t hash.pool = cf->pool; hash.temp_pool = NULL; - if (ngx_hash_init(&hash, headers_names.elts, headers_names.nelts) != NGX_OK) - { - return NGX_CONF_ERROR; - } - - return NGX_CONF_OK; + return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts); } diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -139,14 +139,14 @@ static ngx_command_t ngx_http_ssi_filte NULL }, { ngx_string("ssi_min_file_chunk"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + 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_ssi_loc_conf_t, min_file_chunk), NULL }, { ngx_string("ssi_value_length"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + 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_ssi_loc_conf_t, value_len), diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -101,7 +101,7 @@ static ngx_command_t ngx_http_ssl_comma NULL }, { ngx_string("ssl_verify_client"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_enum_slot, NGX_HTTP_SRV_CONF_OFFSET, offsetof(ngx_http_ssl_srv_conf_t, verify), diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -50,6 +50,8 @@ static void ngx_http_uwsgi_finalize_requ static void *ngx_http_uwsgi_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_uwsgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child); +static ngx_int_t ngx_http_uwsgi_merge_params(ngx_conf_t *cf, + ngx_http_uwsgi_loc_conf_t *conf, ngx_http_uwsgi_loc_conf_t *prev); static char *ngx_http_uwsgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -1112,17 +1114,9 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t ngx_http_uwsgi_loc_conf_t *prev = parent; ngx_http_uwsgi_loc_conf_t *conf = child; - u_char *p; size_t size; - uintptr_t *code; - ngx_uint_t i; - ngx_array_t headers_names; - ngx_keyval_t *src; - ngx_hash_key_t *hk; ngx_hash_init_t hash; ngx_http_core_loc_conf_t *clcf; - ngx_http_script_compile_t sc; - ngx_http_script_copy_code_t *copy; if (conf->upstream.store != 0) { ngx_conf_merge_value(conf->upstream.store, prev->upstream.store, 0); @@ -1365,95 +1359,146 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t ngx_conf_merge_uint_value(conf->modifier1, prev->modifier1, 0); ngx_conf_merge_uint_value(conf->modifier2, prev->modifier2, 0); - if (conf->params_source == NULL) { - conf->flushes = prev->flushes; - conf->params_len = prev->params_len; - conf->params = prev->params; - conf->params_source = prev->params_source; - conf->headers_hash = prev->headers_hash; + if (ngx_http_uwsgi_merge_params(cf, conf, prev) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + +static ngx_int_t +ngx_http_uwsgi_merge_params(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *conf, + ngx_http_uwsgi_loc_conf_t *prev) +{ + u_char *p; + size_t size; + uintptr_t *code; + ngx_uint_t i, nsrc; + ngx_array_t headers_names; #if (NGX_HTTP_CACHE) - - if (conf->params_source == NULL) { + ngx_array_t params_merged; +#endif + ngx_keyval_t *src; + ngx_hash_key_t *hk; + ngx_hash_init_t hash; + ngx_http_script_compile_t sc; + ngx_http_script_copy_code_t *copy; - if ((conf->upstream.cache == NULL) - == (prev->upstream.cache == NULL)) - { - return NGX_CONF_OK; - } + if (conf->params_source == NULL) { + conf->params_source = prev->params_source; - /* 6 is a number of ngx_http_uwsgi_cache_headers entries */ - conf->params_source = ngx_array_create(cf->pool, 6, - sizeof(ngx_keyval_t)); - if (conf->params_source == NULL) { - return NGX_CONF_ERROR; - } + if (prev->headers_hash.buckets +#if (NGX_HTTP_CACHE) + && ((conf->upstream.cache == NULL) == (prev->upstream.cache == NULL)) +#endif + ) + { + conf->flushes = prev->flushes; + conf->params_len = prev->params_len; + conf->params = prev->params; + conf->headers_hash = prev->headers_hash; + conf->header_params = prev->header_params; + + return NGX_OK; } -#else + } - if (conf->params_source == NULL) { - return NGX_CONF_OK; - } - + if (conf->params_source == NULL +#if (NGX_HTTP_CACHE) + && (conf->upstream.cache == NULL) #endif + ) + { + conf->headers_hash.buckets = (void *) 1; + return NGX_OK; } conf->params_len = ngx_array_create(cf->pool, 64, 1); if (conf->params_len == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } conf->params = ngx_array_create(cf->pool, 512, 1); if (conf->params == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } if (ngx_array_init(&headers_names, cf->temp_pool, 4, sizeof(ngx_hash_key_t)) != NGX_OK) { - return NGX_CONF_ERROR; + return NGX_ERROR; } - src = conf->params_source->elts; + if (conf->params_source) { + src = conf->params_source->elts; + nsrc = conf->params_source->nelts; + + } else { + src = NULL; + nsrc = 0; + } #if (NGX_HTTP_CACHE) if (conf->upstream.cache) { ngx_keyval_t *h, *s; - for (h = ngx_http_uwsgi_cache_headers; h->key.len; h++) { + if (ngx_array_init(¶ms_merged, cf->temp_pool, 4, sizeof(ngx_keyval_t)) + != NGX_OK) + { + return NGX_ERROR; + } + + for (i = 0; i < nsrc; i++) { - for (i = 0; i < conf->params_source->nelts; i++) { + s = ngx_array_push(¶ms_merged); + if (s == NULL) { + return NGX_ERROR; + } + + *s = src[i]; + } + + h = ngx_http_uwsgi_cache_headers; + + while (h->key.len) { + + src = params_merged.elts; + nsrc = params_merged.nelts; + + for (i = 0; i < nsrc; i++) { if (ngx_strcasecmp(h->key.data, src[i].key.data) == 0) { goto next; } } - s = ngx_array_push(conf->params_source); + s = ngx_array_push(¶ms_merged); if (s == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } *s = *h; - src = conf->params_source->elts; - next: h++; } + + src = params_merged.elts; + nsrc = params_merged.nelts; } #endif - for (i = 0; i < conf->params_source->nelts; i++) { + for (i = 0; i < nsrc; i++) { if (src[i].key.len > sizeof("HTTP_") - 1 && ngx_strncmp(src[i].key.data, "HTTP_", sizeof("HTTP_") - 1) == 0) { hk = ngx_array_push(&headers_names); if (hk == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } hk->key.len = src[i].key.len - 5; @@ -1469,7 +1514,7 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t copy = ngx_array_push_n(conf->params_len, sizeof(ngx_http_script_copy_code_t)); if (copy == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code; @@ -1482,7 +1527,7 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t copy = ngx_array_push_n(conf->params, size); if (copy == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } copy->code = ngx_http_script_copy_code; @@ -1501,12 +1546,12 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t sc.values = &conf->params; if (ngx_http_script_compile(&sc) != NGX_OK) { - return NGX_CONF_ERROR; + return NGX_ERROR; } code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t)); if (code == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } *code = (uintptr_t) NULL; @@ -1514,7 +1559,7 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t code = ngx_array_push_n(conf->params, sizeof(uintptr_t)); if (code == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } *code = (uintptr_t) NULL; @@ -1522,7 +1567,7 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t code = ngx_array_push_n(conf->params_len, sizeof(uintptr_t)); if (code == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } *code = (uintptr_t) NULL; @@ -1537,12 +1582,7 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t hash.pool = cf->pool; hash.temp_pool = NULL; - if (ngx_hash_init(&hash, headers_names.elts, headers_names.nelts) != NGX_OK) - { - return NGX_CONF_ERROR; - } - - return NGX_CONF_OK; + return ngx_hash_init(&hash, headers_names.elts, headers_names.nelts); } 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 @@ -48,7 +48,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '1.1.7'; +our $VERSION = '1.1.8'; 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 @@ -143,7 +143,7 @@ static ngx_conf_enum_t ngx_http_core_if }; -static ngx_conf_enum_t ngx_http_core_keepalive_disable[] = { +static ngx_conf_bitmask_t ngx_http_core_keepalive_disable[] = { { ngx_string("none"), NGX_HTTP_KEEPALIVE_DISABLE_NONE }, { ngx_string("msie6"), NGX_HTTP_KEEPALIVE_DISABLE_MSIE6 }, { ngx_string("safari"), NGX_HTTP_KEEPALIVE_DISABLE_SAFARI }, @@ -513,8 +513,8 @@ static ngx_command_t ngx_http_core_comm NULL }, { ngx_string("keepalive_disable"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_enum_slot, + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, + ngx_conf_set_bitmask_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_core_loc_conf_t, keepalive_disable), &ngx_http_core_keepalive_disable }, @@ -3475,9 +3475,11 @@ ngx_http_core_merge_loc_conf(ngx_conf_t ngx_conf_merge_msec_value(conf->client_body_timeout, prev->client_body_timeout, 60000); - ngx_conf_merge_uint_value(conf->keepalive_disable, prev->keepalive_disable, - NGX_HTTP_KEEPALIVE_DISABLE_MSIE6 - |NGX_HTTP_KEEPALIVE_DISABLE_SAFARI); + ngx_conf_merge_bitmask_value(conf->keepalive_disable, + prev->keepalive_disable, + (NGX_CONF_BITMASK_SET + |NGX_HTTP_KEEPALIVE_DISABLE_MSIE6 + |NGX_HTTP_KEEPALIVE_DISABLE_SAFARI)); ngx_conf_merge_uint_value(conf->satisfy, prev->satisfy, NGX_HTTP_SATISFY_ALL); ngx_conf_merge_uint_value(conf->if_modified_since, prev->if_modified_since, @@ -4398,7 +4400,7 @@ ngx_http_core_open_file_cache(ngx_conf_t if (ngx_strncmp(value[i].data, "max=", 4) == 0) { max = ngx_atoi(value[i].data + 4, value[i].len - 4); - if (max == NGX_ERROR) { + if (max <= 0) { goto failed; } diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -480,7 +480,7 @@ struct ngx_http_request_s { * ngx_http_limit_zone_module and ngx_http_limit_req_module * we use the single bits in the request structure */ - unsigned limit_zone_set:1; + unsigned limit_conn_set:1; unsigned limit_req_set:1; #if 0 diff --git a/src/mail/ngx_mail_proxy_module.c b/src/mail/ngx_mail_proxy_module.c --- a/src/mail/ngx_mail_proxy_module.c +++ b/src/mail/ngx_mail_proxy_module.c @@ -60,7 +60,7 @@ static ngx_command_t ngx_mail_proxy_com NULL }, { ngx_string("proxy_pass_error_message"), - NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, NGX_MAIL_SRV_CONF_OFFSET, offsetof(ngx_mail_proxy_conf_t, pass_error_message), diff --git a/src/os/unix/ngx_files.h b/src/os/unix/ngx_files.h --- a/src/os/unix/ngx_files.h +++ b/src/os/unix/ngx_files.h @@ -128,6 +128,7 @@ ngx_write_fd(ngx_fd_t fd, void *buf, siz #define ngx_linefeed(p) *p++ = LF; #define NGX_LINEFEED_SIZE 1 +#define NGX_LINEFEED "\x0a" #define ngx_rename_file(o, n) rename((const char *) o, (const char *) n)