# HG changeset patch # User Igor Sysoev # Date 1256504400 -10800 # Node ID 89dc5654117ceb3ff7dab94469669e4cc22fcf5b # Parent dc87c92181c74099fad8545e93297394296109ad nginx 0.7.63 *) Security: now "/../" are disabled in "Destination" request header line. *) Change: minimum supported OpenSSL version is 0.9.7. *) Change: the "ask" parameter of the "ssl_verify_client" directive was changed to the "optional" parameter and now it checks a client certificate if it was offered. Thanks to Brice Figureau. *) Feature: now the "-V" switch shows TLS SNI support. *) Feature: the $ssl_client_verify variable. Thanks to Brice Figureau. *) Feature: the "ssl_crl" directive. Thanks to Brice Figureau. *) Bugfix: the $ssl_client_cert variable usage corrupted memory; the bug had appeared in 0.7.7. Thanks to Sergey Zhuravlev. *) Feature: now the start cache loader runs in a separate process; this should improve large caches handling. *) Feature: now temporary files and permanent storage area may reside at different file systems. *) Bugfix: nginx counted incorrectly disk cache size. *) Change: now directive "gzip_disable msie6" does not disable gzipping for MSIE 6.0 SV1. *) Bugfix: nginx always added "Vary: Accept-Encoding" response header line, if both "gzip_static" and "gzip_vary" were on. *) Feature: the "proxy" parameter of the "geo" directive. *) Feature: the ngx_http_geoip_module. *) Feature: the "limit_rate_after" directive. Thanks to Ivan Debnar. *) Feature: the "limit_req_log_level" and "limit_conn_log_level" directives. *) Bugfix: now "limit_req" directive conforms to the leaky bucket algorithm. Thanks to Maxim Dounin. *) Bugfix: in ngx_http_limit_req_module. Thanks to Maxim Dounin. *) Bugfix: now nginx allows underscores in a request method. *) Bugfix: "proxy_pass_header" and "fastcgi_pass_header" directives did not pass to a client the "X-Accel-Redirect", "X-Accel-Limit-Rate", "X-Accel-Buffering", and "X-Accel-Charset" lines from backend response header. Thanks to Maxim Dounin. *) Bugfix: in handling "Last-Modified" and "Accept-Ranges" backend response header lines; the bug had appeared in 0.7.44. Thanks to Maxim Dounin. *) Feature: the "image_filter_transparency" directive. *) Feature: the "image_filter" directive supports variables for setting size. *) Bugfix: in PNG alpha-channel support in the ngx_http_image_filter_module. *) Bugfix: in transparency support in the ngx_http_image_filter_module. *) Feature: now several "perl_modules" directives may be used. *) Bugfix: ngx_http_perl_module responses did not work in subrequests. *) Bugfix: nginx sent '\0' in a "Location" response header line on MKCOL request. Thanks to Xie Zhenye. *) Bugfix: an "error_page" directive did not redirect a 413 error; the bug had appeared in 0.6.10. *) Bugfix: in memory allocation error handling. Thanks to Maxim Dounin and Kirill A. Korinskiy. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,96 @@ +Changes with nginx 0.7.63 26 Oct 2009 + + *) Security: now "/../" are disabled in "Destination" request header + line. + + *) Change: minimum supported OpenSSL version is 0.9.7. + + *) Change: the "ask" parameter of the "ssl_verify_client" directive was + changed to the "optional" parameter and now it checks a client + certificate if it was offered. + Thanks to Brice Figureau. + + *) Feature: now the "-V" switch shows TLS SNI support. + + *) Feature: the $ssl_client_verify variable. + Thanks to Brice Figureau. + + *) Feature: the "ssl_crl" directive. + Thanks to Brice Figureau. + + *) Bugfix: the $ssl_client_cert variable usage corrupted memory; the + bug had appeared in 0.7.7. + Thanks to Sergey Zhuravlev. + + *) Feature: now the start cache loader runs in a separate process; this + should improve large caches handling. + + *) Feature: now temporary files and permanent storage area may reside + at different file systems. + + *) Bugfix: nginx counted incorrectly disk cache size. + + *) Change: now directive "gzip_disable msie6" does not disable gzipping + for MSIE 6.0 SV1. + + *) Bugfix: nginx always added "Vary: Accept-Encoding" response header + line, if both "gzip_static" and "gzip_vary" were on. + + *) Feature: the "proxy" parameter of the "geo" directive. + + *) Feature: the ngx_http_geoip_module. + + *) Feature: the "limit_rate_after" directive. + Thanks to Ivan Debnar. + + *) Feature: the "limit_req_log_level" and "limit_conn_log_level" + directives. + + *) Bugfix: now "limit_req" directive conforms to the leaky bucket + algorithm. + Thanks to Maxim Dounin. + + *) Bugfix: in ngx_http_limit_req_module. + Thanks to Maxim Dounin. + + *) Bugfix: now nginx allows underscores in a request method. + + *) Bugfix: "proxy_pass_header" and "fastcgi_pass_header" directives did + not pass to a client the "X-Accel-Redirect", "X-Accel-Limit-Rate", + "X-Accel-Buffering", and "X-Accel-Charset" lines from backend + response header. + Thanks to Maxim Dounin. + + *) Bugfix: in handling "Last-Modified" and "Accept-Ranges" backend + response header lines; the bug had appeared in 0.7.44. + Thanks to Maxim Dounin. + + *) Feature: the "image_filter_transparency" directive. + + *) Feature: the "image_filter" directive supports variables for setting + size. + + *) Bugfix: in PNG alpha-channel support in the + ngx_http_image_filter_module. + + *) Bugfix: in transparency support in the ngx_http_image_filter_module. + + *) Feature: now several "perl_modules" directives may be used. + + *) Bugfix: ngx_http_perl_module responses did not work in subrequests. + + *) Bugfix: nginx sent '\0' in a "Location" response header line on + MKCOL request. + Thanks to Xie Zhenye. + + *) Bugfix: an "error_page" directive did not redirect a 413 error; the + bug had appeared in 0.6.10. + + *) Bugfix: in memory allocation error handling. + Thanks to Maxim Dounin and Kirill A. Korinskiy. + + Changes with nginx 0.7.62 14 Sep 2009 *) Security: a segmentation fault might occur in worker process while diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,99 @@ +Изменения в nginx 0.7.63 26.10.2009 + + *) Безопасность: теперь символы "/../" запрещены в строке "Destination" + в заголовке запроса. + + *) Изменение: минимальная поддерживаемая версия OpenSSL - 0.9.7. + + *) Изменение: параметр ask директивы ssl_verify_client изменён на + параметр optional и теперь он проверяет клиентский сертификат, если + он был предложен. + Спасибо Brice Figureau. + + *) Добавление: теперь ключ -V показывает статус поддержки TLS SNI. + + *) Добавление: переменная $ssl_client_verify. + Спасибо Brice Figureau. + + *) Добавление: директива ssl_crl. + Спасибо Brice Figureau. + + *) Исправление: использование переменной $ssl_client_cert портило + память; ошибка появилась в 0.7.7. + Спасибо Сергею Журавлёву. + + *) Добавление: теперь стартовый загрузчик кэша работает в отдельном + процесс; это должно улучшить обработку больших кэшей. + + *) Добавление: теперь временные файлы и постоянное место хранения могут + располагаться на разных файловых системах. + + *) Исправление: nginx неверно считал размер кэша на диске. + + *) Изменение: теперь директива "gzip_disable msie6" не запрещает сжатие + для MSIE 6.0 SV1. + + *) Исправление: nginx всегда добавлял строку "Vary: Accept-Encoding" в + заголовок ответа, если обе директивы gzip_static и gzip_vary были + включены. + + *) Добавление: параметр proxy директивы geo. + + *) Добавление: модуль ngx_http_geoip_module. + + *) Добавление: директива limit_rate_after. + Спасибо Ivan Debnar. + + *) Добавление: директивы limit_req_log_level и limit_conn_log_level. + + *) Исправление: Теперь директива limit_req соответствует алгоритму + leaky bucket. + Спасибо Максиму Дунину. + + *) Исправление: в модуле ngx_http_limit_req_module. + Спасибо Максиму Дунину. + + *) Исправление: теперь nginx разрешает подчёркивания в методе запроса. + + *) Исправление: директивы proxy_pass_header и fastcgi_pass_header" не + передавали клиенту строки "X-Accel-Redirect", "X-Accel-Limit-Rate", + "X-Accel-Buffering" и "X-Accel-Charset" из заголовка ответа + бэкенда. + Спасибо Максиму Дунину. + + *) Исправление: в обработке строк "Last-Modified" и "Accept-Ranges" в + заголовке ответа бэкенда; ошибка появилась в 0.7.44 + Спасибо Максиму Дунину. + + *) Добавление: директива image_filter_transparency. + + *) Добавление: директива image_filter поддерживает переменные для + задания размеров. + + *) Исправление: в поддержке альфа-канала PNG в модуле + ngx_http_image_filter_module. + + *) Исправление: в поддержке прозрачности в модуле + ngx_http_image_filter_module. + + *) Добавление: теперь можно использовать несколько директив + perl_modules. + + *) Исправление: ответы модуля ngx_http_perl_module не работали в + подзапросах. + + *) Исправление: nginx слал символ '\0' в строке "Location" в заголовке + в ответе на запрос MKCOL. + Спасибо Xie Zhenye. + + *) Исправление: директива error_page не перенаправляла ошибку 413; + ошибка появилась в 0.6.10. + + *) Исправление: в обработке ошибок выделения памяти. + Спасибо Максиму Дунину и Кириллу Коринскому. + + Изменения в nginx 0.7.62 14.09.2009 *) Безопасность: при обработке специально созданного запроса в рабочем diff --git a/auto/lib/conf b/auto/lib/conf --- a/auto/lib/conf +++ b/auto/lib/conf @@ -67,6 +67,9 @@ if [ $USE_PERL = YES ]; then . auto/lib/perl/conf fi +if [ $HTTP_GEOIP = YES ]; then + . auto/lib/geoip/conf +fi if [ $NGX_GOOGLE_PERFTOOLS = YES ]; then . auto/lib/google-perftools/conf fi diff --git a/auto/lib/geoip/conf b/auto/lib/geoip/conf new file mode 100644 --- /dev/null +++ b/auto/lib/geoip/conf @@ -0,0 +1,78 @@ + +# Copyright (C) Igor Sysoev + + + ngx_feature="GeoIP library" + ngx_feature_name= + ngx_feature_run=no + ngx_feature_incs= + ngx_feature_path= + ngx_feature_libs="-lGeoIP" + ngx_feature_test="GeoIP_open(NULL, 0)" + . auto/feature + + +if [ $ngx_found = no ]; then + + # FreeBSD port + + ngx_feature="GeoIP library in /usr/local/" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -lGeoIP" + else + ngx_feature_libs="-L/usr/local/lib -lGeoIP" + fi + + . auto/feature +fi + + +if [ $ngx_found = no ]; then + + # NetBSD port + + ngx_feature="GeoIP library in /usr/pkg/" + ngx_feature_path="/usr/pkg/include/" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/usr/pkg/lib -L/usr/pkg/lib -lGeoIP" + else + ngx_feature_libs="-L/usr/pkg/lib -lGeoIP" + fi + + . auto/feature +fi + + +if [ $ngx_found = no ]; then + + # MacPorts + + ngx_feature="GeoIP library in /opt/local/" + ngx_feature_path="/opt/local/include" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/opt/local/lib -L/opt/local/lib -lGeoIP" + else + ngx_feature_libs="-L/opt/local/lib -lGeoIP" + fi + + . auto/feature +fi + + +if [ $ngx_found = yes ]; then + CORE_LIBS="$CORE_LIBS $ngx_feature_libs" + +else + +cat << END + +$0: error: the GeoIP module requires the GeoIP library. +You can either do not enable the module or install the library. + +END + + exit 1 +fi diff --git a/auto/modules b/auto/modules --- a/auto/modules +++ b/auto/modules @@ -240,6 +240,12 @@ if [ $HTTP_GEO = YES ]; then HTTP_SRCS="$HTTP_SRCS $HTTP_GEO_SRCS" fi +if [ $HTTP_GEOIP = YES ]; then + have=NGX_HTTP_GEOIP . auto/have + HTTP_MODULES="$HTTP_MODULES $HTTP_GEOIP_MODULE" + HTTP_SRCS="$HTTP_SRCS $HTTP_GEOIP_SRCS" +fi + if [ $HTTP_MAP = YES ]; then have=NGX_HTTP_MAP . auto/have HTTP_MODULES="$HTTP_MODULES $HTTP_MAP_MODULE" diff --git a/auto/options b/auto/options --- a/auto/options +++ b/auto/options @@ -71,6 +71,7 @@ HTTP_AUTOINDEX=YES HTTP_RANDOM_INDEX=NO HTTP_STATUS=NO HTTP_GEO=YES +HTTP_GEOIP=NO HTTP_MAP=YES HTTP_REFERER=YES HTTP_REWRITE=YES @@ -184,6 +185,7 @@ do --with-http_addition_module) HTTP_ADDITION=YES ;; --with-http_xslt_module) HTTP_XSLT=YES ;; --with-http_image_filter_module) HTTP_IMAGE_FILTER=YES ;; + --with-http_geoip_module) HTTP_GEOIP=YES ;; --with-http_sub_module) HTTP_SUB=YES ;; --with-http_dav_module) HTTP_DAV=YES ;; --with-http_flv_module) HTTP_FLV=YES ;; @@ -310,6 +312,7 @@ cat << END --with-http_addition_module enable ngx_http_addition_module --with-http_xslt_module enable ngx_http_xslt_module --with-http_image_filter_module enable ngx_http_image_filter_module + --with-http_geoip_module enable ngx_http_geoip_module --with-http_sub_module enable ngx_http_sub_module --with-http_dav_module enable ngx_http_dav_module --with-http_flv_module enable ngx_http_flv_module diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -377,6 +377,10 @@ HTTP_GEO_MODULE=ngx_http_geo_module HTTP_GEO_SRCS=src/http/modules/ngx_http_geo_module.c +HTTP_GEOIP_MODULE=ngx_http_geoip_module +HTTP_GEOIP_SRCS=src/http/modules/ngx_http_geoip_module.c + + HTTP_MAP_MODULE=ngx_http_map_module HTTP_MAP_SRCS=src/http/modules/ngx_http_map_module.c diff --git a/src/core/nginx.c b/src/core/nginx.c --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -239,6 +239,13 @@ main(int argc, char *const *argv) #ifdef NGX_COMPILER ngx_log_stderr(0, "built by " NGX_COMPILER); #endif +#if (NGX_SSL) +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + ngx_log_stderr(0, "TLS SNI support enabled"); +#else + ngx_log_stderr(0, "TLS SNI support disabled"); +#endif +#endif ngx_log_stderr(0, "configure arguments:" NGX_CONFIGURE); } 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 7062 -#define NGINX_VERSION "0.7.62" +#define nginx_version 7063 +#define NGINX_VERSION "0.7.63" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c --- a/src/core/ngx_cycle.c +++ b/src/core/ngx_cycle.c @@ -216,7 +216,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) if (module->create_conf) { rv = module->create_conf(cycle); - if (rv == NGX_CONF_ERROR) { + if (rv == NULL) { ngx_destroy_pool(pool); return NULL; } @@ -255,11 +255,13 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) #endif if (ngx_conf_param(&conf) != NGX_CONF_OK) { + environ = senv; ngx_destroy_cycle_pools(&conf); return NULL; } if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) { + environ = senv; ngx_destroy_cycle_pools(&conf); return NULL; } @@ -280,6 +282,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) if (module->init_conf(cycle, cycle->conf_ctx[ngx_modules[i]->index]) == NGX_CONF_ERROR) { + environ = senv; ngx_destroy_cycle_pools(&conf); return NULL; } @@ -698,8 +701,8 @@ old_shm_zone_done: if (ngx_process == NGX_PROCESS_MASTER || ngx_is_init_cycle(old_cycle)) { /* - * perl_destruct() frees environ if it is not the same as it was at - * perl_construct() time. So we have saved an previous cycle + * perl_destruct() frees environ, if it is not the same as it was at + * perl_construct() time, therefore we save the previous cycle * environment before ngx_conf_parse() where it will be changed. */ diff --git a/src/core/ngx_file.c b/src/core/ngx_file.c --- a/src/core/ngx_file.c +++ b/src/core/ngx_file.c @@ -8,8 +8,9 @@ #include -static ngx_atomic_uint_t ngx_temp_number; -static ngx_atomic_uint_t ngx_random_number; +static ngx_atomic_t temp_number = 0; +ngx_atomic_t *ngx_temp_number = &temp_number; +ngx_atomic_int_t ngx_random_number = 123456; ssize_t @@ -99,13 +100,7 @@ ngx_create_temp_file(ngx_file_t *file, n continue; } - if ((path->level[0] == 0) - || (err != NGX_ENOENT -#if (NGX_WIN32) - && err != NGX_ENOTDIR -#endif - )) - { + if ((path->level[0] == 0) || (err != NGX_ENOPATH)) { ngx_log_error(NGX_LOG_CRIT, file->log, err, ngx_open_tempfile_n " \"%s\" failed", file->name.data); @@ -211,22 +206,16 @@ ngx_create_full_path(u_char *dir, ngx_ui } -void -ngx_init_temp_number(void) -{ - ngx_temp_number = 0; - ngx_random_number = 123456; -} - - ngx_atomic_uint_t ngx_next_temp_number(ngx_uint_t collision) { - if (collision) { - ngx_temp_number += ngx_random_number; - } + ngx_atomic_uint_t n, add; + + add = collision ? ngx_random_number : 1; - return ngx_temp_number++; + n = ngx_atomic_fetch_add(ngx_temp_number, add); + + return n + add; } @@ -264,7 +253,8 @@ ngx_conf_set_path_slot(ngx_conf_t *cf, n } path->len = 0; - path->manager = (ngx_path_manager_pt) cmd->post; + path->manager = NULL; + path->loader = NULL; path->conf_file = cf->conf_file->file.name.data; path->line = cf->conf_file->line; @@ -325,6 +315,7 @@ ngx_conf_merge_path_value(ngx_conf_t *cf + init->level[2] + (init->level[2] ? 1 : 0); (*path)->manager = NULL; + (*path)->loader = NULL; (*path)->conf_file = NULL; if (ngx_add_path(cf, path) != NGX_OK) { @@ -528,7 +519,9 @@ ngx_create_pathes(ngx_cycle_t *cycle, ng ngx_int_t ngx_ext_rename_file(ngx_str_t *src, ngx_str_t *to, ngx_ext_rename_file_t *ext) { - ngx_err_t err; + u_char *name; + ngx_err_t err; + ngx_copy_file_t cf; #if !(NGX_WIN32) @@ -558,14 +551,8 @@ ngx_ext_rename_file(ngx_str_t *src, ngx_ err = ngx_errno; - if (err -#if (NGX_WIN32) - == ERROR_PATH_NOT_FOUND -#else - == NGX_ENOENT -#endif - ) - { + if (err == NGX_ENOPATH) { + if (!ext->create_path) { goto failed; } @@ -584,7 +571,6 @@ ngx_ext_rename_file(ngx_str_t *src, ngx_ } err = ngx_errno; - goto failed; } #if (NGX_WIN32) @@ -605,6 +591,53 @@ ngx_ext_rename_file(ngx_str_t *src, ngx_ #endif + if (err == NGX_EXDEV) { + + cf.size = -1; + cf.buf_size = 0; + cf.access = ext->access; + cf.time = ext->time; + cf.log = ext->log; + + name = ngx_alloc(to->len + 1 + 10 + 1, ext->log); + if (name == NULL) { + return NGX_ERROR; + } + + (void) ngx_sprintf(name, "%*s.%010uD%Z", to->len, to->data, + (uint32_t) ngx_next_temp_number(0)); + + if (ngx_copy_file(src->data, name, &cf) == NGX_OK) { + + if (ngx_rename_file(name, to->data) != NGX_FILE_ERROR) { + ngx_free(name); + + if (ngx_delete_file(src->data) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno, + ngx_delete_file_n " \"%s\" failed", + src->data); + return NGX_ERROR; + } + + return NGX_OK; + } + + ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno, + ngx_rename_file_n " \"%s\" to \"%s\" failed", + name, to->data); + + if (ngx_delete_file(name) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_CRIT, ext->log, ngx_errno, + ngx_delete_file_n " \"%s\" failed", name); + + } + } + + ngx_free(name); + + err = 0; + } + failed: if (ext->delete_file) { @@ -614,15 +647,141 @@ failed: } } - if (err && ext->log_rename_error) { + if (err) { ngx_log_error(NGX_LOG_CRIT, ext->log, err, ngx_rename_file_n " \"%s\" to \"%s\" failed", src->data, to->data); } - ext->rename_error = err; + return NGX_ERROR; +} + + +ngx_int_t +ngx_copy_file(u_char *from, u_char *to, ngx_copy_file_t *cf) +{ + char *buf; + off_t size; + size_t len; + ssize_t n; + ngx_fd_t fd, nfd; + ngx_int_t rc; + ngx_file_info_t fi; + + rc = NGX_ERROR; + buf = NULL; + nfd = NGX_INVALID_FILE; + + fd = ngx_open_file(from, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); + + if (fd == NGX_INVALID_FILE) { + ngx_log_error(NGX_LOG_CRIT, cf->log, ngx_errno, + ngx_open_file_n " \"%s\" failed", from); + goto failed; + } + + if (cf->size != -1) { + size = cf->size; + + } else { + if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_fd_info_n " \"%s\" failed", from); + + goto failed; + } + + size = ngx_file_size(&fi); + } + + len = cf->buf_size ? cf->buf_size : 65536; + + if ((off_t) len > size) { + len = (size_t) size; + } + + buf = ngx_alloc(len, cf->log); + if (buf == NULL) { + goto failed; + } + + nfd = ngx_open_file(to, NGX_FILE_WRONLY, NGX_FILE_CREATE_OR_OPEN, + cf->access); + + if (nfd == NGX_INVALID_FILE) { + ngx_log_error(NGX_LOG_CRIT, cf->log, ngx_errno, + ngx_open_file_n " \"%s\" failed", to); + goto failed; + } + + while (size > 0) { - return NGX_ERROR; + if ((off_t) len > size) { + len = (size_t) size; + } + + n = ngx_read_fd(fd, buf, len); + + if (n == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_read_fd_n " \"%s\" failed", from); + goto failed; + } + + if ((size_t) n != len) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_read_fd_n " has read only %z of %uz from %s", + n, size, from); + goto failed; + } + + n = ngx_write_fd(nfd, buf, len); + + if (n == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_write_fd_n " \"%s\" failed", to); + goto failed; + } + + if ((size_t) n != len) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_write_fd_n " has written only %z of %uz to %s", + n, size, to); + goto failed; + } + + size -= n; + } + + if (ngx_set_file_time(to, nfd, cf->time) != NGX_OK) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_set_file_time_n " \"%s\" failed", to); + goto failed; + } + + rc = NGX_OK; + +failed: + + if (nfd != NGX_INVALID_FILE) { + if (ngx_close_file(nfd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", to); + } + } + + if (fd != NGX_INVALID_FILE) { + if (ngx_close_file(fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", from); + } + } + + if (buf) { + ngx_free(buf); + } + + return rc; } diff --git a/src/core/ngx_file.h b/src/core/ngx_file.h --- a/src/core/ngx_file.h +++ b/src/core/ngx_file.h @@ -30,6 +30,7 @@ struct ngx_file_s { typedef time_t (*ngx_path_manager_pt) (void *data); +typedef void (*ngx_path_loader_pt) (void *data); typedef struct { @@ -38,6 +39,7 @@ typedef struct { size_t level[3]; ngx_path_manager_pt manager; + ngx_path_loader_pt loader; void *data; u_char *conf_file; @@ -71,16 +73,25 @@ typedef struct { ngx_uint_t path_access; time_t time; ngx_fd_t fd; - ngx_err_t rename_error; unsigned create_path:1; unsigned delete_file:1; - unsigned log_rename_error:1; ngx_log_t *log; } ngx_ext_rename_file_t; +typedef struct { + off_t size; + size_t buf_size; + + ngx_uint_t access; + time_t time; + + ngx_log_t *log; +} ngx_copy_file_t; + + typedef struct ngx_tree_ctx_s ngx_tree_ctx_t; typedef ngx_int_t (*ngx_tree_init_handler_pt) (void *ctx, void *prev); @@ -115,9 +126,9 @@ ngx_int_t ngx_add_path(ngx_conf_t *cf, n ngx_int_t ngx_create_pathes(ngx_cycle_t *cycle, ngx_uid_t user); ngx_int_t ngx_ext_rename_file(ngx_str_t *src, ngx_str_t *to, ngx_ext_rename_file_t *ext); +ngx_int_t ngx_copy_file(u_char *from, u_char *to, ngx_copy_file_t *cf); ngx_int_t ngx_walk_tree(ngx_tree_ctx_t *ctx, ngx_str_t *tree); -void ngx_init_temp_number(void); ngx_atomic_uint_t ngx_next_temp_number(ngx_uint_t collision); char *ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -126,4 +137,8 @@ char *ngx_conf_merge_path_value(ngx_conf char *ngx_conf_set_access_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +extern ngx_atomic_t *ngx_temp_number; +extern ngx_atomic_int_t ngx_random_number; + + #endif /* _NGX_FILE_H_INCLUDED_ */ diff --git a/src/core/ngx_hash.c b/src/core/ngx_hash.c --- a/src/core/ngx_hash.c +++ b/src/core/ngx_hash.c @@ -534,7 +534,7 @@ ngx_hash_wildcard_init(ngx_hash_init_t * next_name->key.len = names[n].key.len - len; next_name->key.data = names[n].key.data + len; - next_name->key_hash= 0; + next_name->key_hash = 0; next_name->value = names[n].value; #if 0 @@ -562,7 +562,7 @@ ngx_hash_wildcard_init(ngx_hash_init_t * next_name->key.len = names[i].key.len - dot_len; next_name->key.data = names[i].key.data + dot_len; - next_name->key_hash= 0; + next_name->key_hash = 0; next_name->value = names[i].value; #if 0 diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c --- a/src/core/ngx_output_chain.c +++ b/src/core/ngx_output_chain.c @@ -314,12 +314,11 @@ ngx_output_chain_add_copy(ngx_pool_t *po #endif + cl->next = NULL; *ll = cl; ll = &cl->next; } - *ll = NULL; - return NGX_OK; } diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -30,12 +30,15 @@ ngx_cpystrn(u_char *dst, u_char *src, si return dst; } - for ( /* void */ ; --n; dst++, src++) { + while (--n) { *dst = *src; if (*dst == '\0') { return dst; } + + dst++; + src++; } *dst = '\0'; @@ -565,8 +568,8 @@ ngx_strcasecmp(u_char *s1, u_char *s2) c1 = (ngx_uint_t) *s1++; c2 = (ngx_uint_t) *s2++; - c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1; - c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2; + c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1; + c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2; if (c1 == c2) { @@ -591,8 +594,8 @@ ngx_strncasecmp(u_char *s1, u_char *s2, c1 = (ngx_uint_t) *s1++; c2 = (ngx_uint_t) *s2++; - c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1; - c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2; + c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1; + c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2; if (c1 == c2) { @@ -680,7 +683,7 @@ ngx_strcasestrn(u_char *s1, char *s2, si ngx_uint_t c1, c2; c2 = (ngx_uint_t) *s2++; - c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2; + c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2; do { do { @@ -690,7 +693,7 @@ ngx_strcasestrn(u_char *s1, char *s2, si return NULL; } - c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1; + c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1; } while (c1 != c2); @@ -712,7 +715,7 @@ ngx_strlcasestrn(u_char *s1, u_char *las ngx_uint_t c1, c2; c2 = (ngx_uint_t) *s2++; - c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2; + c2 = (c2 >= 'A' && c2 <= 'Z') ? (c2 | 0x20) : c2; last -= n; do { @@ -723,7 +726,7 @@ ngx_strlcasestrn(u_char *s1, u_char *las c1 = (ngx_uint_t) *s1++; - c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1; + c1 = (c1 >= 'A' && c1 <= 'Z') ? (c1 | 0x20) : c1; } while (c1 != c2); @@ -1337,7 +1340,7 @@ ngx_escape_uri(u_char *dst, u_char *src, /* find the number of the characters to be escaped */ - n = 0; + n = 0; for (i = 0; i < size; i++) { if (escape[*src >> 5] & (1 << (*src & 0x1f))) { diff --git a/src/event/modules/ngx_devpoll_module.c b/src/event/modules/ngx_devpoll_module.c --- a/src/event/modules/ngx_devpoll_module.c +++ b/src/event/modules/ngx_devpoll_module.c @@ -550,7 +550,7 @@ ngx_devpoll_create_conf(ngx_cycle_t *cyc dpcf = ngx_palloc(cycle->pool, sizeof(ngx_devpoll_conf_t)); if (dpcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } dpcf->changes = NGX_CONF_UNSET; diff --git a/src/event/modules/ngx_epoll_module.c b/src/event/modules/ngx_epoll_module.c --- a/src/event/modules/ngx_epoll_module.c +++ b/src/event/modules/ngx_epoll_module.c @@ -552,7 +552,7 @@ ngx_epoll_create_conf(ngx_cycle_t *cycle epcf = ngx_palloc(cycle->pool, sizeof(ngx_epoll_conf_t)); if (epcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } epcf->events = NGX_CONF_UNSET; diff --git a/src/event/modules/ngx_eventport_module.c b/src/event/modules/ngx_eventport_module.c --- a/src/event/modules/ngx_eventport_module.c +++ b/src/event/modules/ngx_eventport_module.c @@ -581,7 +581,7 @@ ngx_eventport_create_conf(ngx_cycle_t *c epcf = ngx_palloc(cycle->pool, sizeof(ngx_eventport_conf_t)); if (epcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } epcf->events = NGX_CONF_UNSET; diff --git a/src/event/modules/ngx_kqueue_module.c b/src/event/modules/ngx_kqueue_module.c --- a/src/event/modules/ngx_kqueue_module.c +++ b/src/event/modules/ngx_kqueue_module.c @@ -768,7 +768,7 @@ ngx_kqueue_create_conf(ngx_cycle_t *cycl kcf = ngx_palloc(cycle->pool, sizeof(ngx_kqueue_conf_t)); if (kcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } kcf->changes = NGX_CONF_UNSET; diff --git a/src/event/modules/ngx_rtsig_module.c b/src/event/modules/ngx_rtsig_module.c --- a/src/event/modules/ngx_rtsig_module.c +++ b/src/event/modules/ngx_rtsig_module.c @@ -691,7 +691,7 @@ ngx_rtsig_create_conf(ngx_cycle_t *cycle rtscf = ngx_palloc(cycle->pool, sizeof(ngx_rtsig_conf_t)); if (rtscf == NULL) { - return NGX_CONF_ERROR; + return NULL; } rtscf->signo = NGX_CONF_UNSET; diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -43,7 +43,7 @@ ngx_uint_t ngx_event_flags; ngx_event_actions_t ngx_event_actions; -ngx_atomic_t connection_counter = 1; +static ngx_atomic_t connection_counter = 1; ngx_atomic_t *ngx_connection_counter = &connection_counter; @@ -429,6 +429,7 @@ ngx_event_module_init(ngx_cycle_t *cycle u_char *shared; size_t size, cl; ngx_shm_t shm; + ngx_time_t *tp; ngx_core_conf_t *ccf; ngx_event_conf_t *ecf; @@ -492,7 +493,8 @@ ngx_event_module_init(ngx_cycle_t *cycle cl = 128; size = cl /* ngx_accept_mutex */ - + cl; /* ngx_connection_counter */ + + cl /* ngx_connection_counter */ + + cl; /* ngx_temp_number */ #if (NGX_STAT_STUB) @@ -526,23 +528,29 @@ ngx_event_module_init(ngx_cycle_t *cycle ngx_connection_counter = (ngx_atomic_t *) (shared + 1 * cl); -#if (NGX_STAT_STUB) - - ngx_stat_accepted = (ngx_atomic_t *) (shared + 2 * cl); - ngx_stat_handled = (ngx_atomic_t *) (shared + 3 * cl); - ngx_stat_requests = (ngx_atomic_t *) (shared + 4 * cl); - ngx_stat_active = (ngx_atomic_t *) (shared + 5 * cl); - ngx_stat_reading = (ngx_atomic_t *) (shared + 6 * cl); - ngx_stat_writing = (ngx_atomic_t *) (shared + 7 * cl); - -#endif - (void) ngx_atomic_cmp_set(ngx_connection_counter, 0, 1); ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "counter: %p, %d", ngx_connection_counter, *ngx_connection_counter); + ngx_temp_number = (ngx_atomic_t *) (shared + 2 * cl); + + tp = ngx_timeofday(); + + ngx_random_number = (tp->msec << 16) + ngx_pid; + +#if (NGX_STAT_STUB) + + ngx_stat_accepted = (ngx_atomic_t *) (shared + 3 * cl); + ngx_stat_handled = (ngx_atomic_t *) (shared + 4 * cl); + ngx_stat_requests = (ngx_atomic_t *) (shared + 5 * cl); + ngx_stat_active = (ngx_atomic_t *) (shared + 6 * cl); + ngx_stat_reading = (ngx_atomic_t *) (shared + 7 * cl); + ngx_stat_writing = (ngx_atomic_t *) (shared + 8 * cl); + +#endif + return NGX_OK; } @@ -1113,7 +1121,7 @@ ngx_event_create_conf(ngx_cycle_t *cycle ecf = ngx_palloc(cycle->pool, sizeof(ngx_event_conf_t)); if (ecf == NULL) { - return NGX_CONF_ERROR; + return NULL; } ecf->connections = NGX_CONF_UNSET_UINT; @@ -1128,7 +1136,7 @@ ngx_event_create_conf(ngx_cycle_t *cycle if (ngx_array_init(&ecf->debug_connection, cycle->pool, 4, sizeof(ngx_event_debug_t)) == NGX_ERROR) { - return NGX_CONF_ERROR; + return NULL; } #endif diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -97,16 +97,12 @@ int ngx_ssl_session_cache_index; ngx_int_t ngx_ssl_init(ngx_log_t *log) { -#if OPENSSL_VERSION_NUMBER >= 0x00907000 OPENSSL_config(NULL); -#endif SSL_library_init(); SSL_load_error_strings(); -#if (NGX_SSL_ENGINE) ENGINE_load_builtin_engines(); -#endif ngx_ssl_connection_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); @@ -169,9 +165,7 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_ SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_D5_BUG); SSL_CTX_set_options(ssl->ctx, SSL_OP_TLS_BLOCK_PADDING_BUG); -#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS SSL_CTX_set_options(ssl->ctx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); -#endif SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_DH_USE); @@ -267,6 +261,51 @@ ngx_ssl_client_certificate(ngx_conf_t *c } +ngx_int_t +ngx_ssl_crl(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *crl) +{ + X509_STORE *store; + X509_LOOKUP *lookup; + + if (crl->len == 0) { + return NGX_OK; + } + + if (ngx_conf_full_name(cf->cycle, crl, 1) != NGX_OK) { + return NGX_ERROR; + } + + store = SSL_CTX_get_cert_store(ssl->ctx); + + if (store == NULL) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CTX_get_cert_store() failed"); + return NGX_ERROR; + } + + lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); + + if (lookup == NULL) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "X509_STORE_add_lookup() failed"); + return NGX_ERROR; + } + + if (X509_LOOKUP_load_file(lookup, (char *) crl->data, X509_FILETYPE_PEM) + == 0) + { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "X509_LOOKUP_load_file(\"%s\") failed", crl->data); + return NGX_ERROR; + } + + X509_STORE_set_flags(store, + X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); + + return NGX_OK; +} + + static int ngx_http_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store) { @@ -1201,9 +1240,7 @@ ngx_ssl_connection_error(ngx_connection_ if (err == NGX_ECONNRESET || err == NGX_EPIPE || err == NGX_ENOTCONN -#if !(NGX_CRIT_ETIMEDOUT) || err == NGX_ETIMEDOUT -#endif || err == NGX_ECONNREFUSED || err == NGX_ENETDOWN || err == NGX_ENETUNREACH @@ -1974,7 +2011,7 @@ ngx_ssl_get_certificate(ngx_connection_t p = s->data; - for (i = 0; i < len; i++) { + for (i = 0; i < cert.len - 1; i++) { *p++ = cert.data[i]; if (cert.data[i] == LF) { *p++ = '\t'; @@ -2108,6 +2145,35 @@ ngx_ssl_get_serial_number(ngx_connection } +ngx_int_t +ngx_ssl_get_client_verify(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s) +{ + X509 *cert; + + if (SSL_get_verify_result(c->ssl->connection) != X509_V_OK) { + s->len = sizeof("FAILED") - 1; + s->data = (u_char *) "FAILED"; + + return NGX_OK; + } + + cert = SSL_get_peer_certificate(c->ssl->connection); + + if (cert) { + s->len = sizeof("SUCCESS") - 1; + s->data = (u_char *) "SUCCESS"; + + } else { + s->len = sizeof("NONE") - 1; + s->data = (u_char *) "NONE"; + } + + X509_free(cert); + + return NGX_OK; +} + + static void * ngx_openssl_create_conf(ngx_cycle_t *cycle) { @@ -2115,7 +2181,7 @@ ngx_openssl_create_conf(ngx_cycle_t *cyc oscf = ngx_pcalloc(cycle->pool, sizeof(ngx_openssl_conf_t)); if (oscf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* @@ -2131,7 +2197,6 @@ ngx_openssl_create_conf(ngx_cycle_t *cyc static char * ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { -#if (NGX_SSL_ENGINE) ngx_openssl_conf_t *oscf = conf; ENGINE *engine; @@ -2166,23 +2231,11 @@ ngx_openssl_engine(ngx_conf_t *cf, ngx_c ENGINE_free(engine); return NGX_CONF_OK; - -#else - - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"ssl_engine\" directive is available only in " - "OpenSSL 0.9.7 and higher,"); - - return NGX_CONF_ERROR; - -#endif } static void ngx_openssl_exit(ngx_cycle_t *cycle) { -#if (NGX_SSL_ENGINE) ENGINE_cleanup(); -#endif } diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -13,12 +13,8 @@ #include #include - -#if OPENSSL_VERSION_NUMBER >= 0x00907000 #include #include -#define NGX_SSL_ENGINE 1 -#endif #define NGX_SSL_NAME "OpenSSL" @@ -100,6 +96,7 @@ ngx_int_t ngx_ssl_certificate(ngx_conf_t ngx_str_t *cert, ngx_str_t *key); ngx_int_t ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, ngx_int_t depth); +ngx_int_t ngx_ssl_crl(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *crl); ngx_int_t ngx_ssl_generate_rsa512_key(ngx_ssl_t *ssl); ngx_int_t ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *file); ngx_int_t ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx, @@ -131,6 +128,8 @@ ngx_int_t ngx_ssl_get_issuer_dn(ngx_conn ngx_str_t *s); ngx_int_t ngx_ssl_get_serial_number(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s); +ngx_int_t ngx_ssl_get_client_verify(ngx_connection_t *c, ngx_pool_t *pool, + ngx_str_t *s); ngx_int_t ngx_ssl_handshake(ngx_connection_t *c); diff --git a/src/http/modules/ngx_http_access_module.c b/src/http/modules/ngx_http_access_module.c --- a/src/http/modules/ngx_http_access_module.c +++ b/src/http/modules/ngx_http_access_module.c @@ -201,7 +201,7 @@ ngx_http_access_create_loc_conf(ngx_conf conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_access_loc_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } return conf; diff --git a/src/http/modules/ngx_http_addition_filter_module.c b/src/http/modules/ngx_http_addition_filter_module.c --- a/src/http/modules/ngx_http_addition_filter_module.c +++ b/src/http/modules/ngx_http_addition_filter_module.c @@ -212,7 +212,7 @@ ngx_http_addition_create_conf(ngx_conf_t conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_addition_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* diff --git a/src/http/modules/ngx_http_auth_basic_module.c b/src/http/modules/ngx_http_auth_basic_module.c --- a/src/http/modules/ngx_http_auth_basic_module.c +++ b/src/http/modules/ngx_http_auth_basic_module.c @@ -372,7 +372,7 @@ ngx_http_auth_basic_create_loc_conf(ngx_ conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_auth_basic_loc_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } return conf; diff --git a/src/http/modules/ngx_http_autoindex_module.c b/src/http/modules/ngx_http_autoindex_module.c --- a/src/http/modules/ngx_http_autoindex_module.c +++ b/src/http/modules/ngx_http_autoindex_module.c @@ -145,7 +145,7 @@ ngx_http_autoindex_handler(ngx_http_requ ngx_int_t rc, size; ngx_str_t path; ngx_dir_t dir; - ngx_uint_t i, level; + ngx_uint_t i, level, utf8; ngx_pool_t *pool; ngx_time_t *tp; ngx_chain_t out; @@ -252,6 +252,16 @@ ngx_http_autoindex_handler(ngx_http_requ filename = path.data; filename[path.len] = '/'; + if (r->headers_out.charset.len == 5 + && ngx_strncasecmp(r->headers_out.charset.data, (u_char *) "utf-8", 5) + == 0) + { + utf8 = 1; + + } else { + utf8 = 0; + } + for ( ;; ) { ngx_set_errno(0); @@ -335,7 +345,7 @@ ngx_http_autoindex_handler(ngx_http_requ entry->escape = 2 * ngx_escape_uri(NULL, ngx_de_name(&dir), len, NGX_ESCAPE_HTML); - if (r->utf8) { + if (utf8) { entry->utf_len = ngx_utf8_length(entry->name.data, entry->name.len); } else { entry->utf_len = len; @@ -622,7 +632,7 @@ ngx_http_autoindex_create_loc_conf(ngx_c conf = ngx_palloc(cf->pool, sizeof(ngx_http_autoindex_loc_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } conf->enable = NGX_CONF_UNSET; diff --git a/src/http/modules/ngx_http_browser_module.c b/src/http/modules/ngx_http_browser_module.c --- a/src/http/modules/ngx_http_browser_module.c +++ b/src/http/modules/ngx_http_browser_module.c @@ -423,7 +423,7 @@ ngx_http_browser_create_conf(ngx_conf_t conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_browser_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* diff --git a/src/http/modules/ngx_http_charset_filter_module.c b/src/http/modules/ngx_http_charset_filter_module.c --- a/src/http/modules/ngx_http_charset_filter_module.c +++ b/src/http/modules/ngx_http_charset_filter_module.c @@ -9,8 +9,9 @@ #include -#define NGX_HTTP_NO_CHARSET -2 -#define NGX_HTTP_CHARSET_VAR 0x10000 +#define NGX_HTTP_CHARSET_OFF -2 +#define NGX_HTTP_NO_CHARSET -3 +#define NGX_HTTP_CHARSET_VAR 0x10000 /* 1 byte length and up to 3 bytes for the UTF-8 encoding of the UCS-2 */ #define NGX_UTF_LEN 4 @@ -61,6 +62,7 @@ typedef struct { typedef struct { u_char *table; ngx_int_t charset; + ngx_str_t charset_name; ngx_chain_t *busy; ngx_chain_t *free_bufs; @@ -82,9 +84,16 @@ typedef struct { } ngx_http_charset_conf_ctx_t; -static ngx_int_t ngx_http_charset_get_charset(ngx_http_charset_t *charsets, - ngx_uint_t n, ngx_str_t *charset); -static ngx_int_t ngx_http_charset_set_charset(ngx_http_request_t *r, +static ngx_int_t ngx_http_destination_charset(ngx_http_request_t *r, + ngx_str_t *name); +static ngx_int_t ngx_http_main_request_charset(ngx_http_request_t *r, + ngx_str_t *name); +static ngx_int_t ngx_http_source_charset(ngx_http_request_t *r, + ngx_str_t *name); +static ngx_int_t ngx_http_get_charset(ngx_http_request_t *r, ngx_str_t *name); +static ngx_inline void ngx_http_set_charset(ngx_http_request_t *r, + ngx_str_t *charset); +static ngx_int_t ngx_http_charset_ctx(ngx_http_request_t *r, ngx_http_charset_t *charsets, ngx_int_t charset, ngx_int_t source_charset); static ngx_uint_t ngx_http_charset_recode(ngx_buf_t *b, u_char *table); static ngx_chain_t *ngx_http_charset_recode_from_utf8(ngx_pool_t *pool, @@ -207,207 +216,264 @@ static ngx_int_t ngx_http_charset_header_filter(ngx_http_request_t *r) { ngx_int_t charset, source_charset; - ngx_str_t *mc, *from, *to, s; - ngx_uint_t n; + ngx_str_t dst, src; ngx_http_charset_t *charsets; - ngx_http_charset_ctx_t *ctx; - ngx_http_variable_value_t *vv; - ngx_http_charset_loc_conf_t *lcf, *mlcf; ngx_http_charset_main_conf_t *mcf; - mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module); - - charsets = mcf->charsets.elts; - n = mcf->charsets.nelts; - - /* destination charset */ - if (r == r->main) { - - if (!r->ignore_content_encoding - && r->headers_out.content_encoding - && r->headers_out.content_encoding->value.len) - { - return ngx_http_next_header_filter(r); - } - - if (r->headers_out.content_type.len == 0) { - return ngx_http_next_header_filter(r); - } - - if (r->headers_out.override_charset - && r->headers_out.override_charset->len) - { - charset = ngx_http_charset_get_charset(charsets, n, - r->headers_out.override_charset); - - if (charset == NGX_HTTP_NO_CHARSET) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "unknown charset \"%V\" to override", - r->headers_out.override_charset); - - return ngx_http_next_header_filter(r); - } - - } else { - mlcf = ngx_http_get_module_loc_conf(r, - ngx_http_charset_filter_module); - charset = mlcf->charset; - - if (charset == NGX_HTTP_NO_CHARSET) { - return ngx_http_next_header_filter(r); - } - - if (r->headers_out.charset.len) { - if (mlcf->override_charset == 0) { - return ngx_http_next_header_filter(r); - } - - } else { - if (ngx_http_test_content_type(r, &mlcf->types) == NULL) { - return ngx_http_next_header_filter(r); - } - } - - if (charset >= NGX_HTTP_CHARSET_VAR) { - vv = ngx_http_get_indexed_variable(r, - charset - NGX_HTTP_CHARSET_VAR); - - if (vv == NULL || vv->not_found) { - return NGX_ERROR; - } - - s.len = vv->len; - s.data = vv->data; - - charset = ngx_http_charset_get_charset(charsets, n, &s); - } - } + charset = ngx_http_destination_charset(r, &dst); } else { - ctx = ngx_http_get_module_ctx(r->main, ngx_http_charset_filter_module); - - if (ctx == NULL) { - - mc = &r->main->headers_out.charset; - - if (mc->len == 0) { - return ngx_http_next_header_filter(r); - } + charset = ngx_http_main_request_charset(r, &dst); + } - ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_charset_ctx_t)); - if (ctx == NULL) { - return NGX_ERROR; - } - - ngx_http_set_ctx(r->main, ctx, ngx_http_charset_filter_module); + if (charset == NGX_ERROR) { + return NGX_ERROR; + } - charset = ngx_http_charset_get_charset(charsets, n, mc); - - ctx->charset = charset; - - } else { - charset = ctx->charset; - } + if (charset == NGX_DECLINED) { + return ngx_http_next_header_filter(r); } - /* source charset */ - - if (r->headers_out.charset.len == 0) { - lcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module); - - source_charset = lcf->source_charset; - - if (source_charset >= NGX_HTTP_CHARSET_VAR) { - vv = ngx_http_get_indexed_variable(r, - source_charset - NGX_HTTP_CHARSET_VAR); - - if (vv == NULL || vv->not_found) { - return NGX_ERROR; - } + /* charset: charset index or NGX_HTTP_NO_CHARSET */ - s.len = vv->len; - s.data = vv->data; - - source_charset = ngx_http_charset_get_charset(charsets, n, &s); - } + source_charset = ngx_http_source_charset(r, &src); - if (charset != NGX_HTTP_NO_CHARSET) { - return ngx_http_charset_set_charset(r, mcf->charsets.elts, charset, - source_charset); - } - - if (source_charset == NGX_CONF_UNSET) { - return ngx_http_next_header_filter(r); - } - - from = &charsets[source_charset].name; - to = &r->main->headers_out.charset; - - goto no_charset_map; + if (source_charset == NGX_ERROR) { + return NGX_ERROR; } - source_charset = ngx_http_charset_get_charset(charsets, n, - &r->headers_out.charset); + /* + * source_charset: charset index, NGX_HTTP_NO_CHARSET, + * or NGX_HTTP_CHARSET_OFF + */ + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "charset: \"%V\" > \"%V\"", &src, &dst); + + if (source_charset == NGX_HTTP_CHARSET_OFF) { + ngx_http_set_charset(r, &dst); + + return ngx_http_next_header_filter(r); + } if (charset == NGX_HTTP_NO_CHARSET || source_charset == NGX_HTTP_NO_CHARSET) { - if (charset != source_charset - || ngx_strcasecmp(r->main->headers_out.charset.data, - r->headers_out.charset.data) - != 0) + if (source_charset != charset + || ngx_strncasecmp(dst.data, src.data, dst.len) != 0) { - from = &r->headers_out.charset; - to = (charset == NGX_HTTP_NO_CHARSET) ? - &r->main->headers_out.charset: - &charsets[charset].name; - goto no_charset_map; } + ngx_http_set_charset(r, &dst); + return ngx_http_next_header_filter(r); } + mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module); + charsets = mcf->charsets.elts; + if (source_charset != charset && (charsets[source_charset].tables == NULL || charsets[source_charset].tables[charset] == NULL)) { - from = &charsets[source_charset].name; - to = &charsets[charset].name; - goto no_charset_map; } r->headers_out.content_type.len = r->headers_out.content_type_len; - return ngx_http_charset_set_charset(r, mcf->charsets.elts, charset, - source_charset); + ngx_http_set_charset(r, &dst); + + if (source_charset != charset) { + return ngx_http_charset_ctx(r, charsets, charset, source_charset); + } + + return ngx_http_next_header_filter(r); no_charset_map: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no \"charset_map\" between the charsets \"%V\" and \"%V\"", - from, to); + &src, &dst); return ngx_http_next_header_filter(r); } static ngx_int_t -ngx_http_charset_get_charset(ngx_http_charset_t *charsets, ngx_uint_t n, - ngx_str_t *charset) +ngx_http_destination_charset(ngx_http_request_t *r, ngx_str_t *name) +{ + ngx_int_t charset; + ngx_http_charset_t *charsets; + ngx_http_variable_value_t *vv; + ngx_http_charset_loc_conf_t *mlcf; + ngx_http_charset_main_conf_t *mcf; + + if (!r->ignore_content_encoding + && r->headers_out.content_encoding + && r->headers_out.content_encoding->value.len) + { + return NGX_DECLINED; + } + + if (r->headers_out.content_type.len == 0) { + return NGX_DECLINED; + } + + if (r->headers_out.override_charset + && r->headers_out.override_charset->len) + { + *name = *r->headers_out.override_charset; + + charset = ngx_http_get_charset(r, name); + + if (charset != NGX_HTTP_NO_CHARSET) { + return charset; + } + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "unknown charset \"%V\" to override", name); + + return NGX_DECLINED; + } + + mlcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module); + charset = mlcf->charset; + + if (charset == NGX_HTTP_CHARSET_OFF) { + return NGX_DECLINED; + } + + if (r->headers_out.charset.len) { + if (mlcf->override_charset == 0) { + return NGX_DECLINED; + } + + } else { + if (ngx_http_test_content_type(r, &mlcf->types) == NULL) { + return NGX_DECLINED; + } + } + + if (charset < NGX_HTTP_CHARSET_VAR) { + mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module); + charsets = mcf->charsets.elts; + *name = charsets[charset].name; + return charset; + } + + vv = ngx_http_get_indexed_variable(r, charset - NGX_HTTP_CHARSET_VAR); + + if (vv == NULL || vv->not_found) { + return NGX_ERROR; + } + + name->len = vv->len; + name->data = vv->data; + + return ngx_http_get_charset(r, name); +} + + +static ngx_int_t +ngx_http_main_request_charset(ngx_http_request_t *r, ngx_str_t *src) { - ngx_uint_t i; + ngx_int_t charset; + ngx_str_t *main_charset; + ngx_http_charset_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r->main, ngx_http_charset_filter_module); + + if (ctx) { + *src = ctx->charset_name; + return ctx->charset; + } + + main_charset = &r->main->headers_out.charset; + + if (main_charset->len == 0) { + return NGX_DECLINED; + } + + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_charset_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_http_set_ctx(r->main, ctx, ngx_http_charset_filter_module); + + charset = ngx_http_get_charset(r, main_charset); + + ctx->charset = charset; + ctx->charset_name = *main_charset; + *src = *main_charset; + + return charset; +} + + +static ngx_int_t +ngx_http_source_charset(ngx_http_request_t *r, ngx_str_t *name) +{ + ngx_int_t charset; + ngx_http_charset_t *charsets; + ngx_http_variable_value_t *vv; + ngx_http_charset_loc_conf_t *lcf; + ngx_http_charset_main_conf_t *mcf; + + if (r->headers_out.charset.len) { + *name = r->headers_out.charset; + return ngx_http_get_charset(r, name); + } + + lcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module); + + charset = lcf->source_charset; + + if (charset == NGX_HTTP_CHARSET_OFF) { + name->len = 0; + return charset; + } + + if (charset < NGX_HTTP_CHARSET_VAR) { + mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module); + charsets = mcf->charsets.elts; + *name = charsets[charset].name; + return charset; + } + + vv = ngx_http_get_indexed_variable(r, charset - NGX_HTTP_CHARSET_VAR); + + if (vv == NULL || vv->not_found) { + return NGX_ERROR; + } + + name->len = vv->len; + name->data = vv->data; + + return ngx_http_get_charset(r, name); +} + + +static ngx_int_t +ngx_http_get_charset(ngx_http_request_t *r, ngx_str_t *name) +{ + ngx_uint_t i, n; + ngx_http_charset_t *charset; + ngx_http_charset_main_conf_t *mcf; + + mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module); + + charset = mcf->charsets.elts; + n = mcf->charsets.nelts; for (i = 0; i < n; i++) { - if (charsets[i].name.len != charset->len) { + if (charset[i].name.len != name->len) { continue; } - if (ngx_strncasecmp(charsets[i].name.data, charset->data, charset->len) - == 0) - { + if (ngx_strncasecmp(charset[i].name.data, name->data, name->len) == 0) { return i; } } @@ -416,11 +482,12 @@ ngx_http_charset_get_charset(ngx_http_ch } -static ngx_int_t -ngx_http_charset_set_charset(ngx_http_request_t *r, - ngx_http_charset_t *charsets, ngx_int_t charset, ngx_int_t source_charset) +static ngx_inline void +ngx_http_set_charset(ngx_http_request_t *r, ngx_str_t *charset) { - ngx_http_charset_ctx_t *ctx; + if (r != r->main) { + return; + } if (r->headers_out.status == NGX_HTTP_MOVED_PERMANENTLY || r->headers_out.status == NGX_HTTP_MOVED_TEMPORARILY) @@ -431,16 +498,18 @@ ngx_http_charset_set_charset(ngx_http_re */ r->headers_out.charset.len = 0; - - return ngx_http_next_header_filter(r); + return; } - r->headers_out.charset = charsets[charset].name; - r->utf8 = charsets[charset].utf8; + r->headers_out.charset = *charset; +} + - if (source_charset == NGX_CONF_UNSET || source_charset == charset) { - return ngx_http_next_header_filter(r); - } +static ngx_int_t +ngx_http_charset_ctx(ngx_http_request_t *r, ngx_http_charset_t *charsets, + ngx_int_t charset, ngx_int_t source_charset) +{ + ngx_http_charset_ctx_t *ctx; ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_charset_ctx_t)); if (ctx == NULL) { @@ -451,6 +520,7 @@ ngx_http_charset_set_charset(ngx_http_re ctx->table = charsets[source_charset].tables[charset]; ctx->charset = charset; + ctx->charset_name = charsets[charset].name; ctx->length = charsets[charset].length; ctx->from_utf8 = charsets[source_charset].utf8; ctx->to_utf8 = charsets[charset].utf8; @@ -1338,7 +1408,7 @@ ngx_http_set_charset_slot(ngx_conf_t *cf if (cmd->offset == offsetof(ngx_http_charset_loc_conf_t, charset) && ngx_strcmp(value[1].data, "off") == 0) { - *cp = NGX_HTTP_NO_CHARSET; + *cp = NGX_HTTP_CHARSET_OFF; return NGX_CONF_OK; } @@ -1418,27 +1488,27 @@ ngx_http_charset_create_main_conf(ngx_co mcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_charset_main_conf_t)); if (mcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } if (ngx_array_init(&mcf->charsets, cf->pool, 2, sizeof(ngx_http_charset_t)) != NGX_OK) { - return NGX_CONF_ERROR; + return NULL; } if (ngx_array_init(&mcf->tables, cf->pool, 1, sizeof(ngx_http_charset_tables_t)) != NGX_OK) { - return NGX_CONF_ERROR; + return NULL; } if (ngx_array_init(&mcf->recodes, cf->pool, 2, sizeof(ngx_http_charset_recode_t)) != NGX_OK) { - return NGX_CONF_ERROR; + return NULL; } return mcf; @@ -1452,7 +1522,7 @@ ngx_http_charset_create_loc_conf(ngx_con lcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_charset_loc_conf_t)); if (lcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* @@ -1489,14 +1559,12 @@ ngx_http_charset_merge_loc_conf(ngx_conf } ngx_conf_merge_value(conf->override_charset, prev->override_charset, 0); - ngx_conf_merge_value(conf->charset, prev->charset, NGX_HTTP_NO_CHARSET); + ngx_conf_merge_value(conf->charset, prev->charset, NGX_HTTP_CHARSET_OFF); + ngx_conf_merge_value(conf->source_charset, prev->source_charset, + NGX_HTTP_CHARSET_OFF); - if (conf->source_charset == NGX_CONF_UNSET) { - conf->source_charset = prev->source_charset; - } - - if (conf->charset == NGX_HTTP_NO_CHARSET - || conf->source_charset == NGX_CONF_UNSET + if (conf->charset == NGX_HTTP_CHARSET_OFF + || conf->source_charset == NGX_HTTP_CHARSET_OFF || conf->charset == conf->source_charset) { return NGX_CONF_OK; diff --git a/src/http/modules/ngx_http_dav_module.c b/src/http/modules/ngx_http_dav_module.c --- a/src/http/modules/ngx_http_dav_module.c +++ b/src/http/modules/ngx_http_dav_module.c @@ -53,8 +53,6 @@ static ngx_int_t ngx_http_dav_copy_dir_t ngx_str_t *path); static ngx_int_t ngx_http_dav_copy_tree_file(ngx_tree_ctx_t *ctx, ngx_str_t *path); -static ngx_int_t ngx_http_dav_copy_file(ngx_tree_ctx_t *ctx, u_char *from, - u_char *to); static ngx_int_t ngx_http_dav_depth(ngx_http_request_t *r, ngx_int_t dflt); static ngx_int_t ngx_http_dav_error(ngx_log_t *log, ngx_err_t err, @@ -216,6 +214,8 @@ ngx_http_dav_put_handler(ngx_http_reques ngx_http_map_uri_to_path(r, &path, &root, 0); + path.len--; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http put filename: \"%s\"", path.data); @@ -249,7 +249,6 @@ ngx_http_dav_put_handler(ngx_http_reques ext.time = -1; ext.create_path = dlcf->create_full_put_path; ext.delete_file = 1; - ext.log_rename_error = 1; ext.log = r->connection->log; if (r->headers_in.date) { @@ -491,6 +490,7 @@ ngx_http_dav_mkcol_handler(ngx_http_requ p = ngx_http_map_uri_to_path(r, &path, &root, 0); *(p - 1) = '\0'; + r->uri.len--; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http mkcol path: \"%s\"", path.data); @@ -517,9 +517,10 @@ ngx_http_dav_copy_move_handler(ngx_http_ size_t len, root; ngx_err_t err; ngx_int_t rc, depth; - ngx_uint_t overwrite, slash, dir; - ngx_str_t path, uri; + ngx_uint_t overwrite, slash, dir, flags; + ngx_str_t path, uri, duri, args; ngx_tree_ctx_t tree; + ngx_copy_file_t cf; ngx_file_info_t fi; ngx_table_elt_t *dest, *over; ngx_ext_rename_file_t ext; @@ -594,6 +595,14 @@ invalid_destination: destination_done: + duri.len = last - p; + duri.data = p; + flags = 0; + + if (ngx_http_parse_unsafe_uri(r, &duri, &args, &flags) != NGX_OK) { + goto invalid_destination; + } + if ((r->uri.data[r->uri.len - 1] == '/' && *(last - 1) != '/') || (r->uri.data[r->uri.len - 1] != '/' && *(last - 1) == '/')) { @@ -656,9 +665,7 @@ overwrite_done: "http copy from: \"%s\"", path.data); uri = r->uri; - - r->uri.len = last - p; - r->uri.data = p; + r->uri = duri; ngx_http_map_uri_to_path(r, ©.path, &root, 0); @@ -791,43 +798,24 @@ overwrite_done: ext.time = -1; ext.create_path = 1; ext.delete_file = 0; - ext.log_rename_error = 0; ext.log = r->connection->log; if (ngx_ext_rename_file(&path, ©.path, &ext) == NGX_OK) { return NGX_HTTP_NO_CONTENT; } - if (ext.rename_error != NGX_EXDEV) { - - if (ext.rename_error) { - ngx_log_error(NGX_LOG_CRIT, r->connection->log, - ext.rename_error, - ngx_rename_file_n " \"%s\" to \"%s\" failed", - path.data, copy.path.data); - } - - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } + return NGX_HTTP_INTERNAL_SERVER_ERROR; } dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module); - tree.size = ngx_file_size(&fi); - tree.mtime = ngx_file_mtime(&fi); - tree.access = dlcf->access; - tree.log = r->connection->log; + cf.size = ngx_file_size(&fi); + cf.buf_size = 0; + cf.access = dlcf->access; + cf.time = ngx_file_mtime(&fi); + cf.log = r->connection->log; - if (ngx_http_dav_copy_file(&tree, path.data, copy.path.data) == NGX_OK) - { - if (r->method == NGX_HTTP_MOVE) { - rc = ngx_http_dav_delete_path(r, &path, 0); - - if (rc != NGX_OK) { - return rc; - } - } - + if (ngx_copy_file(path.data, copy.path.data, &cf) == NGX_OK) { return NGX_HTTP_NO_CONTENT; } } @@ -941,6 +929,7 @@ ngx_http_dav_copy_tree_file(ngx_tree_ctx { u_char *p, *file; size_t len; + ngx_copy_file_t cf; ngx_http_dav_copy_ctx_t *copy; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, @@ -961,7 +950,13 @@ ngx_http_dav_copy_tree_file(ngx_tree_ctx ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, "http copy file to: \"%s\"", file); - (void) ngx_http_dav_copy_file(ctx, path->data, file); + cf.size = ctx->size; + cf.buf_size = 0; + cf.access = ctx->access; + cf.time = ctx->mtime; + cf.log = ctx->log; + + (void) ngx_copy_file(path->data, file, &cf); ngx_free(file); @@ -970,75 +965,6 @@ ngx_http_dav_copy_tree_file(ngx_tree_ctx static ngx_int_t -ngx_http_dav_copy_file(ngx_tree_ctx_t *ctx, u_char *from, u_char *to) -{ - off_t size; - ssize_t n; - ngx_fd_t fd, cfd; - ngx_int_t rc; - u_char buf[NGX_HTTP_DAV_COPY_BLOCK]; - - fd = ngx_open_file(from, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); - - if (fd == NGX_INVALID_FILE) { - (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_open_file_n, - from); - return NGX_ERROR; - } - - cfd = ngx_open_file(to, NGX_FILE_WRONLY, NGX_FILE_CREATE_OR_OPEN, - ctx->access); - - rc = NGX_ERROR; - - if (cfd == NGX_INVALID_FILE) { - (void) ngx_http_dav_error(ctx->log, ngx_errno, 0, ngx_open_file_n, to); - goto failed; - } - - for (size = ctx->size; size > 0; size -= n) { - - n = ngx_read_fd(fd, buf, NGX_HTTP_DAV_COPY_BLOCK); - - if (n == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno, - ngx_read_fd_n " \"%s\" failed", from); - goto failed; - } - - if (ngx_write_fd(cfd, buf, n) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno, - ngx_write_fd_n " \"%s\" failed", to); - goto failed; - } - } - - if (ngx_set_file_time(to, cfd, ctx->mtime) != NGX_OK) { - ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno, - ngx_set_file_time_n " \"%s\" failed", to); - goto failed; - } - - if (ngx_close_file(cfd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno, - ngx_close_file_n " \"%s\" failed", to); - goto failed; - } - - rc = NGX_OK; - -failed: - - if (ngx_close_file(fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno, - ngx_close_file_n " \"%s\" failed", from); - } - - return rc; -} - - -static ngx_int_t ngx_http_dav_depth(ngx_http_request_t *r, ngx_int_t dflt) { ngx_table_elt_t *depth; @@ -1154,7 +1080,7 @@ ngx_http_dav_create_loc_conf(ngx_conf_t conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_dav_loc_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* 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 @@ -543,20 +543,17 @@ ngx_http_fastcgi_handler(ngx_http_reques return NGX_HTTP_INTERNAL_SERVER_ERROR; } + if (ngx_http_upstream_create(r) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t)); if (f == NULL) { - return NGX_ERROR; + return NGX_HTTP_INTERNAL_SERVER_ERROR; } ngx_http_set_ctx(r, f, ngx_http_fastcgi_module); - u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t)); - if (u == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - r->upstream = u; - flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); if (flcf->fastcgi_lengths) { @@ -565,15 +562,11 @@ ngx_http_fastcgi_handler(ngx_http_reques } } + u = r->upstream; + u->schema.len = sizeof("fastcgi://") - 1; u->schema.data = (u_char *) "fastcgi://"; - u->peer.log = r->connection->log; - u->peer.log_error = NGX_ERROR_ERR; -#if (NGX_THREADS) - u->peer.lock = &r->connection->lock; -#endif - u->output.tag = (ngx_buf_tag_t) &ngx_http_fastcgi_module; u->conf = &flcf->upstream; @@ -1836,7 +1829,7 @@ ngx_http_fastcgi_create_loc_conf(ngx_con conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastcgi_loc_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* 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 @@ -35,6 +35,7 @@ typedef struct { ngx_radix_tree_t *tree; ngx_rbtree_t rbtree; ngx_rbtree_node_t sentinel; + ngx_array_t *proxies; ngx_pool_t *pool; ngx_pool_t *temp_pool; } ngx_http_geo_conf_ctx_t; @@ -46,12 +47,16 @@ typedef struct { ngx_http_geo_high_ranges_t *high; } u; + ngx_array_t *proxies; + ngx_int_t index; } ngx_http_geo_ctx_t; static in_addr_t ngx_http_geo_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx); +static in_addr_t ngx_http_geo_real_addr(ngx_http_request_t *r, + ngx_http_geo_ctx_t *ctx); static char *ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_geo(ngx_conf_t *cf, ngx_command_t *dummy, void *conf); static char *ngx_http_geo_range(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, @@ -64,6 +69,10 @@ static char *ngx_http_geo_cidr(ngx_conf_ ngx_str_t *value); static ngx_http_variable_value_t *ngx_http_geo_value(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, ngx_str_t *value); +static char *ngx_http_geo_add_proxy(ngx_conf_t *cf, + ngx_http_geo_conf_ctx_t *ctx, ngx_cidr_t *cidr); +static ngx_int_t ngx_http_geo_cidr_value(ngx_conf_t *cf, ngx_str_t *net, + ngx_cidr_t *cidr); static ngx_command_t ngx_http_geo_commands[] = { @@ -168,6 +177,50 @@ ngx_http_geo_range_variable(ngx_http_req static in_addr_t ngx_http_geo_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx) { + u_char *p, *ip; + size_t len; + in_addr_t addr; + ngx_uint_t i, n; + ngx_in_cidr_t *proxies; + ngx_table_elt_t *xfwd; + + addr = ngx_http_geo_real_addr(r, ctx); + + xfwd = r->headers_in.x_forwarded_for; + + if (xfwd == NULL || ctx->proxies == NULL) { + return addr; + } + + proxies = ctx->proxies->elts; + n = ctx->proxies->nelts; + + for (i = 0; i < n; i++) { + if ((addr & proxies[i].mask) == proxies[i].addr) { + + len = xfwd->value.len; + ip = xfwd->value.data; + + for (p = ip + len - 1; p > ip; p--) { + if (*p == ' ' || *p == ',') { + p++; + len -= p - ip; + ip = p; + break; + } + } + + return ntohl(ngx_inet_addr(ip, len)); + } + } + + return addr; +} + + +static in_addr_t +ngx_http_geo_real_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx) +{ struct sockaddr_in *sin; ngx_http_variable_value_t *v; @@ -259,6 +312,7 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_c ctx.high = NULL; ctx.tree = NULL; + ctx.proxies = NULL; ctx.pool = cf->pool; save = *cf; @@ -271,6 +325,8 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_c *cf = save; + geo->proxies = ctx.proxies; + if (ctx.high) { for (i = 0; i < 0x10000; i++) { @@ -341,6 +397,7 @@ ngx_http_geo(ngx_conf_t *cf, ngx_command { char *rv; ngx_str_t *value, file; + ngx_cidr_t cidr; ngx_http_geo_conf_ctx_t *ctx; ctx = cf->ctx; @@ -394,6 +451,16 @@ ngx_http_geo(ngx_conf_t *cf, ngx_command rv = ngx_conf_parse(cf, &file); goto done; + + } else if (ngx_strcmp(value[0].data, "proxy") == 0) { + + if (ngx_http_geo_cidr_value(cf, &value[1], &cidr) != NGX_OK) { + goto failed; + } + + rv = ngx_http_geo_add_proxy(cf, ctx, &cidr); + + goto done; } if (ctx->high) { @@ -803,33 +870,8 @@ ngx_http_geo_cidr(ngx_conf_t *cf, ngx_ht del = 0; } - if (ngx_strcmp(net->data, "255.255.255.255") == 0) { - cidr.u.in.addr = 0xffffffff; - cidr.u.in.mask = 0xffffffff; - - } else { - rc = ngx_ptocidr(net, &cidr); - - if (rc == NGX_ERROR) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid network \"%V\"", net); - return NGX_CONF_ERROR; - } - - if (cidr.family != AF_INET) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"geo\" supports IPv4 only"); - return NGX_CONF_ERROR; - } - - if (rc == NGX_DONE) { - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "low address bits of %V are meaningless", - net); - } - - cidr.u.in.addr = ntohl(cidr.u.in.addr); - cidr.u.in.mask = ntohl(cidr.u.in.mask); + if (ngx_http_geo_cidr_value(cf, net, &cidr) != NGX_OK) { + return NGX_CONF_ERROR; } if (del) { @@ -864,7 +906,7 @@ ngx_http_geo_cidr(ngx_conf_t *cf, ngx_ht /* rc == NGX_BUSY */ - old = (ngx_http_variable_value_t *) + old = (ngx_http_variable_value_t *) ngx_radix32tree_find(ctx->tree, cidr.u.in.addr & cidr.u.in.mask); ngx_conf_log_error(NGX_LOG_WARN, cf, 0, @@ -927,3 +969,64 @@ ngx_http_geo_value(ngx_conf_t *cf, ngx_h return val; } + + +static char * +ngx_http_geo_add_proxy(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, + ngx_cidr_t *cidr) +{ + ngx_in_cidr_t *c; + + if (ctx->proxies == NULL) { + ctx->proxies = ngx_array_create(ctx->pool, 4, sizeof(ngx_in_cidr_t)); + if (ctx->proxies == NULL) { + return NGX_CONF_ERROR; + } + } + + c = ngx_array_push(ctx->proxies); + if (c == NULL) { + return NGX_CONF_ERROR; + } + + c->addr = cidr->u.in.addr; + c->mask = cidr->u.in.mask; + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_geo_cidr_value(ngx_conf_t *cf, ngx_str_t *net, ngx_cidr_t *cidr) +{ + ngx_int_t rc; + + if (ngx_strcmp(net->data, "255.255.255.255") == 0) { + cidr->u.in.addr = 0xffffffff; + cidr->u.in.mask = 0xffffffff; + + return NGX_OK; + } + + rc = ngx_ptocidr(net, cidr); + + if (rc == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid network \"%V\"", net); + return NGX_ERROR; + } + + if (cidr->family != AF_INET) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"geo\" supports IPv4 only"); + return NGX_ERROR; + } + + if (rc == NGX_DONE) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "low address bits of %V are meaningless", net); + } + + cidr->u.in.addr = ntohl(cidr->u.in.addr); + cidr->u.in.mask = ntohl(cidr->u.in.mask); + + return NGX_OK; +} diff --git a/src/http/modules/ngx_http_geoip_module.c b/src/http/modules/ngx_http_geoip_module.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_geoip_module.c @@ -0,0 +1,376 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + +#include +#include + + +typedef struct { + GeoIP *country; + GeoIP *city; +} ngx_http_geoip_conf_t; + + +typedef struct { + ngx_str_t *name; + uintptr_t data; +} ngx_http_geoip_var_t; + + +typedef const char *(*ngx_http_geoip_variable_handler_pt)(GeoIP *, u_long addr); + +static ngx_int_t ngx_http_geoip_country_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_geoip_city_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); + +static ngx_int_t ngx_http_geoip_add_variables(ngx_conf_t *cf); +static void *ngx_http_geoip_create_conf(ngx_conf_t *cf); +static char *ngx_http_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_http_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static void ngx_http_geoip_cleanup(void *data); + + +static ngx_command_t ngx_http_geoip_commands[] = { + + { ngx_string("geoip_country"), + NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, + ngx_http_geoip_country, + NGX_HTTP_MAIN_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("geoip_city"), + NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, + ngx_http_geoip_city, + NGX_HTTP_MAIN_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_geoip_module_ctx = { + ngx_http_geoip_add_variables, /* preconfiguration */ + NULL, /* postconfiguration */ + + ngx_http_geoip_create_conf, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + NULL, /* create location configuration */ + NULL /* merge location configuration */ +}; + + +ngx_module_t ngx_http_geoip_module = { + NGX_MODULE_V1, + &ngx_http_geoip_module_ctx, /* module context */ + ngx_http_geoip_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_variable_t ngx_http_geoip_vars[] = { + + { ngx_string("geoip_country_code"), NULL, ngx_http_geoip_country_variable, + (uintptr_t) GeoIP_country_code_by_ipnum, 0, 0 }, + + { ngx_string("geoip_country_code3"), NULL, ngx_http_geoip_country_variable, + (uintptr_t) GeoIP_country_code3_by_ipnum, 0, 0 }, + + { ngx_string("geoip_country_name"), NULL, ngx_http_geoip_country_variable, + (uintptr_t) GeoIP_country_name_by_ipnum, 0, 0 }, + + { ngx_string("geoip_city_country_code"), NULL, ngx_http_geoip_city_variable, + offsetof(GeoIPRecord, country_code), 0, 0 }, + + { ngx_string("geoip_city_country_code3"), NULL, + ngx_http_geoip_city_variable, + offsetof(GeoIPRecord, country_code3), 0, 0 }, + + { ngx_string("geoip_city_country_name"), NULL, ngx_http_geoip_city_variable, + offsetof(GeoIPRecord, country_name), 0, 0 }, + + { ngx_string("geoip_region"), NULL, + ngx_http_geoip_city_variable, + offsetof(GeoIPRecord, region), 0, 0 }, + + { ngx_string("geoip_city"), NULL, + ngx_http_geoip_city_variable, + offsetof(GeoIPRecord, city), 0, 0 }, + + { ngx_string("geoip_postal_code"), NULL, + ngx_http_geoip_city_variable, + offsetof(GeoIPRecord, postal_code), 0, 0 }, + + { ngx_null_string, NULL, NULL, 0, 0, 0 } +}; + + +static ngx_int_t +ngx_http_geoip_country_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + ngx_http_geoip_variable_handler_pt handler = + (ngx_http_geoip_variable_handler_pt) data; + + u_long addr; + const char *val; + struct sockaddr_in *sin; + ngx_http_geoip_conf_t *gcf; + + gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module); + + if (gcf->country == NULL) { + goto not_found; + } + + if (r->connection->sockaddr->sa_family != AF_INET) { + goto not_found; + } + + sin = (struct sockaddr_in *) r->connection->sockaddr; + addr = ntohl(sin->sin_addr.s_addr); + + val = handler(gcf->country, addr); + + if (val == NULL) { + goto not_found; + } + + v->len = ngx_strlen(val); + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = (u_char *) val; + + return NGX_OK; + +not_found: + + v->not_found = 1; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_geoip_city_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + u_long addr; + char *val; + size_t len; + GeoIPRecord *gr; + struct sockaddr_in *sin; + ngx_http_geoip_conf_t *gcf; + + gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module); + + if (gcf->city == NULL) { + goto not_found; + } + + if (r->connection->sockaddr->sa_family != AF_INET) { + goto not_found; + } + + sin = (struct sockaddr_in *) r->connection->sockaddr; + addr = ntohl(sin->sin_addr.s_addr); + + gr = GeoIP_record_by_ipnum(gcf->city, addr); + + if (gr == NULL) { + goto not_found; + } + + val = *(char **) ((char *) gr + data); + + if (val == NULL) { + goto no_value; + } + + len = ngx_strlen(val); + v->data = ngx_pnalloc(r->pool, len); + + if (v->data == NULL) { + GeoIPRecord_delete(gr); + return NGX_ERROR; + } + + ngx_memcpy(v->data, val, len); + + v->len = len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + GeoIPRecord_delete(gr); + + return NGX_OK; + +no_value: + + GeoIPRecord_delete(gr); + +not_found: + + v->not_found = 1; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_geoip_add_variables(ngx_conf_t *cf) +{ + ngx_http_variable_t *var, *v; + + for (v = ngx_http_geoip_vars; v->name.len; v++) { + var = ngx_http_add_variable(cf, &v->name, v->flags); + if (var == NULL) { + return NGX_ERROR; + } + + var->get_handler = v->get_handler; + var->data = v->data; + } + + return NGX_OK; +} + + +static void * +ngx_http_geoip_create_conf(ngx_conf_t *cf) +{ + ngx_pool_cleanup_t *cln; + ngx_http_geoip_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_geoip_conf_t)); + if (conf == NULL) { + return NULL; + } + + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NULL; + } + + cln->handler = ngx_http_geoip_cleanup; + cln->data = conf; + + return conf; +} + + +static char * +ngx_http_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_geoip_conf_t *gcf = conf; + + ngx_str_t *value; + + if (gcf->country) { + return "is duplicate"; + } + + value = cf->args->elts; + + gcf->country = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE); + + if (gcf->country == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "GeoIO_open(\"%V\") failed", &value[1]); + + return NGX_CONF_ERROR; + } + + switch (gcf->country->databaseType) { + + case GEOIP_COUNTRY_EDITION: + case GEOIP_PROXY_EDITION: + case GEOIP_NETSPEED_EDITION: + + return NGX_CONF_OK; + + default: + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid GeoIP database \"%V\" type:%d", + &value[1], gcf->country->databaseType); + return NGX_CONF_ERROR; + } +} + + +static char * +ngx_http_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_geoip_conf_t *gcf = conf; + + ngx_str_t *value; + + if (gcf->city) { + return "is duplicate"; + } + + value = cf->args->elts; + + gcf->city = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE); + + if (gcf->city == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "GeoIO_open(\"%V\") failed", &value[1]); + + return NGX_CONF_ERROR; + } + + switch (gcf->city->databaseType) { + + case GEOIP_CITY_EDITION_REV0: + case GEOIP_CITY_EDITION_REV1: + + return NGX_CONF_OK; + + default: + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid GeoIP City database \"%V\" type:%d", + &value[1], gcf->city->databaseType); + return NGX_CONF_ERROR; + } +} + + +static void +ngx_http_geoip_cleanup(void *data) +{ + ngx_http_geoip_conf_t *gcf = data; + + if (gcf->country) { + GeoIP_delete(gcf->country); + } + + if (gcf->city) { + GeoIP_delete(gcf->city); + } +} diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c --- a/src/http/modules/ngx_http_gzip_filter_module.c +++ b/src/http/modules/ngx_http_gzip_filter_module.c @@ -1069,7 +1069,7 @@ ngx_http_gzip_create_conf(ngx_conf_t *cf conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_gzip_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* 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 @@ -95,7 +95,13 @@ ngx_http_gzip_static_handler(ngx_http_re gzcf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_static_module); - if (!gzcf->enable || ngx_http_gzip_ok(r) != NGX_OK) { + if (!gzcf->enable) { + return NGX_DECLINED; + } + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (clcf->gzip_vary && ngx_http_gzip_ok(r) != NGX_OK) { return NGX_DECLINED; } @@ -116,8 +122,6 @@ ngx_http_gzip_static_handler(ngx_http_re ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http filename: \"%s\"", path.data); - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.directio = clcf->directio; @@ -138,6 +142,7 @@ ngx_http_gzip_static_handler(ngx_http_re case NGX_ENOTDIR: case NGX_ENAMETOOLONG: + r->gzip = 0; return NGX_DECLINED; case NGX_EACCES: @@ -251,7 +256,7 @@ ngx_http_gzip_static_create_conf(ngx_con conf = ngx_palloc(cf->pool, sizeof(ngx_http_gzip_static_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } conf->enable = NGX_CONF_UNSET; diff --git a/src/http/modules/ngx_http_headers_filter_module.c b/src/http/modules/ngx_http_headers_filter_module.c --- a/src/http/modules/ngx_http_headers_filter_module.c +++ b/src/http/modules/ngx_http_headers_filter_module.c @@ -421,7 +421,7 @@ ngx_http_headers_create_conf(ngx_conf_t conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_headers_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* 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 @@ -40,6 +40,11 @@ typedef struct { ngx_uint_t height; ngx_int_t jpeg_quality; + ngx_flag_t transparency; + + ngx_http_complex_value_t *wcv; + ngx_http_complex_value_t *hcv; + size_t buffer_size; } ngx_http_image_filter_conf_t; @@ -53,6 +58,9 @@ typedef struct { ngx_uint_t width; ngx_uint_t height; + ngx_uint_t max_width; + ngx_uint_t max_height; + ngx_uint_t phase; ngx_uint_t type; } ngx_http_image_filter_ctx_t; @@ -80,6 +88,9 @@ static gdImagePtr ngx_http_image_new(ngx static u_char *ngx_http_image_out(ngx_http_request_t *r, ngx_uint_t type, gdImagePtr img, int *size); static void ngx_http_image_cleanup(void *data); +static ngx_uint_t ngx_http_image_filter_get_value(ngx_http_request_t *r, + ngx_http_complex_value_t *cv, ngx_uint_t v); +static ngx_uint_t ngx_http_image_filter_value(ngx_str_t *value); static void *ngx_http_image_filter_create_conf(ngx_conf_t *cf); @@ -106,6 +117,13 @@ static ngx_command_t ngx_http_image_fil offsetof(ngx_http_image_filter_conf_t, jpeg_quality), 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, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_image_filter_conf_t, transparency), + NULL }, + { ngx_string("image_filter_buffer"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, @@ -454,7 +472,6 @@ ngx_http_image_read(ngx_http_request_t * static ngx_buf_t * ngx_http_image_process(ngx_http_request_t *r) { - ngx_buf_t *b; ngx_int_t rc; ngx_http_image_filter_ctx_t *ctx; ngx_http_image_filter_conf_t *conf; @@ -468,20 +485,28 @@ ngx_http_image_process(ngx_http_request_ conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module); if (conf->filter == NGX_HTTP_IMAGE_SIZE) { - - b = ngx_http_image_json(r, rc == NGX_OK ? ctx : NULL); + return ngx_http_image_json(r, rc == NGX_OK ? ctx : NULL); + } - } else if (rc == NGX_OK - && ctx->width <= conf->width - && ctx->height <= conf->height) - { - b = ngx_http_image_asis(r, ctx); - - } else { - b = ngx_http_image_resize(r, ctx); + ctx->max_width = ngx_http_image_filter_get_value(r, conf->wcv, conf->width); + if (ctx->max_width == 0) { + return NULL; } - return b; + ctx->max_height = ngx_http_image_filter_get_value(r, conf->hcv, + conf->height); + if (ctx->max_height == 0) { + return NULL; + } + + if (rc == NGX_OK + && ctx->width <= ctx->max_width + && ctx->height <= ctx->max_height) + { + return ngx_http_image_asis(r, ctx); + } + + return ngx_http_image_resize(r, ctx); } @@ -662,8 +687,9 @@ ngx_http_image_size(ngx_http_request_t * 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, - colors, transparent, size; + int sx, sy, dx, dy, ox, oy, size, + colors, palette, transparent, + red, green, blue; u_char *out; ngx_buf_t *b; ngx_uint_t resize; @@ -682,29 +708,53 @@ ngx_http_image_resize(ngx_http_request_t conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module); - if ((ngx_uint_t) sx <= conf->width && (ngx_uint_t) sy <= conf->height) { + if ((ngx_uint_t) sx <= ctx->max_width + && (ngx_uint_t) sy <= ctx->max_height) + { gdImageDestroy(src); return ngx_http_image_asis(r, ctx); } colors = gdImageColorsTotal(src); - transparent = gdImageGetTransparent(src); + + if (colors && conf->transparency) { + transparent = gdImageGetTransparent(src); + + if (transparent != -1) { + palette = colors; + red = gdImageRed(src, transparent); + green = gdImageGreen(src, transparent); + blue = gdImageBlue(src, transparent); + + goto transparent; + } + } + + palette = 0; + transparent = -1; + red = 0; + green = 0; + blue = 0; + +transparent: + + gdImageColorTransparent(src, -1); dx = sx; dy = sy; if (conf->filter == NGX_HTTP_IMAGE_RESIZE) { - if ((ngx_uint_t) dx > conf->width) { - dy = dy * conf->width / dx; + if ((ngx_uint_t) dx > ctx->max_width) { + dy = dy * ctx->max_width / dx; dy = dy ? dy : 1; - dx = conf->width; + dx = ctx->max_width; } - if ((ngx_uint_t) dy > conf->height) { - dx = dx * conf->height / dy; + if ((ngx_uint_t) dy > ctx->max_height) { + dx = dx * ctx->max_height / dy; dx = dx ? dx : 1; - dy = conf->height; + dy = ctx->max_height; } resize = 1; @@ -713,34 +763,44 @@ ngx_http_image_resize(ngx_http_request_t resize = 0; - if ((ngx_uint_t) (dx * 100 / dy) < conf->width * 100 / conf->height) { - - if ((ngx_uint_t) dx > conf->width) { - dy = dy * conf->width / dx; + if ((ngx_uint_t) (dx * 100 / dy) + < ctx->max_width * 100 / ctx->max_height) + { + if ((ngx_uint_t) dx > ctx->max_width) { + dy = dy * ctx->max_width / dx; dy = dy ? dy : 1; - dx = conf->width; + dx = ctx->max_width; resize = 1; } } else { - if ((ngx_uint_t) dy > conf->height) { - dx = dx * conf->height / dy; + if ((ngx_uint_t) dy > ctx->max_height) { + dx = dx * ctx->max_height / dy; dx = dx ? dx : 1; - dy = conf->height; + dy = ctx->max_height; resize = 1; } } } if (resize) { - dst = ngx_http_image_new(r, dx, dy, colors); + dst = ngx_http_image_new(r, dx, dy, palette); if (dst == NULL) { gdImageDestroy(src); return NULL; } + if (colors == 0) { + gdImageSaveAlpha(dst, 1); + gdImageAlphaBlending(dst, 0); + } + gdImageCopyResampled(dst, src, 0, 0, 0, 0, dx, dy, sx, sy); + if (colors) { + gdImageTrueColorToPalette(dst, 1, 256); + } + gdImageDestroy(src); } else { @@ -751,15 +811,15 @@ ngx_http_image_resize(ngx_http_request_t src = dst; - if ((ngx_uint_t) dx > conf->width) { - ox = dx - conf->width; + if ((ngx_uint_t) dx > ctx->max_width) { + ox = dx - ctx->max_width; } else { ox = 0; } - if ((ngx_uint_t) dy > conf->height) { - oy = dy - conf->height; + if ((ngx_uint_t) dy > ctx->max_height) { + oy = dy - ctx->max_height; } else { oy = 0; @@ -781,13 +841,24 @@ ngx_http_image_resize(ngx_http_request_t "image crop: %d x %d @ %d x %d", dx, dy, ox, oy); + if (colors == 0) { + gdImageSaveAlpha(dst, 1); + gdImageAlphaBlending(dst, 0); + } + gdImageCopy(dst, src, 0, 0, ox, oy, dx - ox, dy - oy); + if (colors) { + gdImageTrueColorToPalette(dst, 1, 256); + } + gdImageDestroy(src); } } - gdImageColorTransparent(dst, transparent); + if (transparent != -1 && colors) { + gdImageColorTransparent(dst, gdImageColorExact(dst, red, green, blue)); + } out = ngx_http_image_out(r, ctx->type, dst, &size); @@ -941,6 +1012,43 @@ ngx_http_image_cleanup(void *data) } +static ngx_uint_t +ngx_http_image_filter_get_value(ngx_http_request_t *r, + ngx_http_complex_value_t *cv, ngx_uint_t v) +{ + ngx_str_t val; + + if (cv == NULL) { + return v; + } + + if (ngx_http_complex_value(r, cv, &val) != NGX_OK) { + return 0; + } + + return ngx_http_image_filter_value(&val); +} + + +static ngx_uint_t +ngx_http_image_filter_value(ngx_str_t *value) +{ + ngx_int_t n; + + if (value->len == 1 && value->data[0] == '-') { + return (ngx_uint_t) -1; + } + + n = ngx_atoi(value->data, value->len); + + if (n > 0) { + return (ngx_uint_t) n; + } + + return 0; +} + + static void * ngx_http_image_filter_create_conf(ngx_conf_t *cf) { @@ -948,11 +1056,12 @@ ngx_http_image_filter_create_conf(ngx_co conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_image_filter_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } conf->filter = NGX_CONF_UNSET_UINT; conf->jpeg_quality = NGX_CONF_UNSET; + conf->transparency = NGX_CONF_UNSET; conf->buffer_size = NGX_CONF_UNSET_SIZE; return conf; @@ -974,12 +1083,16 @@ ngx_http_image_filter_merge_conf(ngx_con conf->filter = prev->filter; conf->width = prev->width; conf->height = prev->height; + conf->wcv = prev->wcv; + conf->hcv = prev->hcv; } } /* 75 is libjpeg default quality */ ngx_conf_merge_value(conf->jpeg_quality, prev->jpeg_quality, 75); + ngx_conf_merge_value(conf->transparency, prev->transparency, 1); + ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, 1 * 1024 * 1024); @@ -992,9 +1105,11 @@ ngx_http_image_filter(ngx_conf_t *cf, ng { ngx_http_image_filter_conf_t *imcf = conf; - ngx_str_t *value; - ngx_int_t n; - ngx_uint_t i; + ngx_str_t *value; + ngx_int_t n; + ngx_uint_t i; + ngx_http_complex_value_t cv; + ngx_http_compile_complex_value_t ccv; value = cf->args->elts; @@ -1027,32 +1142,60 @@ ngx_http_image_filter(ngx_conf_t *cf, ng goto failed; } - i++; + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[++i]; + ccv.complex_value = &cv; - if (value[i].len == 1 && value[i].data[0] == '-') { - imcf->width = (ngx_uint_t) -1; + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } - } else { - n = ngx_atoi(value[i].data, value[i].len); - if (n == NGX_ERROR) { + if (cv.lengths == NULL) { + n = ngx_http_image_filter_value(&value[i]); + + if (n == 0) { goto failed; } imcf->width = (ngx_uint_t) n; + + } else { + imcf->wcv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t)); + if (imcf->wcv == NULL) { + return NGX_CONF_ERROR; + } + + *imcf->wcv = cv; } - i++; + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[++i]; + ccv.complex_value = &cv; - if (value[i].len == 1 && value[i].data[0] == '-') { - imcf->height = (ngx_uint_t) -1; + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } - } else { - n = ngx_atoi(value[i].data, value[i].len); - if (n == NGX_ERROR) { + if (cv.lengths == NULL) { + n = ngx_http_image_filter_value(&value[i]); + + if (n == 0) { goto failed; } imcf->height = (ngx_uint_t) n; + + } else { + imcf->hcv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t)); + if (imcf->hcv == NULL) { + return NGX_CONF_ERROR; + } + + *imcf->hcv = cv; } return NGX_CONF_OK; diff --git a/src/http/modules/ngx_http_index_module.c b/src/http/modules/ngx_http_index_module.c --- a/src/http/modules/ngx_http_index_module.c +++ b/src/http/modules/ngx_http_index_module.c @@ -366,7 +366,7 @@ ngx_http_index_create_loc_conf(ngx_conf_ conf = ngx_palloc(cf->pool, sizeof(ngx_http_index_loc_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } conf->indices = NULL; 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 @@ -42,7 +42,10 @@ typedef struct { ngx_shm_zone_t *shm_zone; /* integer value, 1 corresponds to 0.001 r/s */ ngx_uint_t burst; - ngx_uint_t nodelay;/* unsigned nodelay:1 */ + ngx_uint_t limit_log_level; + ngx_uint_t delay_log_level; + + ngx_uint_t nodelay; /* unsigned nodelay:1 */ } ngx_http_limit_req_conf_t; @@ -62,6 +65,15 @@ static char *ngx_http_limit_req(ngx_conf static ngx_int_t ngx_http_limit_req_init(ngx_conf_t *cf); +static ngx_conf_enum_t ngx_http_limit_req_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_req_commands[] = { { ngx_string("limit_req_zone"), @@ -78,6 +90,13 @@ static ngx_command_t ngx_http_limit_req 0, NULL }, + { ngx_string("limit_req_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_req_conf_t, limit_log_level), + &ngx_http_limit_req_log_levels }, + ngx_null_command }; @@ -181,12 +200,12 @@ ngx_http_limit_req_handler(ngx_http_requ } ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "limit_req: %i %ui.%03ui", rc, excess / 1000, excess % 1000); + "limit_req: %i %ui.%03ui", rc, excess / 1000, excess % 1000); if (rc == NGX_BUSY) { ngx_shmtx_unlock(&ctx->shpool->mutex); - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + ngx_log_error(lrcf->limit_log_level, r->connection->log, 0, "limiting requests, excess: %ui.%03ui by zone \"%V\"", excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name); @@ -200,7 +219,7 @@ ngx_http_limit_req_handler(ngx_http_requ return NGX_DECLINED; } - ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + ngx_log_error(lrcf->delay_log_level, r->connection->log, 0, "delaying request, excess: %ui.%03ui, by zone \"%V\"", excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name); @@ -263,8 +282,23 @@ done: static void ngx_http_limit_req_delay(ngx_http_request_t *r) { + ngx_event_t *wev; + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "limit_req delay"); + "limit_req delay"); + + wev = r->connection->write; + + if (!wev->timedout) { + + if (ngx_handle_write_event(wev, 0) != NGX_OK) { + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + } + + return; + } + + wev->timedout = 0; if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); @@ -368,15 +402,16 @@ ngx_http_limit_req_lookup(ngx_http_limit excess = 0; } + if ((ngx_uint_t) excess > lrcf->burst) { + *lrp = lr; + return NGX_BUSY; + } + lr->excess = excess; lr->last = now; *lrp = lr; - if ((ngx_uint_t) excess > lrcf->burst) { - return NGX_BUSY; - } - if (excess) { return NGX_AGAIN; } @@ -522,7 +557,7 @@ ngx_http_limit_req_create_conf(ngx_conf_ conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_req_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* @@ -533,6 +568,8 @@ ngx_http_limit_req_create_conf(ngx_conf_ * conf->nodelay = 0; */ + conf->limit_log_level = NGX_CONF_UNSET_UINT; + return conf; } @@ -547,6 +584,12 @@ ngx_http_limit_req_merge_conf(ngx_conf_t *conf = *prev; } + ngx_conf_merge_uint_value(conf->limit_log_level, prev->limit_log_level, + NGX_LOG_ERR); + + conf->delay_log_level = (conf->limit_log_level == NGX_LOG_INFO) ? + NGX_LOG_INFO : conf->limit_log_level + 1; + return NGX_CONF_OK; } diff --git a/src/http/modules/ngx_http_limit_zone_module.c b/src/http/modules/ngx_http_limit_zone_module.c --- a/src/http/modules/ngx_http_limit_zone_module.c +++ b/src/http/modules/ngx_http_limit_zone_module.c @@ -33,6 +33,7 @@ typedef struct { typedef struct { ngx_shm_zone_t *shm_zone; ngx_uint_t conn; + ngx_uint_t log_level; } ngx_http_limit_zone_conf_t; @@ -48,6 +49,15 @@ static char *ngx_http_limit_conn(ngx_con 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"), @@ -64,6 +74,13 @@ static ngx_command_t ngx_http_limit_zon 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 }; @@ -189,7 +206,7 @@ ngx_http_limit_zone_handler(ngx_http_req ngx_shmtx_unlock(&shpool->mutex); - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + ngx_log_error(lzcf->log_level, r->connection->log, 0, "limiting connections by zone \"%V\"", &lzcf->shm_zone->shm.name); @@ -381,7 +398,7 @@ ngx_http_limit_zone_create_conf(ngx_conf conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_zone_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* @@ -391,6 +408,8 @@ ngx_http_limit_zone_create_conf(ngx_conf * conf->conn = 0; */ + conf->log_level = NGX_CONF_UNSET_UINT; + return conf; } @@ -405,6 +424,8 @@ ngx_http_limit_zone_merge_conf(ngx_conf_ *conf = *prev; } + ngx_conf_merge_uint_value(conf->log_level, prev->log_level, NGX_LOG_ERR); + return NGX_CONF_OK; } diff --git a/src/http/modules/ngx_http_log_module.c b/src/http/modules/ngx_http_log_module.c --- a/src/http/modules/ngx_http_log_module.c +++ b/src/http/modules/ngx_http_log_module.c @@ -676,7 +676,7 @@ ngx_http_log_escape(u_char *dst, u_char /* find the number of the characters to be escaped */ - n = 0; + n = 0; for (i = 0; i < size; i++) { if (escape[*src >> 5] & (1 << (*src & 0x1f))) { @@ -714,18 +714,18 @@ ngx_http_log_create_main_conf(ngx_conf_t conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_main_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } if (ngx_array_init(&conf->formats, cf->pool, 4, sizeof(ngx_http_log_fmt_t)) != NGX_OK) { - return NGX_CONF_ERROR; + return NULL; } fmt = ngx_array_push(&conf->formats); if (fmt == NULL) { - return NGX_CONF_ERROR; + return NULL; } fmt->name.len = sizeof("combined") - 1; @@ -735,7 +735,7 @@ ngx_http_log_create_main_conf(ngx_conf_t fmt->ops = ngx_array_create(cf->pool, 16, sizeof(ngx_http_log_op_t)); if (fmt->ops == NULL) { - return NGX_CONF_ERROR; + return NULL; } return conf; @@ -749,7 +749,7 @@ ngx_http_log_create_loc_conf(ngx_conf_t conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_loc_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } conf->open_file_cache = NGX_CONF_UNSET_PTR; 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 @@ -160,7 +160,7 @@ ngx_http_map_create_conf(ngx_conf_t *cf) mcf = ngx_palloc(cf->pool, sizeof(ngx_http_map_conf_t)); if (mcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } mcf->hash_max_size = NGX_CONF_UNSET_UINT; 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 @@ -176,23 +176,18 @@ ngx_http_memcached_handler(ngx_http_requ return NGX_HTTP_INTERNAL_SERVER_ERROR; } - mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module); - - u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t)); - if (u == NULL) { + if (ngx_http_upstream_create(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } + u = r->upstream; + u->schema.len = sizeof("memcached://") - 1; u->schema.data = (u_char *) "memcached://"; - u->peer.log = r->connection->log; - u->peer.log_error = NGX_ERROR_ERR; -#if (NGX_THREADS) - u->peer.lock = &r->connection->lock; -#endif + u->output.tag = (ngx_buf_tag_t) &ngx_http_memcached_module; - u->output.tag = (ngx_buf_tag_t) &ngx_http_memcached_module; + mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module); u->conf = &mlcf->upstream; @@ -202,8 +197,6 @@ ngx_http_memcached_handler(ngx_http_requ u->abort_request = ngx_http_memcached_abort_request; u->finalize_request = ngx_http_memcached_finalize_request; - r->upstream = u; - ctx = ngx_palloc(r->pool, sizeof(ngx_http_memcached_ctx_t)); if (ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; @@ -513,7 +506,7 @@ ngx_http_memcached_create_loc_conf(ngx_c conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_memcached_loc_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* 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 @@ -590,13 +590,10 @@ ngx_http_proxy_handler(ngx_http_request_ ngx_http_proxy_ctx_t *ctx; ngx_http_proxy_loc_conf_t *plcf; - u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t)); - if (u == NULL) { + if (ngx_http_upstream_create(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } - r->upstream = u; - ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_ctx_t)); if (ctx == NULL) { return NGX_ERROR; @@ -606,6 +603,8 @@ ngx_http_proxy_handler(ngx_http_request_ plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); + u = r->upstream; + if (plcf->proxy_lengths == 0) { ctx->vars = plcf->vars; u->schema = plcf->vars.schema; @@ -619,12 +618,6 @@ ngx_http_proxy_handler(ngx_http_request_ } } - u->peer.log = r->connection->log; - u->peer.log_error = NGX_ERROR_ERR; -#if (NGX_THREADS) - u->peer.lock = &r->connection->lock; -#endif - u->output.tag = (ngx_buf_tag_t) &ngx_http_proxy_module; u->conf = &plcf->upstream; @@ -1884,7 +1877,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_ conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* diff --git a/src/http/modules/ngx_http_random_index_module.c b/src/http/modules/ngx_http_random_index_module.c --- a/src/http/modules/ngx_http_random_index_module.c +++ b/src/http/modules/ngx_http_random_index_module.c @@ -280,7 +280,7 @@ ngx_http_random_index_create_loc_conf(ng conf = ngx_palloc(cf->pool, sizeof(ngx_http_random_index_loc_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } conf->enable = NGX_CONF_UNSET; diff --git a/src/http/modules/ngx_http_realip_module.c b/src/http/modules/ngx_http_realip_module.c --- a/src/http/modules/ngx_http_realip_module.c +++ b/src/http/modules/ngx_http_realip_module.c @@ -360,7 +360,7 @@ ngx_http_realip_create_loc_conf(ngx_conf conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_realip_loc_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* diff --git a/src/http/modules/ngx_http_referer_module.c b/src/http/modules/ngx_http_referer_module.c --- a/src/http/modules/ngx_http_referer_module.c +++ b/src/http/modules/ngx_http_referer_module.c @@ -221,7 +221,7 @@ ngx_http_referer_create_conf(ngx_conf_t conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_referer_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } #if (NGX_PCRE) diff --git a/src/http/modules/ngx_http_rewrite_module.c b/src/http/modules/ngx_http_rewrite_module.c --- a/src/http/modules/ngx_http_rewrite_module.c +++ b/src/http/modules/ngx_http_rewrite_module.c @@ -220,7 +220,7 @@ ngx_http_rewrite_create_loc_conf(ngx_con conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_rewrite_loc_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } conf->stack_size = NGX_CONF_UNSET_UINT; @@ -446,7 +446,7 @@ ngx_http_rewrite(ngx_conf_t *cf, ngx_com return NGX_CONF_ERROR; } - *code = (uintptr_t) NULL; + *code = NULL; } regex->next = (u_char *) lcf->codes->elts + lcf->codes->nelts @@ -568,7 +568,7 @@ ngx_http_rewrite_if(ngx_conf_t *cf, ngx_ if_code = ngx_array_push_n(lcf->codes, sizeof(ngx_http_script_if_code_t)); if (if_code == NULL) { - return NULL; + return NGX_CONF_ERROR; } if_code->code = ngx_http_script_if_code; diff --git a/src/http/modules/ngx_http_secure_link_module.c b/src/http/modules/ngx_http_secure_link_module.c --- a/src/http/modules/ngx_http_secure_link_module.c +++ b/src/http/modules/ngx_http_secure_link_module.c @@ -152,7 +152,7 @@ ngx_http_secure_link_create_conf(ngx_con conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_secure_link_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* 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 @@ -360,6 +360,7 @@ ngx_http_ssi_header_filter(ngx_http_requ if (r == r->main) { ngx_http_clear_content_length(r); ngx_http_clear_last_modified(r); + ngx_http_clear_accept_ranges(r); } return ngx_http_next_header_filter(r); @@ -1907,7 +1908,7 @@ ngx_http_ssi_include(ngx_http_request_t args.len = 0; args.data = NULL; - flags = 0; + flags = NGX_HTTP_LOG_UNSAFE; if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) { return NGX_HTTP_SSI_ERROR; @@ -2689,14 +2690,14 @@ ngx_http_ssi_create_main_conf(ngx_conf_t smcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssi_main_conf_t)); if (smcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } smcf->commands.pool = cf->pool; smcf->commands.temp_pool = cf->temp_pool; if (ngx_hash_keys_array_init(&smcf->commands, NGX_HASH_SMALL) != NGX_OK) { - return NGX_CONF_ERROR; + return NULL; } return smcf; @@ -2736,7 +2737,7 @@ ngx_http_ssi_create_loc_conf(ngx_conf_t slcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssi_loc_conf_t)); if (slcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* 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 @@ -31,15 +31,6 @@ static char *ngx_http_ssl_enable(ngx_con static char *ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -#if !defined (SSL_OP_CIPHER_SERVER_PREFERENCE) - -static char *ngx_http_ssl_nosupported(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); - -static char ngx_http_ssl_openssl097[] = "OpenSSL 0.9.7 and higher"; - -#endif - static ngx_conf_bitmask_t ngx_http_ssl_protocols[] = { { ngx_string("SSLv2"), NGX_SSL_SSLv2 }, @@ -52,7 +43,7 @@ static ngx_conf_bitmask_t ngx_http_ssl_ static ngx_conf_enum_t ngx_http_ssl_verify[] = { { ngx_string("off"), 0 }, { ngx_string("on"), 1 }, - { ngx_string("ask"), 2 }, + { ngx_string("optional"), 2 }, { ngx_null_string, 0 } }; @@ -124,14 +115,10 @@ static ngx_command_t ngx_http_ssl_comma { ngx_string("ssl_prefer_server_ciphers"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, -#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE ngx_conf_set_flag_slot, NGX_HTTP_SRV_CONF_OFFSET, offsetof(ngx_http_ssl_srv_conf_t, prefer_server_ciphers), NULL }, -#else - ngx_http_ssl_nosupported, 0, 0, ngx_http_ssl_openssl097 }, -#endif { ngx_string("ssl_session_cache"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE12, @@ -147,6 +134,13 @@ static ngx_command_t ngx_http_ssl_comma offsetof(ngx_http_ssl_srv_conf_t, session_timeout), NULL }, + { ngx_string("ssl_crl"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_ssl_srv_conf_t, crl), + NULL }, + ngx_null_command }; @@ -206,6 +200,9 @@ static ngx_http_variable_t ngx_http_ssl { ngx_string("ssl_client_serial"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_serial_number, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("ssl_client_verify"), NULL, ngx_http_ssl_variable, + (uintptr_t) ngx_ssl_get_client_verify, NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_null_string, NULL, NULL, 0, 0, 0 } }; @@ -302,7 +299,7 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t sscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssl_srv_conf_t)); if (sscf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* @@ -313,6 +310,7 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t * sscf->certificate_key = { 0, NULL }; * sscf->dhparam = { 0, NULL }; * sscf->client_certificate = { 0, NULL }; + * sscf->crl = { 0, NULL }; * sscf->ciphers.len = 0; * sscf->ciphers.data = NULL; * sscf->shm_zone = NULL; @@ -359,6 +357,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * ngx_conf_merge_str_value(conf->client_certificate, prev->client_certificate, ""); + ngx_conf_merge_str_value(conf->crl, prev->crl, ""); ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS); @@ -407,9 +406,10 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * ngx_http_ssl_servername) == 0) { - ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, - "SSL_CTX_set_tlsext_servername_callback() failed"); - return NGX_CONF_ERROR; + ngx_log_error(NGX_LOG_WARN, cf->log, 0, + "nginx was built with SNI support, however, now it is linked " + "dynamically to an OpenSSL library which has no tlsext support, " + "therefore SNI is not available"); } #endif @@ -453,16 +453,16 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * { return NGX_CONF_ERROR; } + + if (ngx_ssl_crl(cf, &conf->ssl, &conf->crl) != NGX_OK) { + return NGX_CONF_ERROR; + } } -#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE - if (conf->prefer_server_ciphers) { SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); } -#endif - /* a temporary 512-bit RSA key is required for export versions of MSIE */ if (ngx_ssl_generate_rsa512_key(&conf->ssl) != NGX_OK) { return NGX_CONF_ERROR; @@ -620,18 +620,3 @@ invalid: return NGX_CONF_ERROR; } - - -#if !defined (SSL_OP_CIPHER_SERVER_PREFERENCE) - -static char * -ngx_http_ssl_nosupported(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"%V\" directive is available only in %s,", - &cmd->name, cmd->post); - - return NGX_CONF_ERROR; -} - -#endif diff --git a/src/http/modules/ngx_http_ssl_module.h b/src/http/modules/ngx_http_ssl_module.h --- a/src/http/modules/ngx_http_ssl_module.h +++ b/src/http/modules/ngx_http_ssl_module.h @@ -33,6 +33,7 @@ typedef struct { ngx_str_t certificate_key; ngx_str_t dhparam; ngx_str_t client_certificate; + ngx_str_t crl; ngx_str_t ciphers; diff --git a/src/http/modules/ngx_http_sub_filter_module.c b/src/http/modules/ngx_http_sub_filter_module.c --- a/src/http/modules/ngx_http_sub_filter_module.c +++ b/src/http/modules/ngx_http_sub_filter_module.c @@ -638,7 +638,7 @@ ngx_http_sub_create_conf(ngx_conf_t *cf) slcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_sub_loc_conf_t)); if (slcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* diff --git a/src/http/modules/ngx_http_userid_filter_module.c b/src/http/modules/ngx_http_userid_filter_module.c --- a/src/http/modules/ngx_http_userid_filter_module.c +++ b/src/http/modules/ngx_http_userid_filter_module.c @@ -570,7 +570,7 @@ ngx_http_userid_create_conf(ngx_conf_t * conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_userid_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* diff --git a/src/http/modules/ngx_http_xslt_filter_module.c b/src/http/modules/ngx_http_xslt_filter_module.c --- a/src/http/modules/ngx_http_xslt_filter_module.c +++ b/src/http/modules/ngx_http_xslt_filter_module.c @@ -404,7 +404,7 @@ ngx_http_xslt_add_chunk(ngx_http_request sax->endElementNs = ngx_http_xslt_sax_end_element; sax->characters = ngx_http_xslt_sax_characters; - sax->ignorableWhitespace = ngx_http_xslt_sax_characters; + sax->ignorableWhitespace = ngx_http_xslt_sax_characters; sax->cdataBlock = ngx_http_xslt_sax_cdata_block; sax->getEntity = ngx_http_xslt_sax_get_entity; sax->resolveEntity = ngx_http_xslt_sax_resolve_entity; @@ -1172,7 +1172,7 @@ ngx_http_xslt_filter_create_main_conf(ng conf = ngx_palloc(cf->pool, sizeof(ngx_http_xslt_filter_main_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } if (ngx_array_init(&conf->dtd_files, cf->pool, 1, @@ -1200,7 +1200,7 @@ ngx_http_xslt_filter_create_conf(ngx_con conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_xslt_filter_loc_conf_t)); if (conf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* 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 @@ -47,7 +47,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '0.7.62'; +our $VERSION = '0.7.63'; require XSLoader; XSLoader::load('nginx', $VERSION); diff --git a/src/http/modules/perl/ngx_http_perl_module.c b/src/http/modules/perl/ngx_http_perl_module.c --- a/src/http/modules/perl/ngx_http_perl_module.c +++ b/src/http/modules/perl/ngx_http_perl_module.c @@ -13,8 +13,8 @@ typedef struct { PerlInterpreter *perl; HV *nginx; - ngx_str_t modules; - ngx_array_t requires; + ngx_array_t *modules; + ngx_array_t *requires; } ngx_http_perl_main_conf_t; @@ -57,8 +57,6 @@ static char *ngx_http_perl_init_main_con static void *ngx_http_perl_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_perl_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child); -static char *ngx_http_perl_require(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); static char *ngx_http_perl(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_perl_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -74,16 +72,16 @@ static ngx_command_t ngx_http_perl_comm { ngx_string("perl_modules"), NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_conf_set_str_array_slot, NGX_HTTP_MAIN_CONF_OFFSET, offsetof(ngx_http_perl_main_conf_t, modules), NULL }, { ngx_string("perl_require"), NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, - ngx_http_perl_require, + ngx_conf_set_str_array_slot, NGX_HTTP_MAIN_CONF_OFFSET, - 0, + offsetof(ngx_http_perl_main_conf_t, requires), NULL }, { ngx_string("perl"), @@ -458,8 +456,10 @@ ngx_http_perl_ssi(ngx_http_request_t *r, static char * ngx_http_perl_init_interpreter(ngx_conf_t *cf, ngx_http_perl_main_conf_t *pmcf) { + ngx_str_t *m; + ngx_uint_t i; #if (NGX_HAVE_PERL_MULTIPLICITY) - ngx_pool_cleanup_t *cln; + ngx_pool_cleanup_t *cln; cln = ngx_pool_cleanup_add(cf->pool, 0); if (cln == NULL) { @@ -471,14 +471,29 @@ ngx_http_perl_init_interpreter(ngx_conf_ #endif #ifdef NGX_PERL_MODULES - if (pmcf->modules.data == NULL) { - pmcf->modules.data = NGX_PERL_MODULES; + if (pmcf->modules == NGX_CONF_UNSET_PTR) { + + pmcf->modules = ngx_array_create(cf->pool, 1, sizeof(ngx_str_t)); + if (pmcf->modules == NULL) { + return NGX_CONF_ERROR; + } + + m = ngx_array_push(pmcf->modules); + if (m == NULL) { + return NGX_CONF_ERROR; + } + + m->len = sizeof(NGX_PERL_MODULES) - 1; + m->data = NGX_PERL_MODULES; } #endif - if (pmcf->modules.data) { - if (ngx_conf_full_name(cf->cycle, &pmcf->modules, 0) != NGX_OK) { - return NGX_CONF_ERROR; + if (pmcf->modules != NGX_CONF_UNSET_PTR) { + m = pmcf->modules->elts; + for (i = 0; i < pmcf->modules->nelts; i++) { + if (ngx_conf_full_name(cf->cycle, &m[i], 0) != NGX_OK) { + return NGX_CONF_ERROR; + } } } @@ -490,7 +505,7 @@ ngx_http_perl_init_interpreter(ngx_conf_ return NGX_CONF_ERROR; } - if (ngx_http_perl_run_requires(aTHX_ &pmcf->requires, cf->log) + if (ngx_http_perl_run_requires(aTHX_ pmcf->requires, cf->log) != NGX_OK) { return NGX_CONF_ERROR; @@ -538,7 +553,9 @@ ngx_http_perl_create_interpreter(ngx_con int n; STRLEN len; SV *sv; - char *ver, *embedding[6]; + char *ver, **embedding; + ngx_str_t *m; + ngx_uint_t i; PerlInterpreter *perl; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "create perl interpreter"); @@ -564,15 +581,21 @@ ngx_http_perl_create_interpreter(ngx_con PL_exit_flags |= PERL_EXIT_DESTRUCT_END; #endif + n = (pmcf->modules != NGX_CONF_UNSET_PTR) ? pmcf->modules->nelts * 2 : 0; + + embedding = ngx_palloc(cf->pool, (4 + n) * sizeof(char *)); + if (embedding == NULL) { + goto fail; + } + embedding[0] = ""; - if (pmcf->modules.data) { - embedding[1] = "-I"; - embedding[2] = (char *) pmcf->modules.data; - n = 3; - - } else { - n = 1; + if (n++) { + m = pmcf->modules->elts; + for (i = 0; i < pmcf->modules->nelts; i++) { + embedding[2 * i + 1] = "-I"; + embedding[2 * i + 2] = (char *) m[i].data; + } } embedding[n++] = "-Mnginx"; @@ -596,7 +619,7 @@ ngx_http_perl_create_interpreter(ngx_con goto fail; } - if (ngx_http_perl_run_requires(aTHX_ &pmcf->requires, cf->log) != NGX_OK) { + if (ngx_http_perl_run_requires(aTHX_ pmcf->requires, cf->log) != NGX_OK) { goto fail; } @@ -617,26 +640,28 @@ fail: static ngx_int_t ngx_http_perl_run_requires(pTHX_ ngx_array_t *requires, ngx_log_t *log) { - char **script; + u_char *err; STRLEN len; - ngx_str_t err; + ngx_str_t *script; ngx_uint_t i; + if (requires == NGX_CONF_UNSET_PTR) { + return NGX_OK; + } + script = requires->elts; for (i = 0; i < requires->nelts; i++) { - require_pv(script[i]); + require_pv((char *) script[i].data); if (SvTRUE(ERRSV)) { - err.data = (u_char *) SvPV(ERRSV, len); - for (len--; err.data[len] == LF || err.data[len] == CR; len--) { - /* void */ - } - err.len = len + 1; + err = (u_char *) SvPV(ERRSV, len); + while (--len && (err[len] == CR || err[len] == LF)) { /* void */ } ngx_log_error(NGX_LOG_EMERG, log, 0, - "require_pv(\"%s\") failed: \"%V\"", script[i], &err); + "require_pv(\"%s\") failed: \"%*s\"", + script[i].data, len + 1, err); return NGX_ERROR; } @@ -653,8 +678,8 @@ ngx_http_perl_call_handler(pTHX_ ngx_htt SV *sv; int n, status; char *line; + u_char *err; STRLEN len, n_a; - ngx_str_t err; ngx_uint_t i; ngx_connection_t *c; @@ -724,14 +749,11 @@ ngx_http_perl_call_handler(pTHX_ ngx_htt if (SvTRUE(ERRSV)) { - err.data = (u_char *) SvPV(ERRSV, len); - for (len--; err.data[len] == LF || err.data[len] == CR; len--) { - /* void */ - } - err.len = len + 1; + err = (u_char *) SvPV(ERRSV, len); + while (--len && (err[len] == CR || err[len] == LF)) { /* void */ } ngx_log_error(NGX_LOG_ERR, c->log, 0, - "call_sv(\"%V\") failed: \"%V\"", handler, &err); + "call_sv(\"%V\") failed: \"%*s\"", handler, len + 1, err); if (rv) { return NGX_ERROR; @@ -765,7 +787,10 @@ ngx_http_perl_eval_anon_sub(pTHX_ ngx_st } } - if (ngx_strncmp(p, "sub ", 4) == 0 || ngx_strncmp(p, "use ", 4) == 0) { + if (ngx_strncmp(p, "sub ", 4) == 0 + || ngx_strncmp(p, "sub{", 4) == 0 + || ngx_strncmp(p, "use ", 4) == 0) + { *sv = eval_pv((char *) p, FALSE); /* eval_pv() does not set ERRSV on failure */ @@ -784,14 +809,11 @@ ngx_http_perl_create_main_conf(ngx_conf_ pmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_perl_main_conf_t)); if (pmcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } - if (ngx_array_init(&pmcf->requires, cf->pool, 1, sizeof(u_char *)) - != NGX_OK) - { - return NULL; - } + pmcf->modules = NGX_CONF_UNSET_PTR; + pmcf->requires = NGX_CONF_UNSET_PTR; return pmcf; } @@ -869,7 +891,7 @@ ngx_http_perl_create_loc_conf(ngx_conf_t plcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_perl_loc_conf_t)); if (plcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* @@ -898,28 +920,6 @@ ngx_http_perl_merge_loc_conf(ngx_conf_t static char * -ngx_http_perl_require(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_http_perl_main_conf_t *pmcf = conf; - - u_char **p; - ngx_str_t *value; - - value = cf->args->elts; - - p = ngx_array_push(&pmcf->requires); - - if (p == NULL) { - return NGX_CONF_ERROR; - } - - *p = value[1].data; - - return NGX_CONF_OK; -} - - -static char * ngx_http_perl(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_perl_loc_conf_t *plcf = conf; diff --git a/src/http/ngx_http_cache.h b/src/http/ngx_http_cache.h --- a/src/http/ngx_http_cache.h +++ b/src/http/ngx_http_cache.h @@ -97,6 +97,7 @@ typedef struct { ngx_rbtree_node_t sentinel; ngx_queue_t queue; ngx_atomic_t cold; + ngx_atomic_t loading; off_t size; } ngx_http_file_cache_sh_t; 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 @@ -433,6 +433,14 @@ static ngx_command_t ngx_http_core_comm offsetof(ngx_http_core_loc_conf_t, limit_rate), NULL }, + { ngx_string("limit_rate_after"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_core_loc_conf_t, limit_rate_after), + NULL }, + { ngx_string("keepalive_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, ngx_http_core_keepalive, @@ -877,6 +885,7 @@ ngx_http_core_find_config_phase(ngx_http "client intended to send too large body: %O bytes", r->headers_in.content_length_n); + (void) ngx_http_discard_request_body(r); ngx_http_finalize_request(r, NGX_HTTP_REQUEST_ENTITY_TOO_LARGE); return NGX_OK; } @@ -2691,14 +2700,14 @@ ngx_http_core_create_main_conf(ngx_conf_ cmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_core_main_conf_t)); if (cmcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } if (ngx_array_init(&cmcf->servers, cf->pool, 4, sizeof(ngx_http_core_srv_conf_t *)) != NGX_OK) { - return NGX_CONF_ERROR; + return NULL; } cmcf->server_names_hash_max_size = NGX_CONF_UNSET_UINT; @@ -2750,7 +2759,7 @@ ngx_http_core_create_srv_conf(ngx_conf_t cscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_core_srv_conf_t)); if (cscf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* @@ -2763,14 +2772,14 @@ ngx_http_core_create_srv_conf(ngx_conf_t sizeof(ngx_http_listen_t)) != NGX_OK) { - return NGX_CONF_ERROR; + return NULL; } if (ngx_array_init(&cscf->server_names, cf->temp_pool, 4, sizeof(ngx_http_server_name_t)) != NGX_OK) { - return NGX_CONF_ERROR; + return NULL; } cscf->connection_pool_size = NGX_CONF_UNSET_SIZE; @@ -2881,7 +2890,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t lcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_core_loc_conf_t)); if (lcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* @@ -2920,6 +2929,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t lcf->send_lowat = NGX_CONF_UNSET_SIZE; lcf->postpone_output = NGX_CONF_UNSET_SIZE; lcf->limit_rate = NGX_CONF_UNSET_SIZE; + lcf->limit_rate_after = NGX_CONF_UNSET_SIZE; lcf->keepalive_timeout = NGX_CONF_UNSET_MSEC; lcf->keepalive_header = NGX_CONF_UNSET; lcf->keepalive_requests = NGX_CONF_UNSET_UINT; @@ -3119,6 +3129,8 @@ ngx_http_core_merge_loc_conf(ngx_conf_t ngx_conf_merge_size_value(conf->postpone_output, prev->postpone_output, 1460); ngx_conf_merge_size_value(conf->limit_rate, prev->limit_rate, 0); + ngx_conf_merge_size_value(conf->limit_rate_after, prev->limit_rate_after, + 0); ngx_conf_merge_msec_value(conf->keepalive_timeout, prev->keepalive_timeout, 75000); ngx_conf_merge_sec_value(conf->keepalive_header, diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -324,6 +324,7 @@ struct ngx_http_core_loc_conf_s { size_t send_lowat; /* send_lowat */ size_t postpone_output; /* postpone_output */ size_t limit_rate; /* limit_rate */ + size_t limit_rate_after; /* limit_rate_after */ size_t sendfile_max_chunk; /* sendfile_max_chunk */ ngx_msec_t client_body_timeout; /* client_body_timeout */ diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -53,6 +53,7 @@ ngx_http_file_cache_init(ngx_shm_zone_t ngx_http_file_cache_t *ocache = data; size_t len; + ngx_uint_t n; ngx_http_file_cache_t *cache; cache = shm_zone->data; @@ -68,6 +69,15 @@ ngx_http_file_cache_init(ngx_shm_zone_t return NGX_ERROR; } + for (n = 0; n < 3; n++) { + if (cache->path->level[n] != ocache->path->level[n]) { + ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0, + "cache \"%V\" had previously different levels", + &shm_zone->shm.name); + return NGX_ERROR; + } + } + cache->sh = ocache->sh; cache->shpool = ocache->shpool; @@ -75,6 +85,10 @@ ngx_http_file_cache_init(ngx_shm_zone_t cache->max_size /= cache->bsize; + if (!cache->sh->cold || cache->sh->loading) { + cache->path->loader = NULL; + } + return NGX_OK; } @@ -100,6 +114,7 @@ ngx_http_file_cache_init(ngx_shm_zone_t ngx_queue_init(&cache->sh->queue); cache->sh->cold = 1; + cache->sh->loading = 0; cache->sh->size = 0; cache->bsize = ngx_fs_bsize(cache->path->name.data); @@ -603,7 +618,7 @@ ngx_http_file_cache_set_header(ngx_http_ void ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf) { - off_t size; + off_t size, length; ngx_int_t rc; ngx_file_uniq_t uniq; ngx_file_info_t fi; @@ -625,6 +640,7 @@ ngx_http_file_cache_update(ngx_http_requ cache = c->file_cache; uniq = 0; + length = 0; ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http file cache rename: \"%s\" to \"%s\"", @@ -635,7 +651,6 @@ ngx_http_file_cache_update(ngx_http_requ ext.time = -1; ext.create_path = 1; ext.delete_file = 1; - ext.log_rename_error = 1; ext.log = r->connection->log; rc = ngx_ext_rename_file(&tf->file.name, &c->file.name, &ext); @@ -650,10 +665,11 @@ ngx_http_file_cache_update(ngx_http_requ } else { uniq = ngx_file_uniq(&fi); + length = ngx_file_size(&fi); } } - size = (c->length + cache->bsize - 1) / cache->bsize; + size = (length + cache->bsize - 1) / cache->bsize; ngx_shmtx_lock(&cache->shpool->mutex); @@ -663,7 +679,7 @@ ngx_http_file_cache_update(ngx_http_requ size = size - (c->node->length + cache->bsize - 1) / cache->bsize; - c->node->length = c->length; + c->node->length = length; cache->sh->size += size; @@ -1026,39 +1042,8 @@ ngx_http_file_cache_manager(void *data) { ngx_http_file_cache_t *cache = data; - off_t size; - time_t next; - ngx_tree_ctx_t tree; - - if (cache->sh->cold) { - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, - "http file cache manager update"); - - tree.init_handler = NULL; - tree.file_handler = ngx_http_file_cache_manage_file; - tree.pre_tree_handler = ngx_http_file_cache_noop; - tree.post_tree_handler = ngx_http_file_cache_noop; - tree.spec_handler = ngx_http_file_cache_delete_file; - tree.data = cache; - tree.alloc = 0; - tree.log = ngx_cycle->log; - - cache->last = ngx_current_msec; - cache->files = 0; - - if (ngx_walk_tree(&tree, &cache->path->name) == NGX_ABORT) { - return 10; - } - - cache->sh->cold = 0; - - ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, - "http file cache: %V %.3fM, bsize: %uz", - &cache->path->name, - ((double) cache->sh->size * cache->bsize) / (1024 * 1024), - cache->bsize); - } + off_t size; + time_t next; next = ngx_http_file_cache_expire(cache); @@ -1088,6 +1073,52 @@ ngx_http_file_cache_manager(void *data) } +static void +ngx_http_file_cache_loader(void *data) +{ + ngx_http_file_cache_t *cache = data; + + ngx_tree_ctx_t tree; + + if (!cache->sh->cold || cache->sh->loading) { + return; + } + + if (!ngx_atomic_cmp_set(&cache->sh->loading, 0, ngx_pid)) { + return; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "http file cache loader"); + + tree.init_handler = NULL; + tree.file_handler = ngx_http_file_cache_manage_file; + tree.pre_tree_handler = ngx_http_file_cache_noop; + tree.post_tree_handler = ngx_http_file_cache_noop; + tree.spec_handler = ngx_http_file_cache_delete_file; + tree.data = cache; + tree.alloc = 0; + tree.log = ngx_cycle->log; + + cache->last = ngx_current_msec; + cache->files = 0; + + if (ngx_walk_tree(&tree, &cache->path->name) == NGX_ABORT) { + cache->sh->loading = 0; + return; + } + + cache->sh->cold = 0; + cache->sh->loading = 0; + + ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, + "http file cache: %V %.3fM, bsize: %uz", + &cache->path->name, + ((double) cache->sh->size * cache->bsize) / (1024 * 1024), + cache->bsize); +} + + static ngx_int_t ngx_http_file_cache_manager_sleep(ngx_http_file_cache_t *cache) { @@ -1468,6 +1499,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t } cache->path->manager = ngx_http_file_cache_manager; + cache->path->loader = ngx_http_file_cache_loader; cache->path->data = cache; if (ngx_add_path(cf, &cache->path) != NGX_OK) { diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -143,7 +143,7 @@ ngx_http_parse_request_line(ngx_http_req break; } - if (ch < 'A' || ch > 'Z') { + if ((ch < 'A' || ch > 'Z') && ch != '_') { return NGX_HTTP_PARSE_INVALID_METHOD; } @@ -257,7 +257,7 @@ ngx_http_parse_request_line(ngx_http_req break; } - if (ch < 'A' || ch > 'Z') { + if ((ch < 'A' || ch > 'Z') && ch != '_') { return NGX_HTTP_PARSE_INVALID_METHOD; } @@ -1322,8 +1322,10 @@ ngx_http_parse_unsafe_uri(ngx_http_reque unsafe: - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "unsafe URI \"%V\" was detected", uri); + if (*flags & NGX_HTTP_LOG_UNSAFE) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "unsafe URI \"%V\" was detected", uri); + } return NGX_ERROR; } diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -129,7 +129,7 @@ ngx_http_header_t ngx_http_headers_in[] { ngx_string("Keep-Alive"), offsetof(ngx_http_headers_in_t, keep_alive), ngx_http_process_header_line }, -#if (NGX_HTTP_PROXY || NGX_HTTP_REALIP) +#if (NGX_HTTP_PROXY || NGX_HTTP_REALIP || NGX_HTTP_GEO) { ngx_string("X-Forwarded-For"), offsetof(ngx_http_headers_in_t, x_forwarded_for), ngx_http_process_header_line }, @@ -384,6 +384,7 @@ ngx_http_init_request(ngx_event_t *rev) r->loc_conf = cscf->ctx->loc_conf; rev->handler = ngx_http_process_request_line; + r->read_event_handler = ngx_http_block_reading; #if (NGX_HTTP_SSL) @@ -451,13 +452,15 @@ ngx_http_init_request(ngx_event_t *rev) sizeof(ngx_table_elt_t)) != NGX_OK) { - ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + ngx_destroy_pool(r->pool); + ngx_http_close_connection(c); return; } r->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module); if (r->ctx == NULL) { - ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + ngx_destroy_pool(r->pool); + ngx_http_close_connection(c); return; } @@ -466,7 +469,8 @@ ngx_http_init_request(ngx_event_t *rev) r->variables = ngx_pcalloc(r->pool, cmcf->variables.nelts * sizeof(ngx_http_variable_value_t)); if (r->variables == NULL) { - ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + ngx_destroy_pool(r->pool); + ngx_http_close_connection(c); return; } @@ -1374,8 +1378,13 @@ ngx_http_process_user_agent(ngx_http_req r->headers_in.msie4 = 1; /* fall through */ case '5': + r->headers_in.msie6 = 1; + break; case '6': - r->headers_in.msie6 = 1; + if (ngx_strstrn(msie + 8, "SV1", 3 - 1) == NULL) { + r->headers_in.msie6 = 1; + } + break; } } @@ -1517,7 +1526,7 @@ ngx_http_process_request(ngx_http_reques sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); - if (sscf->verify == 1) { + if (sscf->verify) { rc = SSL_get_verify_result(c->ssl->connection); if (rc != X509_V_OK) { @@ -1532,20 +1541,22 @@ ngx_http_process_request(ngx_http_reques return; } - cert = SSL_get_peer_certificate(c->ssl->connection); - - if (cert == NULL) { - ngx_log_error(NGX_LOG_INFO, c->log, 0, - "client sent no required SSL certificate"); - - ngx_ssl_remove_cached_session(sscf->ssl.ctx, + if (sscf->verify == 1) { + cert = SSL_get_peer_certificate(c->ssl->connection); + + if (cert == NULL) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client sent no required SSL certificate"); + + ngx_ssl_remove_cached_session(sscf->ssl.ctx, (SSL_get0_session(c->ssl->connection))); - ngx_http_finalize_request(r, NGX_HTTPS_NO_CERT); - return; + ngx_http_finalize_request(r, NGX_HTTPS_NO_CERT); + return; + } + + X509_free(cert); } - - X509_free(cert); } } @@ -2703,7 +2714,14 @@ ngx_http_send_special(ngx_http_request_t } if (flags & NGX_HTTP_LAST) { - b->last_buf = 1; + + if (r == r->main && !r->post_action) { + b->last_buf = 1; + + } else { + b->sync = 1; + b->last_in_chain = 1; + } } if (flags & NGX_HTTP_FLUSH) { 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 @@ -60,6 +60,7 @@ #define NGX_HTTP_ZERO_IN_URI 1 #define NGX_HTTP_SUBREQUEST_IN_MEMORY 2 #define NGX_HTTP_SUBREQUEST_WAITED 4 +#define NGX_HTTP_LOG_UNSAFE 8 #define NGX_HTTP_OK 200 @@ -184,7 +185,7 @@ typedef struct { ngx_table_elt_t *keep_alive; -#if (NGX_HTTP_PROXY || NGX_HTTP_REALIP) +#if (NGX_HTTP_PROXY || NGX_HTTP_REALIP || NGX_HTTP_GEO) ngx_table_elt_t *x_forwarded_for; #endif @@ -488,7 +489,6 @@ struct ngx_http_request_s { unsigned root_tested:1; unsigned done:1; unsigned logged:1; - unsigned utf8:1; unsigned buffered:4; diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c --- a/src/http/ngx_http_script.c +++ b/src/http/ngx_http_script.c @@ -561,7 +561,7 @@ ngx_http_script_add_code(ngx_array_t *co new = ngx_array_push_n(codes, size); if (new == NULL) { - return NGX_CONF_ERROR; + return NULL; } if (code) { diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -230,19 +230,19 @@ ngx_http_upstream_header_t ngx_http_ups { ngx_string("X-Accel-Redirect"), ngx_http_upstream_process_header_line, offsetof(ngx_http_upstream_headers_in_t, x_accel_redirect), - ngx_http_upstream_ignore_header_line, 0, 0 }, + ngx_http_upstream_copy_header_line, 0, 0 }, { ngx_string("X-Accel-Limit-Rate"), ngx_http_upstream_process_limit_rate, 0, - ngx_http_upstream_ignore_header_line, 0, 0 }, + ngx_http_upstream_copy_header_line, 0, 0 }, { ngx_string("X-Accel-Buffering"), ngx_http_upstream_process_buffering, 0, - ngx_http_upstream_ignore_header_line, 0, 0 }, + ngx_http_upstream_copy_header_line, 0, 0 }, { ngx_string("X-Accel-Charset"), ngx_http_upstream_process_charset, 0, - ngx_http_upstream_ignore_header_line, 0, 0 }, + ngx_http_upstream_copy_header_line, 0, 0 }, #if (NGX_HTTP_GZIP) { ngx_string("Content-Encoding"), @@ -354,6 +354,35 @@ ngx_conf_bitmask_t ngx_http_upstream_ca }; +ngx_int_t +ngx_http_upstream_create(ngx_http_request_t *r) +{ + ngx_http_upstream_t *u; + + u = r->upstream; + + if (u && u->cleanup) { + ngx_http_upstream_cleanup(r); + *u->cleanup = NULL; + } + + u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t)); + if (u == NULL) { + return NGX_ERROR; + } + + r->upstream = u; + + u->peer.log = r->connection->log; + u->peer.log_error = NGX_ERROR_ERR; +#if (NGX_THREADS) + u->peer.lock = &r->connection->lock; +#endif + + return NGX_OK; +} + + void ngx_http_upstream_init(ngx_http_request_t *r) { @@ -1733,7 +1762,7 @@ ngx_http_upstream_process_headers(ngx_ht uri = &u->headers_in.x_accel_redirect->value; args.len = 0; args.data = NULL; - flags = 0; + flags = NGX_HTTP_LOG_UNSAFE; if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) { ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND); @@ -2034,11 +2063,6 @@ ngx_http_upstream_send_response(ngx_http r->cache->date = now; r->cache->body_start = (u_short) (u->buffer.pos - u->buffer.start); - if (r->headers_out.content_length_n != -1) { - r->cache->length = r->cache->body_start - + r->headers_out.content_length_n; - } - ngx_http_file_cache_set_header(r, u->buffer.start); } else { @@ -2616,7 +2640,6 @@ ngx_http_upstream_store(ngx_http_request ext.time = -1; ext.create_path = 1; ext.delete_file = 1; - ext.log_rename_error = 1; ext.log = r->connection->log; if (u->headers_in.last_modified) { @@ -2643,6 +2666,8 @@ ngx_http_upstream_store(ngx_http_request } } + path.len--; + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "upstream stores \"%s\" to \"%s\"", tf->file.name.data, path.data); @@ -2864,7 +2889,7 @@ ngx_http_upstream_finalize_request(ngx_h #if (NGX_HTTP_CACHE) - if (u->cacheable) { + if (u->cacheable && r->cache) { time_t valid; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -2898,7 +2923,7 @@ ngx_http_upstream_finalize_request(ngx_h r->connection->log->action = "sending to client"; - if (rc == 0 && r == r->main && !r->post_action) { + if (rc == 0) { rc = ngx_http_send_special(r, NGX_HTTP_LAST); } @@ -3311,10 +3336,11 @@ ngx_http_upstream_copy_last_modified(ngx *ho = *h; + r->headers_out.last_modified = ho; + #if (NGX_HTTP_CACHE) if (r->upstream->cacheable) { - r->headers_out.last_modified = ho; r->headers_out.last_modified_time = ngx_http_parse_time(h->value.data, h->value.len); } @@ -3438,6 +3464,8 @@ ngx_http_upstream_copy_allow_ranges(ngx_ *ho = *h; + r->headers_out.accept_ranges = ho; + return NGX_OK; } @@ -4274,7 +4302,7 @@ ngx_http_upstream_create_main_conf(ngx_c sizeof(ngx_http_upstream_srv_conf_t *)) != NGX_OK) { - return NGX_CONF_ERROR; + return NULL; } return umcf; diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -317,6 +317,7 @@ typedef struct { ngx_int_t ngx_http_upstream_header_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +ngx_int_t ngx_http_upstream_create(ngx_http_request_t *r); void ngx_http_upstream_init(ngx_http_request_t *r); ngx_http_upstream_srv_conf_t *ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags); 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 @@ -46,7 +46,7 @@ ngx_module_t ngx_http_write_filter_modu ngx_int_t ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) { - off_t size, sent, limit; + off_t size, sent, nsent, limit; ngx_uint_t last, flush; ngx_msec_t delay; ngx_chain_t *cl, *ln, **ll, *chain; @@ -210,7 +210,8 @@ ngx_http_write_filter(ngx_http_request_t } if (r->limit_rate) { - limit = r->limit_rate * (ngx_time() - r->start_sec + 1) - c->sent; + limit = r->limit_rate * (ngx_time() - r->start_sec + 1) + - (c->sent - clcf->limit_rate_after); if (limit <= 0) { c->write->delayed = 1; @@ -245,7 +246,23 @@ ngx_http_write_filter(ngx_http_request_t } if (r->limit_rate) { - delay = (ngx_msec_t) ((c->sent - sent) * 1000 / r->limit_rate + 1); + + nsent = c->sent; + + if (clcf->limit_rate_after) { + + sent -= clcf->limit_rate_after; + if (sent < 0) { + sent = 0; + } + + nsent -= clcf->limit_rate_after; + if (nsent < 0) { + nsent = 0; + } + } + + delay = (ngx_msec_t) ((nsent - sent) * 1000 / r->limit_rate + 1); if (delay > 0) { c->write->delayed = 1; diff --git a/src/mail/ngx_mail_auth_http_module.c b/src/mail/ngx_mail_auth_http_module.c --- a/src/mail/ngx_mail_auth_http_module.c +++ b/src/mail/ngx_mail_auth_http_module.c @@ -1302,7 +1302,7 @@ ngx_mail_auth_http_create_conf(ngx_conf_ ahcf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_auth_http_conf_t)); if (ahcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } ahcf->timeout = NGX_CONF_UNSET_MSEC; diff --git a/src/mail/ngx_mail_core_module.c b/src/mail/ngx_mail_core_module.c --- a/src/mail/ngx_mail_core_module.c +++ b/src/mail/ngx_mail_core_module.c @@ -120,20 +120,20 @@ ngx_mail_core_create_main_conf(ngx_conf_ cmcf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_core_main_conf_t)); if (cmcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } if (ngx_array_init(&cmcf->servers, cf->pool, 4, sizeof(ngx_mail_core_srv_conf_t *)) != NGX_OK) { - return NGX_CONF_ERROR; + return NULL; } if (ngx_array_init(&cmcf->listen, cf->pool, 4, sizeof(ngx_mail_listen_t)) != NGX_OK) { - return NGX_CONF_ERROR; + return NULL; } return cmcf; 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 @@ -1061,7 +1061,7 @@ ngx_mail_proxy_create_conf(ngx_conf_t *c pcf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_proxy_conf_t)); if (pcf == NULL) { - return NGX_CONF_ERROR; + return NULL; } pcf->enable = NGX_CONF_UNSET; diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c --- a/src/mail/ngx_mail_ssl_module.c +++ b/src/mail/ngx_mail_ssl_module.c @@ -22,15 +22,6 @@ static char *ngx_mail_ssl_starttls(ngx_c static char *ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -#if !defined (SSL_OP_CIPHER_SERVER_PREFERENCE) - -static char *ngx_mail_ssl_nosupported(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); - -static char ngx_mail_ssl_openssl097[] = "OpenSSL 0.9.7 and higher"; - -#endif - static ngx_conf_enum_t ngx_http_starttls_state[] = { { ngx_string("off"), NGX_MAIL_STARTTLS_OFF }, @@ -102,14 +93,10 @@ static ngx_command_t ngx_mail_ssl_comma { ngx_string("ssl_prefer_server_ciphers"), NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG, -#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE ngx_conf_set_flag_slot, NGX_MAIL_SRV_CONF_OFFSET, offsetof(ngx_mail_ssl_conf_t, prefer_server_ciphers), NULL }, -#else - ngx_mail_ssl_nosupported, 0, 0, ngx_mail_ssl_openssl097 }, -#endif { ngx_string("ssl_session_cache"), NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE12, @@ -166,7 +153,7 @@ ngx_mail_ssl_create_conf(ngx_conf_t *cf) scf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_ssl_conf_t)); if (scf == NULL) { - return NGX_CONF_ERROR; + return NULL; } /* @@ -297,14 +284,10 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, } } -#ifdef SSL_OP_CIPHER_SERVER_PREFERENCE - if (conf->prefer_server_ciphers) { SSL_CTX_set_options(conf->ssl.ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); } -#endif - if (ngx_ssl_generate_rsa512_key(&conf->ssl) != NGX_OK) { return NGX_CONF_ERROR; } @@ -492,18 +475,3 @@ invalid: return NGX_CONF_ERROR; } - - -#if !defined (SSL_OP_CIPHER_SERVER_PREFERENCE) - -static char * -ngx_mail_ssl_nosupported(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"%V\" directive is available only in %s,", - &cmd->name, cmd->post); - - return NGX_CONF_ERROR; -} - -#endif diff --git a/src/os/unix/ngx_errno.h b/src/os/unix/ngx_errno.h --- a/src/os/unix/ngx_errno.h +++ b/src/os/unix/ngx_errno.h @@ -16,6 +16,7 @@ typedef int ngx_err_t; #define NGX_EPERM EPERM #define NGX_ENOENT ENOENT +#define NGX_ENOPATH ENOENT #define NGX_ESRCH ESRCH #define NGX_EINTR EINTR #define NGX_ECHILD ECHILD 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 @@ -18,13 +18,13 @@ typedef ino_t ngx_fil typedef struct { - DIR *dir; - struct dirent *de; - struct stat info; + DIR *dir; + struct dirent *de; + struct stat info; - unsigned type:8; - unsigned valid_info:1; - unsigned valid_type:1; + unsigned type:8; + unsigned valid_info:1; + unsigned valid_type:1; } ngx_dir_t; diff --git a/src/os/unix/ngx_process.c b/src/os/unix/ngx_process.c --- a/src/os/unix/ngx_process.c +++ b/src/os/unix/ngx_process.c @@ -214,21 +214,33 @@ ngx_spawn_process(ngx_cycle_t *cycle, ng switch (respawn) { + case NGX_PROCESS_NORESPAWN: + ngx_processes[s].respawn = 0; + ngx_processes[s].just_spawn = 0; + ngx_processes[s].detached = 0; + break; + + case NGX_PROCESS_JUST_SPAWN: + ngx_processes[s].respawn = 0; + ngx_processes[s].just_spawn = 1; + ngx_processes[s].detached = 0; + break; + case NGX_PROCESS_RESPAWN: ngx_processes[s].respawn = 1; - ngx_processes[s].just_respawn = 0; + ngx_processes[s].just_spawn = 0; ngx_processes[s].detached = 0; break; case NGX_PROCESS_JUST_RESPAWN: ngx_processes[s].respawn = 1; - ngx_processes[s].just_respawn = 1; + ngx_processes[s].just_spawn = 1; ngx_processes[s].detached = 0; break; case NGX_PROCESS_DETACHED: ngx_processes[s].respawn = 0; - ngx_processes[s].just_respawn = 0; + ngx_processes[s].just_spawn = 0; ngx_processes[s].detached = 1; break; } diff --git a/src/os/unix/ngx_process.h b/src/os/unix/ngx_process.h --- a/src/os/unix/ngx_process.h +++ b/src/os/unix/ngx_process.h @@ -27,7 +27,7 @@ typedef struct { char *name; unsigned respawn:1; - unsigned just_respawn:1; + unsigned just_spawn:1; unsigned detached:1; unsigned exiting:1; unsigned exited:1; @@ -45,9 +45,10 @@ typedef struct { #define NGX_MAX_PROCESSES 1024 #define NGX_PROCESS_NORESPAWN -1 -#define NGX_PROCESS_RESPAWN -2 -#define NGX_PROCESS_JUST_RESPAWN -3 -#define NGX_PROCESS_DETACHED -4 +#define NGX_PROCESS_JUST_SPAWN -2 +#define NGX_PROCESS_RESPAWN -3 +#define NGX_PROCESS_JUST_RESPAWN -4 +#define NGX_PROCESS_DETACHED -5 #define ngx_getpid getpid diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c --- a/src/os/unix/ngx_process_cycle.c +++ b/src/os/unix/ngx_process_cycle.c @@ -12,7 +12,9 @@ static void ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type); -static void ngx_start_cache_manager_process(ngx_cycle_t *cycle, ngx_int_t type); +static void ngx_start_cache_manager_processes(ngx_cycle_t *cycle, + ngx_uint_t respawn); +static void ngx_pass_open_channel(ngx_cycle_t *cycle, ngx_channel_t *ch); static void ngx_signal_worker_processes(ngx_cycle_t *cycle, int signo); static ngx_uint_t ngx_reap_children(ngx_cycle_t *cycle); static void ngx_master_process_exit(ngx_cycle_t *cycle); @@ -26,6 +28,7 @@ static ngx_thread_value_t ngx_worker_thr #endif static void ngx_cache_manager_process_cycle(ngx_cycle_t *cycle, void *data); static void ngx_cache_manager_process_handler(ngx_event_t *ev); +static void ngx_cache_loader_process_handler(ngx_event_t *ev); ngx_uint_t ngx_process; @@ -62,6 +65,15 @@ u_long cpu_affinity; static u_char master_process[] = "master process"; +static ngx_cache_manager_ctx_t ngx_cache_manager_ctx = { + ngx_cache_manager_process_handler, "cache manager process", 0 +}; + +static ngx_cache_manager_ctx_t ngx_cache_loader_ctx = { + ngx_cache_loader_process_handler, "cache loader process", 60000 +}; + + static ngx_cycle_t ngx_exit_cycle; static ngx_log_t ngx_exit_log; static ngx_open_file_t ngx_exit_log_file; @@ -123,7 +135,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); - ngx_start_cache_manager_process(cycle, NGX_PROCESS_RESPAWN); + ngx_start_cache_manager_processes(cycle, 0); ngx_new_binary = 0; delay = 0; @@ -207,7 +219,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy if (ngx_new_binary) { ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); - ngx_start_cache_manager_process(cycle, NGX_PROCESS_RESPAWN); + ngx_start_cache_manager_processes(cycle, 0); ngx_noaccepting = 0; continue; @@ -226,7 +238,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy ngx_core_module); ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_JUST_RESPAWN); - ngx_start_cache_manager_process(cycle, NGX_PROCESS_JUST_RESPAWN); + ngx_start_cache_manager_processes(cycle, 1); live = 1; ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); @@ -236,7 +248,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy ngx_restart = 0; ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); - ngx_start_cache_manager_process(cycle, NGX_PROCESS_RESPAWN); + ngx_start_cache_manager_processes(cycle, 0); live = 1; } @@ -269,8 +281,6 @@ ngx_single_process_cycle(ngx_cycle_t *cy { ngx_uint_t i; - ngx_init_temp_number(); - for (i = 0; ngx_modules[i]; i++) { if (ngx_modules[i]->init_process) { if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) { @@ -321,7 +331,7 @@ ngx_single_process_cycle(ngx_cycle_t *cy static void ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type) { - ngx_int_t i, s; + ngx_int_t i; ngx_channel_t ch; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start worker processes"); @@ -339,58 +349,70 @@ ngx_start_worker_processes(ngx_cycle_t * ch.slot = ngx_process_slot; ch.fd = ngx_processes[ngx_process_slot].channel[0]; - for (s = 0; s < ngx_last_process; s++) { - - if (s == ngx_process_slot - || ngx_processes[s].pid == -1 - || ngx_processes[s].channel[0] == -1) - { - continue; - } - - ngx_log_debug6(NGX_LOG_DEBUG_CORE, cycle->log, 0, - "pass channel s:%d pid:%P fd:%d to s:%i pid:%P fd:%d", - ch.slot, ch.pid, ch.fd, - s, ngx_processes[s].pid, - ngx_processes[s].channel[0]); - - /* TODO: NGX_AGAIN */ - - ngx_write_channel(ngx_processes[s].channel[0], - &ch, sizeof(ngx_channel_t), cycle->log); - } + ngx_pass_open_channel(cycle, &ch); } } static void -ngx_start_cache_manager_process(ngx_cycle_t *cycle, ngx_int_t type) +ngx_start_cache_manager_processes(ngx_cycle_t *cycle, ngx_uint_t respawn) { - ngx_int_t i; - ngx_uint_t n; + ngx_uint_t i, manager, loader; ngx_path_t **path; ngx_channel_t ch; + manager = 0; + loader = 0; + path = ngx_cycle->pathes.elts; - for (n = 0; n < ngx_cycle->pathes.nelts; n++) { - if (path[n]->manager) { - goto start; + for (i = 0; i < ngx_cycle->pathes.nelts; i++) { + + if (path[i]->manager) { + manager = 1; + } + + if (path[i]->loader) { + loader = 1; } } - return; + if (manager == 0) { + return; + } -start: + ngx_spawn_process(cycle, ngx_cache_manager_process_cycle, + &ngx_cache_manager_ctx, "cache manager process", + respawn ? NGX_PROCESS_JUST_RESPAWN : NGX_PROCESS_RESPAWN); ch.command = NGX_CMD_OPEN_CHANNEL; - - ngx_spawn_process(cycle, ngx_cache_manager_process_cycle, NULL, - "cache manager process", type); - ch.pid = ngx_processes[ngx_process_slot].pid; ch.slot = ngx_process_slot; ch.fd = ngx_processes[ngx_process_slot].channel[0]; + ngx_pass_open_channel(cycle, &ch); + + if (loader == 0) { + return; + } + + ngx_spawn_process(cycle, ngx_cache_manager_process_cycle, + &ngx_cache_loader_ctx, "cache loader process", + respawn ? NGX_PROCESS_JUST_SPAWN : NGX_PROCESS_NORESPAWN); + + ch.command = NGX_CMD_OPEN_CHANNEL; + ch.pid = ngx_processes[ngx_process_slot].pid; + ch.slot = ngx_process_slot; + ch.fd = ngx_processes[ngx_process_slot].channel[0]; + + ngx_pass_open_channel(cycle, &ch); +} + + +static void +ngx_pass_open_channel(ngx_cycle_t *cycle, ngx_channel_t *ch) +{ + ngx_int_t i; + for (i = 0; i < ngx_last_process; i++) { if (i == ngx_process_slot @@ -402,14 +424,14 @@ start: ngx_log_debug6(NGX_LOG_DEBUG_CORE, cycle->log, 0, "pass channel s:%d pid:%P fd:%d to s:%i pid:%P fd:%d", - ch.slot, ch.pid, ch.fd, + ch->slot, ch->pid, ch->fd, i, ngx_processes[i].pid, ngx_processes[i].channel[0]); /* TODO: NGX_AGAIN */ ngx_write_channel(ngx_processes[i].channel[0], - &ch, sizeof(ngx_channel_t), cycle->log); + ch, sizeof(ngx_channel_t), cycle->log); } } @@ -460,14 +482,14 @@ ngx_signal_worker_processes(ngx_cycle_t ngx_processes[i].exited, ngx_processes[i].detached, ngx_processes[i].respawn, - ngx_processes[i].just_respawn); + ngx_processes[i].just_spawn); if (ngx_processes[i].detached || ngx_processes[i].pid == -1) { continue; } - if (ngx_processes[i].just_respawn) { - ngx_processes[i].just_respawn = 0; + if (ngx_processes[i].just_spawn) { + ngx_processes[i].just_spawn = 0; continue; } @@ -536,7 +558,7 @@ ngx_reap_children(ngx_cycle_t *cycle) ngx_processes[i].exited, ngx_processes[i].detached, ngx_processes[i].respawn, - ngx_processes[i].just_respawn); + ngx_processes[i].just_spawn); if (ngx_processes[i].pid == -1) { continue; @@ -593,26 +615,7 @@ ngx_reap_children(ngx_cycle_t *cycle) ch.slot = ngx_process_slot; ch.fd = ngx_processes[ngx_process_slot].channel[0]; - for (n = 0; n < ngx_last_process; n++) { - - if (n == ngx_process_slot - || ngx_processes[n].pid == -1 - || ngx_processes[n].channel[0] == -1) - { - continue; - } - - ngx_log_debug6(NGX_LOG_DEBUG_CORE, cycle->log, 0, - "pass channel s:%d pid:%P fd:%d to s:%i pid:%P fd:%d", - ch.slot, ch.pid, ch.fd, - n, ngx_processes[n].pid, - ngx_processes[n].channel[0]); - - /* TODO: NGX_AGAIN */ - - ngx_write_channel(ngx_processes[n].channel[0], - &ch, sizeof(ngx_channel_t), cycle->log); - } + ngx_pass_open_channel(cycle, &ch); live = 1; @@ -928,8 +931,6 @@ ngx_worker_process_init(ngx_cycle_t *cyc "sigprocmask() failed"); } - ngx_init_temp_number(); - /* * disable deleting previous events for the listening sockets because * in the worker processes there are no events at all at this point @@ -1268,6 +1269,8 @@ ngx_worker_thread_cycle(void *data) static void ngx_cache_manager_process_cycle(ngx_cycle_t *cycle, void *data) { + ngx_cache_manager_ctx_t *ctx = data; + void *ident[4]; ngx_event_t ev; @@ -1278,16 +1281,16 @@ ngx_cache_manager_process_cycle(ngx_cycl ngx_close_listening_sockets(cycle); ngx_memzero(&ev, sizeof(ngx_event_t)); - ev.handler = ngx_cache_manager_process_handler; + ev.handler = ctx->handler; ev.data = ident; ev.log = cycle->log; ident[3] = (void *) -1; ngx_use_accept_mutex = 0; - ngx_setproctitle("cache manager process"); + ngx_setproctitle(ctx->name); - ngx_add_timer(&ev, 0); + ngx_add_timer(&ev, ctx->delay); for ( ;; ) { @@ -1334,3 +1337,29 @@ ngx_cache_manager_process_handler(ngx_ev ngx_add_timer(ev, next * 1000); } + + +static void +ngx_cache_loader_process_handler(ngx_event_t *ev) +{ + ngx_uint_t i; + ngx_path_t **path; + ngx_cycle_t *cycle; + + cycle = (ngx_cycle_t *) ngx_cycle; + + path = cycle->pathes.elts; + for (i = 0; i < cycle->pathes.nelts; i++) { + + if (ngx_terminate || ngx_quit) { + break; + } + + if (path[i]->loader) { + path[i]->loader(path[i]->data); + ngx_time_update(0, 0); + } + } + + exit(0); +} diff --git a/src/os/unix/ngx_process_cycle.h b/src/os/unix/ngx_process_cycle.h --- a/src/os/unix/ngx_process_cycle.h +++ b/src/os/unix/ngx_process_cycle.h @@ -25,6 +25,13 @@ #define NGX_PROCESS_SIGNALLER 3 +typedef struct { + ngx_event_handler_pt handler; + char *name; + ngx_msec_t delay; +} ngx_cache_manager_ctx_t; + + void ngx_master_process_cycle(ngx_cycle_t *cycle); void ngx_single_process_cycle(ngx_cycle_t *cycle);