# HG changeset patch # User Maxim Dounin # Date 1238888126 -14400 # Node ID 1e91f9968443b54f42346d445a2a2c90362e1503 # Parent c78a94ba4ae1230990a312014412284e1fff8c65# Parent 0cc33540f2e0a6977ce84d59733dee94d51017e2 Merge with 0.7.47. diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -228,3 +228,16 @@ ce4f9ff90bfa58834c5b0db35395fd980c8c4aa0 6281966854a55e092674b01b6861bd025fe158ee NGINX_0_7_32 670af56a1158749e82d7b1fce1ce348f8e10472a NGINX_0_7_33 33394d1255b058295bc596287d249ccd612fb41e NGINX_0_7_34 +15a022ee809bb6234f9ca4993714d9820ef954dd NGINX_0_7_35 +76a79816b77167fb3fc7591b21de449d9cd71322 NGINX_0_7_36 +20962db0117cbc0996dc82ff31f8abc6c3598451 NGINX_0_7_37 +fc5ebf0e5f98c4a7c1c370234e3f9be09b94a2a1 NGINX_0_7_38 +a8424ffa495cf3a21769c567df89bef2a9c0c3fd NGINX_0_7_39 +ca8f7f6cab16b29a7be5b2b789a743bad2d8f0a8 NGINX_0_7_40 +2e2b57743e871f3e1aa5994b693da5d248df5800 NGINX_0_7_41 +bb941a2996a6026f35c76f60ec2cd56c23f34ae5 NGINX_0_7_42 +dcb6b5f9d526e677c2860164d9c03b33caa0bd35 NGINX_0_7_43 +c8cfb6c462efa1a49e51fd193e4c645a5cfb212c NGINX_0_7_44 +9eda3153223b42932fec477da26be67a8a33b781 NGINX_0_7_45 +56baf312c1b57b425c331a325b7875fd92aff5b8 NGINX_0_7_46 +6866b490272ef912cd285ce6edc2c393546ea947 NGINX_0_7_47 diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,190 @@ +Changes with nginx 0.7.47 01 Apr 2009 + + *) Bugfix: nginx could not be built on FreeBSD 6 and early versions; + the bug had appeared in 0.7.46. + + *) Bugfix: nginx could not be built on MacOSX; the bug had + appeared in 0.7.46. + + *) Bugfix: if the "max_size" parameter was set, then the cache manager + might purge a whole cache; the bug had appeared in 0.7.46. + + *) Change: a segmentation fault might occur in worker process, if the + "proxy_cache"/"fastcgi_cache" and the "proxy_cache_valid"/ + "fastcgi_cache_valid" were set on different levels; the bug had + appeared in 0.7.46. + + *) Bugfix: a segmentation fault might occur in worker process, if a + request was redirected to a proxied or FastCGI server via error_page + or try_files; the bug had appeared in 0.7.44. + + +Changes with nginx 0.7.46 30 Mar 2009 + + *) Bugfix: the previous release tarball was incorrect. + + +Changes with nginx 0.7.45 30 Mar 2009 + + *) Change: now the "proxy_cache" and the "proxy_cache_valid" directives + can be set on different levels. + + *) Change: the "clean_time" parameter of the "proxy_cache_path" + directive is canceled. + + *) Feature: the "max_size" parameter of the "proxy_cache_path" + directive. + + *) Feature: the ngx_http_fastcgi_module preliminary cache support. + + *) Feature: now on shared memory allocation errors directive and zone + names are logged. + + *) Bugfix: the directive "add_header last-modified ''" did not delete a + "Last-Modified" response header line; the bug had appeared in 0.7.44. + + *) Bugfix: a relative path in the "auth_basic_user_file" directive + given without variables did not work; the bug had appeared in + 0.7.44. + Thanks to Jerome Loyet. + + *) Bugfix: in an "alias" directive given using variables without + references to captures of regular expressions; the bug had appeared + in 0.7.42. + + +Changes with nginx 0.7.44 23 Mar 2009 + + *) Feature: the ngx_http_proxy_module preliminary cache support. + + *) Feature: the --with-pcre option in the configure. + + *) Feature: the "try_files" directive is now allowed on the server + block level. + + *) Bugfix: the "try_files" directive handled incorrectly a query string + in a fallback parameter. + + *) Bugfix: the "try_files" directive might test incorrectly directories. + + *) Bugfix: if there is the single server for given address:port pair, + then captures in regular expressions in a "server_name" directive + did not work. + + +Changes with nginx 0.7.43 18 Mar 2009 + + *) Bugfix: a request was handled incorrectly, if a "root" directive + used variables; the bug had appeared in 0.7.42. + + *) Bugfix: if a server listened on wildcard address, then the + $server_addr variable value was "0.0.0.0"; the bug had appeared in + 0.7.36. + + +Changes with nginx 0.7.42 16 Mar 2009 + + *) Change: now the "Invalid argument" error returned by + setsockopt(TCP_NODELAY) on Solaris, is ignored. + + *) Change: now if a file specified in a "auth_basic_user_file" + directive is absent, then the 403 error is returned instead of the + 500 one. + + *) Feature: the "auth_basic_user_file" directive supports variables. + Thanks to Kirill A. Korinskiy. + + *) Feature: the "listen" directive supports the "ipv6only" parameter. + Thanks to Zhang Hua. + + *) Bugfix: in an "alias" directive with references to captures of + regular expressions; the bug had appeared in 0.7.40. + + *) Bugfix: compatibility with Tru64 UNIX. + Thanks to Dustin Marquess. + + *) Bugfix: nginx could not be built without PCRE library; the bug had + appeared in 0.7.41. + + +Changes with nginx 0.7.41 11 Mar 2009 + + *) Bugfix: a segmentation fault might occur in worker process, if a + "server_name" or a "location" directives had captures in regular + expressions; the issue had appeared in 0.7.40. + Thanks to Vladimir Sopot. + + +Changes with nginx 0.7.40 09 Mar 2009 + + *) Feature: the "location" directive supports captures in regular + expressions. + + *) Feature: an "alias" directive with capture references may be used + inside a location given by a regular expression with captures. + + *) Feature: the "server_name" directive supports captures in regular + expressions. + + *) Workaround: the ngx_http_autoindex_module did not show the trailing + slash in directories on XFS filesystem; the issue had appeared in + 0.7.15. + Thanks to Dmitry Kuzmenko. + + +Changes with nginx 0.7.39 02 Mar 2009 + + *) Bugfix: large response with SSI might hang, if gzipping was enabled; + the bug had appeared in 0.7.28. + Thanks to Artem Bokhan. + + *) Bugfix: a segmentation fault might occur in worker process, if short + static variants are used in a "try_files" directive. + + +Changes with nginx 0.7.38 23 Feb 2009 + + *) Feature: authentication failures logging. + + *) Bugfix: name/password in auth_basic_user_file were ignored after odd + number of empty lines. + Thanks to Alexander Zagrebin. + + *) Bugfix: a segmentation fault occurred in a master process, if long + path was used in unix domain socket; the bug had appeared in 0.7.36. + + +Changes with nginx 0.7.37 21 Feb 2009 + + *) Bugfix: directives using upstreams did not work; the bug had + appeared in 0.7.36. + + +Changes with nginx 0.7.36 21 Feb 2009 + + *) Feature: a preliminary IPv6 support; the "listen" directive of the + HTTP module supports IPv6. + + *) Bugfix: the $ancient_browser variable did not work for browsers + preset by a "modern_browser" directives. + + +Changes with nginx 0.7.35 16 Feb 2009 + + *) Bugfix: a "ssl_engine" directive did not use a SSL-accelerator for + asymmetric ciphers. + Thanks to Marcin Gozdalik. + + *) Bugfix: a "try_files" directive set MIME type depending on an + original request extension. + + *) Bugfix: "*domain.tld" names were handled incorrectly in + "server_name", "valid_referers", and "map" directives, if an + ".domain.tld" and ".subdomain.domain.tld" wildcards were used; + the bug had appeared in 0.7.9. + + Changes with nginx 0.7.34 10 Feb 2009 *) Feature: the "off" parameter of the "if_modified_since" directive. @@ -382,7 +568,7 @@ Changes with nginx 0.7.9 *) Bugfix: if the "server_name", "valid_referers", and "map" directives used an "*.domain.tld" wildcard and exact name "domain.tld" was not - set, then the exact name was matched by the wildcard; the bugs had + set, then the exact name was matched by the wildcard; the bug had appeared in 0.3.18. diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,189 @@ +Изменения в nginx 0.7.47 01.04.2009 + + *) Исправление: nginx не собирался на FreeBSD 6 и более ранних версиях; + ошибка появилась в 0.7.46. + + *) Исправление: nginx не собирался на MacOSX; ошибка появилась в 0.7.46. + + *) Исправление: если использовался параметр max_size, то cache manager + мог удалить весь кэш; ошибка появилась в 0.7.46. + + *) Изменение: в рабочем процессе мог произойти segmentation fault, если + директивы proxy_cache/fastcgi_cache и proxy_cache_valid/ + fastcgi_cache_valid не были заданы на одном уровне; ошибка появилась + в 0.7.46. + + *) Исправление: в рабочем процессе мог произойти segmentation fault при + перенаправлении запроса проксированному или FastCGI-серверу с + помощью error_page или try_files; ошибка появилась в 0.7.44. + + +Изменения в nginx 0.7.46 30.03.2009 + + *) Исправление: архив предыдущего релиза был неверным. + + +Изменения в nginx 0.7.45 30.03.2009 + + *) Изменение: теперь директивы proxy_cache и proxy_cache_valid можно + задавать на разных уровнях. + + *) Изменение: параметр clean_time в директиве proxy_cache_path удалён. + + *) Добавление: параметр max_size в директиве proxy_cache_path. + + *) Добавление: предварительная поддержка кэширования в модуле + ngx_http_fastcgi_module. + + *) Добавление: теперь при ошибках выделения в разделяемой памяти в логе + указываются названия директивы и зоны. + + *) Исправление: директива "add_header last-modified ''" не удаляла в + заголовке ответа строку "Last-Modified"; ошибка появилась в 0.7.44. + + *) Исправление: в директиве auth_basic_user_file не работал + относительный путь, заданный строкой без переменных; ошибка + появилась в 0.7.44. + Спасибо Jerome Loyet. + + *) Исправление: в директиве alias, заданной переменными без ссылок на + выделения в регулярных выражениях; ошибка появилась в 0.7.42. + + +Изменения в nginx 0.7.44 23.03.2009 + + *) Добавление: предварительная поддержка кэширования в модуле + ngx_http_proxy_module. + + *) Добавление: параметр --with-pcre в configure. + + *) Добавление: теперь директива try_files может быть использована на + уровне server. + + *) Исправление: директива try_files неправильно обрабатывала строку + запроса в последнем параметре. + + *) Исправление: директива try_files могла неверно тестировать каталоги. + + *) Исправление: если для пары адрес:порт описан только один сервер, то + выделения в регулярных выражениях в директиве server_name не + работали. + + +Изменения в nginx 0.7.43 18.03.2009 + + *) Исправление: запрос обрабатывался неверно, если директива root + использовала переменные; ошибка появилась в 0.7.42. + + *) Исправление: если сервер слушал на адресах типа "*", то значение + переменной $server_addr было "0.0.0.0"; ошибка появилась в 0.7.36. + + +Изменения в nginx 0.7.42 16.03.2009 + + *) Изменение: ошибка "Invalid argument", возвращаемая + setsockopt(TCP_NODELAY) на Solaris, теперь игнорируется. + + *) Изменение: при отсутствии файла, указанного в директиве + auth_basic_user_file, теперь возвращается ошибка 403 вместо 500. + + *) Добавление: директива auth_basic_user_file поддерживает переменные. + Спасибо Кириллу Коринскому. + + *) Добавление: директива listen поддерживает параметр ipv6only. + Спасибо Zhang Hua. + + *) Исправление: в директиве alias со ссылками на выделения в регулярных + выражениях; ошибка появилась в 0.7.40. + + *) Исправление: совместимость с Tru64 UNIX. + Спасибо Dustin Marquess. + + *) Исправление: nginx не собирался без библиотеки PCRE; ошибка + появилась в 0.7.41. + + +Изменения в nginx 0.7.41 11.03.2009 + + *) Исправление: в рабочем процессе мог произойти segmentation fault, + если в server_name или location были выделения в регулярных + выражениях; ошибка появилась в 0.7.40. + Спасибо Владимиру Сопоту. + + +Изменения в nginx 0.7.40 09.03.2009 + + *) Добавление: директива location поддерживает выделения в регулярных + выражениях. + + *) Добавление: директиву alias с ссылками на выделения в регулярных + выражениях можно использовать внутри location'а, заданного + регулярным выражением с выделениями. + + *) Добавление: директива server_name поддерживает выделения в + регулярных выражениях. + + *) Изменение: модуль ngx_http_autoindex_module не показывал последний + слэш для каталогов на файловой системе XFS; ошибка появилась в + 0.7.15. + Спасибо Дмитрию Кузьменко. + + +Изменения в nginx 0.7.39 02.03.2009 + + *) Исправление: при включённом сжатии большие ответы с использованием + SSI могли зависать; ошибка появилась в 0.7.28. + Спасибо Артёму Бохану. + + *) Исправление: при использовании коротких статических вариантов в + директиве try_files в рабочем процессе мог произойти segmentation + fault. + + +Изменения в nginx 0.7.38 23.02.2009 + + *) Добавление: логгирование ошибок аутентификации. + + *) Исправление: имя/пароль, заданные в auth_basic_user_file, + игнорировались после нечётного числа пустых строк. + Спасибо Александру Загребину. + + *) Исправление: при использовании длинного пути в unix domain сокете в + главном процессе происходил segmentation fault; ошибка появилась в + 0.7.36. + + +Изменения в nginx 0.7.37 21.02.2009 + + *) Исправление: директивы, использующие upstream'ы, не работали; ошибка + появилась в 0.7.36. + + +Изменения в nginx 0.7.36 21.02.2009 + + *) Добавление: предварительная поддержка IPv6; директива listen модуля + HTTP поддерживает IPv6. + + *) Исправление: переменная $ancient_browser не работала для браузеров, + заданных директивами modern_browser. + + +Изменения в nginx 0.7.35 16.02.2009 + + *) Исправление: директива ssl_engine не использовала SSL-акселератор + для асимметричных шифров. + Спасибо Marcin Gozdalik. + + *) Исправление: директива try_files выставляла MIME-type, исходя из + расширения первоначального запроса. + + *) Исправление: в директивах server_name, valid_referers и map + неправильно обрабатывались имена вида "*domain.tld", если + использовались маски вида ".domain.tld" и ".subdomain.domain.tld"; + ошибка появилась в 0.7.9. + + Изменения в nginx 0.7.34 10.02.2009 *) Добавление: параметр off в директиве if_modified_since. diff --git a/auto/cc/msvc b/auto/cc/msvc --- a/auto/cc/msvc +++ b/auto/cc/msvc @@ -2,7 +2,9 @@ # Copyright (C) Igor Sysoev -# MSVC 6.0 SP2, MSVC Toolkit 2003 (7.1), MSVC 2005 Express Edition SP1 (8.0) +# MSVC 6.0 SP2 +# MSVC Toolkit 2003 (7.1) +# MSVC 2005 Express Edition SP1 (8.0) # optimizations @@ -76,13 +78,11 @@ LINK="\$(CC)" # the link flags CORE_LINK="$CORE_LINK -link -verbose:lib" -if [ $NGX_CC_NAME = msvc7 ]; then - # link with libcmt.lib, multithreaded - LIBC="-MT" -else - # link with msvcrt.dll - LIBC="-MD" -fi +# link with libcmt.lib, multithreaded +LIBC="-MT" +# link with msvcrt.dll +# however, MSVC Toolkit 2003 has no MSVCRT.LIB +#LIBC="-MD" CFLAGS="$CFLAGS $LIBC" diff --git a/auto/headers b/auto/headers --- a/auto/headers +++ b/auto/headers @@ -2,8 +2,11 @@ # Copyright (C) Igor Sysoev -ngx_include="unistd.h"; . auto/include -ngx_include="inttypes.h"; . auto/include -ngx_include="limits.h"; . auto/include -ngx_include="sys/filio.h"; . auto/include -ngx_include="crypt.h"; . auto/include +ngx_include="unistd.h"; . auto/include +ngx_include="inttypes.h"; . auto/include +ngx_include="limits.h"; . auto/include +ngx_include="sys/filio.h"; . auto/include +ngx_include="sys/param.h"; . auto/include +ngx_include="sys/mount.h"; . auto/include +ngx_include="sys/statvfs.h"; . auto/include +ngx_include="crypt.h"; . auto/include diff --git a/auto/include b/auto/include --- a/auto/include +++ b/auto/include @@ -16,6 +16,7 @@ ngx_found=no cat << END > $NGX_AUTOTEST.c +$NGX_INCLUDE_SYS_PARAM_H #include <$ngx_include> int main() { diff --git a/auto/modules b/auto/modules --- a/auto/modules +++ b/auto/modules @@ -65,6 +65,13 @@ if [ $HTTP != YES ]; then fi +if [ $HTTP_CACHE = YES ]; then + USE_MD5=YES + have=NGX_HTTP_CACHE . auto/have + HTTP_SRCS="$HTTP_SRCS $HTTP_FILE_CACHE_SRCS" +fi + + if [ $HTTP_SSI = YES ]; then HTTP_POSTPONE=YES fi @@ -305,11 +312,6 @@ if [ $HTTP_UPSTREAM_IP_HASH = YES ]; the HTTP_SRCS="$HTTP_SRCS $HTTP_UPSTREAM_IP_HASH_SRCS" fi -# STUB -#USE_MD5=YES -#HTTP_SRCS="$HTTP_SRCS $HTTP_CACHE_SRCS" -#HTTP_SRCS="$HTTP_SRCS $HTTP_FILE_CACHE_SRCS" - if [ $HTTP_STUB_STATUS = YES ]; then have=NGX_STAT_STUB . auto/have HTTP_MODULES="$HTTP_MODULES ngx_http_stub_status_module" diff --git a/auto/options b/auto/options --- a/auto/options +++ b/auto/options @@ -43,6 +43,8 @@ EVENT_AIO=NO USE_THREADS=NO +NGX_IPV6=NO + HTTP=YES NGX_HTTP_LOG_PATH= @@ -50,6 +52,7 @@ NGX_HTTP_CLIENT_TEMP_PATH= NGX_HTTP_PROXY_TEMP_PATH= NGX_HTTP_FASTCGI_TEMP_PATH= +HTTP_CACHE=YES HTTP_CHARSET=YES HTTP_GZIP=YES HTTP_SSL=NO @@ -160,7 +163,11 @@ do #--with-threads=*) USE_THREADS="$value" ;; #--with-threads) USE_THREADS="pthreads" ;; + --with-ipv6) NGX_IPV6=YES ;; + --without-http) HTTP=NO ;; + --without-http-cache) HTTP_CACHE=NO ;; + --http-log-path=*) NGX_HTTP_LOG_PATH="$value" ;; --http-client-body-temp-path=*) NGX_HTTP_CLIENT_TEMP_PATH="$value" ;; --http-proxy-temp-path=*) NGX_HTTP_PROXY_TEMP_PATH="$value" ;; @@ -227,6 +234,7 @@ do --with-debug) NGX_DEBUG=YES ;; --without-pcre) USE_PCRE=DISABLED ;; + --with-pcre) USE_PCRE=YES ;; --with-pcre=*) PCRE="$value" ;; --with-pcre-opt=*) PCRE_OPT="$value" ;; @@ -285,6 +293,8 @@ cat << END --with-poll_module enable poll module --without-poll_module disable poll module + --with-ipv6 enable ipv6 support + --with-http_ssl_module enable ngx_http_ssl_module --with-http_realip_module enable ngx_http_realip_module --with-http_addition_module enable ngx_http_addition_module @@ -330,6 +340,7 @@ cat << END files --without-http disable HTTP server + --without-http-cache disable HTTP cache --with-mail enable POP3/IMAP4/SMTP proxy module --with-mail_ssl_module enable ngx_mail_ssl_module @@ -350,7 +361,8 @@ cat << END pentium, pentiumpro, pentium3, pentium4, athlon, opteron, sparc32, sparc64, ppc64 - --without-pcre disable PCRE libarary usage + --without-pcre disable PCRE library usage + --with-pcre force PCRE library usage --with-pcre=DIR set path to PCRE library sources --with-pcre-opt=OPTIONS set additional options for PCRE building diff --git a/auto/os/features b/auto/os/features --- a/auto/os/features +++ b/auto/os/features @@ -98,7 +98,7 @@ if test -z "$NGX_KQUEUE_CHECKED"; then ngx_feature_name="NGX_HAVE_TIMER_EVENT" ngx_feature_run=yes ngx_feature_incs="#include -#include " + #include " ngx_feature_path= ngx_feature_libs= ngx_feature_test="int kq; @@ -205,3 +205,28 @@ ngx_feature_path= ngx_feature_libs= ngx_feature_test="directio(0, DIRECTIO_ON);" . auto/feature + + +ngx_feature="statfs()" +ngx_feature_name="NGX_HAVE_STATFS" +ngx_feature_run=no +ngx_feature_incs="$NGX_INCLUDE_SYS_PARAM_H + $NGX_INCLUDE_SYS_MOUNT_H + $NGX_INCLUDE_SYS_VFS_H" +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="struct statfs fs; + statfs(NULL, &fs);" +. auto/feature + + +ngx_feature="statvfs()" +ngx_feature_name="NGX_HAVE_STATVFS" +ngx_feature_run=no +ngx_feature_incs="#include + #include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="struct statvfs fs; + statvfs(NULL, &fs);" +. auto/feature diff --git a/auto/os/linux b/auto/os/linux --- a/auto/os/linux +++ b/auto/os/linux @@ -11,7 +11,8 @@ CORE_SRCS="$UNIX_SRCS $LINUX_SRCS" ngx_spacer=' ' -CC_AUX_FLAGS="$CC_AUX_FLAGS -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64" +cc_aux_flags="$CC_AUX_FLAGS" +CC_AUX_FLAGS="$cc_aux_flags -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64" # Linux kernel version @@ -60,12 +61,12 @@ fi # sendfile() -CC_AUX_FLAGS="$CC_AUX_FLAGS -D_GNU_SOURCE" +CC_AUX_FLAGS="$cc_aux_flags -D_GNU_SOURCE" ngx_feature="sendfile()" ngx_feature_name="NGX_HAVE_SENDFILE" ngx_feature_run=yes ngx_feature_incs="#include -#include " + #include " ngx_feature_path= ngx_feature_libs= ngx_feature_test="int s = 0, fd = 1; @@ -81,12 +82,12 @@ fi # sendfile64() -CC_AUX_FLAGS="$CC_AUX_FLAGS -D_FILE_OFFSET_BITS=64" +CC_AUX_FLAGS="$cc_aux_flags -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64" ngx_feature="sendfile64()" ngx_feature_name="NGX_HAVE_SENDFILE64" ngx_feature_run=yes ngx_feature_incs="#include -#include " + #include " ngx_feature_path= ngx_feature_libs= ngx_feature_test="int s = 0, fd = 1; @@ -121,3 +122,9 @@ ngx_feature_libs= ngx_feature_test="long mask = 0; sched_setaffinity(0, 32, (cpu_set_t *) &mask)" . auto/feature + + +ngx_include="sys/vfs.h"; . auto/include + + +CC_AUX_FLAGS=$cc_aux_flags diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -33,8 +33,7 @@ CORE_DEPS="src/core/nginx.h \ src/core/ngx_cycle.h \ src/core/ngx_conf_file.h \ src/core/ngx_resolver.h \ - src/core/ngx_open_file_cache.h \ - src/core/ngx_garbage_collector.h" + src/core/ngx_open_file_cache.h" CORE_SRCS="src/core/nginx.c \ @@ -62,8 +61,7 @@ CORE_SRCS="src/core/nginx.c \ src/core/ngx_cpuinfo.c \ src/core/ngx_conf_file.c \ src/core/ngx_resolver.c \ - src/core/ngx_open_file_cache.c \ - src/core/ngx_garbage_collector.c" + src/core/ngx_open_file_cache.c" REGEX_DEPS=src/core/ngx_regex.h @@ -254,8 +252,6 @@ HTTP_MODULES="ngx_http_module \ ngx_http_log_module \ ngx_http_upstream_module" -HTTP_CACHE_MODULE=ngx_http_cache_module - HTTP_WRITE_FILTER_MODULE="ngx_http_write_filter_module" HTTP_HEADER_FILTER_MODULE="ngx_http_header_filter_module" @@ -313,7 +309,6 @@ HTTP_SRCS="$HTTP_SRCS src/http/ngx_http_ HTTP_POSTPONE_FILTER_SRCS=src/http/ngx_http_postpone_filter_module.c -HTTP_CACHE_SRCS=src/http/ngx_http_cache.c HTTP_FILE_CACHE_SRCS=src/http/ngx_http_file_cache.c diff --git a/auto/unix b/auto/unix --- a/auto/unix +++ b/auto/unix @@ -64,6 +64,21 @@ ngx_param=NGX_TIME_T_LEN; ngx_value=$ngx # syscalls, libc calls and some features +if [ $NGX_IPV6 = YES ]; then + ngx_feature="AF_INET6" + ngx_feature_name="NGX_HAVE_INET6" + ngx_feature_run=no + ngx_feature_incs="#include + #include + #include " + ngx_feature_path= + ngx_feature_libs= + ngx_feature_test="struct sockaddr_in6 sin6; + sin6.sin6_family = AF_INET6;" + . auto/feature +fi + + ngx_feature="setproctitle()" ngx_feature_name="NGX_HAVE_SETPROCTITLE" ngx_feature_run=no @@ -175,8 +190,8 @@ ngx_feature='mmap("/dev/zero", MAP_SHARE ngx_feature_name="NGX_HAVE_MAP_DEVZERO" ngx_feature_run=yes ngx_feature_incs="#include -#include -#include " + #include + #include " ngx_feature_path= ngx_feature_libs= ngx_feature_test='void *p; int fd; @@ -190,7 +205,7 @@ ngx_feature="System V shared memory" ngx_feature_name="NGX_HAVE_SYSVSHM" ngx_feature_run=yes ngx_feature_incs="#include -#include " + #include " ngx_feature_path= ngx_feature_libs= ngx_feature_test="int id; @@ -214,7 +229,7 @@ ngx_feature="ioctl(FIONBIO)" ngx_feature_name="NGX_HAVE_FIONBIO" ngx_feature_run=no ngx_feature_incs="#include -$NGX_INCLUDE_SYS_FILIO_H" + $NGX_INCLUDE_SYS_FILIO_H" ngx_feature_path= ngx_feature_libs= ngx_feature_test="int i; i = FIONBIO" diff --git a/src/core/nginx.c b/src/core/nginx.c --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -388,7 +388,7 @@ ngx_add_inherited_sockets(ngx_cycle_t *c if (ngx_array_init(&cycle->listening, cycle->pool, 10, sizeof(ngx_listening_t)) - == NGX_ERROR) + != NGX_OK) { return NGX_ERROR; } @@ -838,7 +838,7 @@ ngx_core_module_init_conf(ngx_cycle_t *c ccf->pid.data = (u_char *) NGX_PID_PATH; } - if (ngx_conf_full_name(cycle, &ccf->pid, 0) == NGX_ERROR) { + if (ngx_conf_full_name(cycle, &ccf->pid, 0) != NGX_OK) { return NGX_CONF_ERROR; } @@ -858,7 +858,7 @@ ngx_core_module_init_conf(ngx_cycle_t *c ccf->lock_file.data = (u_char *) NGX_LOCK_PATH; } - if (ngx_conf_full_name(cycle, &ccf->lock_file, 0) == NGX_ERROR) { + if (ngx_conf_full_name(cycle, &ccf->lock_file, 0) != NGX_OK) { return NGX_CONF_ERROR; } diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,7 +8,8 @@ #define _NGINX_H_INCLUDED_ -#define NGINX_VERSION "0.7.34" +#define nginx_version 007047 +#define NGINX_VERSION "0.7.47" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -741,7 +741,7 @@ ngx_conf_include(ngx_conf_t *cf, ngx_com ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data); - if (ngx_conf_full_name(cf->cycle, &file, 1) == NGX_ERROR) { + if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK) { return NGX_CONF_ERROR; } @@ -854,7 +854,7 @@ ngx_conf_open_file(ngx_cycle_t *cycle, n if (name) { full = *name; - if (ngx_conf_full_name(cycle, &full, 0) == NGX_ERROR) { + if (ngx_conf_full_name(cycle, &full, 0) != NGX_OK) { return NULL; } diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -52,7 +52,6 @@ ngx_listening_inet_stream_socket(ngx_con ls->type = SOCK_STREAM; ls->sockaddr = (struct sockaddr *) sin; ls->socklen = sizeof(struct sockaddr_in); - ls->addr = offsetof(struct sockaddr_in, sin_addr); ls->addr_text_max_len = NGX_INET_ADDRSTRLEN; return ls; @@ -65,7 +64,6 @@ ngx_set_inherited_sockets(ngx_cycle_t *c size_t len; ngx_uint_t i; ngx_listening_t *ls; - struct sockaddr_in *sin; socklen_t olen; #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) ngx_err_t err; @@ -94,33 +92,39 @@ ngx_set_inherited_sockets(ngx_cycle_t *c continue; } - sin = (struct sockaddr_in *) ls[i].sockaddr; + switch (ls[i].sockaddr->sa_family) { - if (sin->sin_family != AF_INET) { +#if (NGX_HAVE_INET6) + case AF_INET6: + ls[i].addr_text_max_len = NGX_INET6_ADDRSTRLEN; + break; +#endif + + case AF_INET: + ls[i].addr_text_max_len = NGX_INET_ADDRSTRLEN; + break; + + default: ngx_log_error(NGX_LOG_CRIT, cycle->log, ngx_socket_errno, "the inherited socket #%d has " - "unsupported family", ls[i].fd); + "an unsupported protocol family", ls[i].fd); ls[i].ignore = 1; continue; } - ls[i].addr_text_max_len = NGX_INET_ADDRSTRLEN; + len = ls[i].addr_text_max_len + sizeof(":65535") - 1; - ls[i].addr_text.data = ngx_pnalloc(cycle->pool, - NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1); + ls[i].addr_text.data = ngx_pnalloc(cycle->pool, len); if (ls[i].addr_text.data == NULL) { return NGX_ERROR; } - len = ngx_sock_ntop(ls[i].sockaddr, ls[i].addr_text.data, - NGX_INET_ADDRSTRLEN); + len = ngx_sock_ntop(ls[i].sockaddr, ls[i].addr_text.data, len, 1); if (len == 0) { return NGX_ERROR; } - ls[i].addr_text.len = ngx_sprintf(ls[i].addr_text.data + len, ":%d", - ntohs(sin->sin_port)) - - ls[i].addr_text.data; + ls[i].addr_text.len = len; ls[i].backlog = NGX_LISTEN_BACKLOG; @@ -278,6 +282,23 @@ ngx_open_listening_sockets(ngx_cycle_t * return NGX_ERROR; } +#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) + + if (ls[i].sockaddr->sa_family == AF_INET6 && ls[i].ipv6only) { + int ipv6only; + + ipv6only = (ls[i].ipv6only == 1); + + if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, + (const void *) &ipv6only, sizeof(int)) + == -1) + { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, + "setsockopt(IPV6_V6ONLY) %V failed, ignored", + &ls[i].addr_text); + } + } +#endif /* TODO: close on exit */ if (!(ngx_event_flags & NGX_USE_AIO_EVENT)) { @@ -778,12 +799,16 @@ ngx_connection_error(ngx_connection_t *c { ngx_uint_t level; - if (err == NGX_ECONNRESET - && c->log_error == NGX_ERROR_IGNORE_ECONNRESET) - { + if (err == NGX_ECONNRESET && c->log_error == NGX_ERROR_IGNORE_ECONNRESET) { return 0; } +#if (NGX_SOLARIS) + if (err == NGX_EINVAL && c->log_error == NGX_ERROR_IGNORE_EINVAL) { + return 0; + } +#endif + if (err == 0 || err == NGX_ECONNRESET #if !(NGX_WIN32) @@ -799,6 +824,7 @@ ngx_connection_error(ngx_connection_t *c { switch (c->log_error) { + case NGX_ERROR_IGNORE_EINVAL: case NGX_ERROR_IGNORE_ECONNRESET: case NGX_ERROR_INFO: level = NGX_LOG_INFO; diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -19,7 +19,6 @@ struct ngx_listening_s { struct sockaddr *sockaddr; socklen_t socklen; /* size of sockaddr */ - size_t addr; /* offset to address in sockaddr */ size_t addr_text_max_len; ngx_str_t addr_text; @@ -57,6 +56,10 @@ struct ngx_listening_s { unsigned shared:1; /* shared between threads or processes */ unsigned addr_ntop:1; +#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) + unsigned ipv6only:2; +#endif + #if (NGX_HAVE_DEFERRED_ACCEPT) unsigned deferred_accept:1; unsigned delete_deferred:1; @@ -70,10 +73,11 @@ struct ngx_listening_s { typedef enum { - NGX_ERROR_CRIT = 0, + NGX_ERROR_ALERT = 0, NGX_ERROR_ERR, NGX_ERROR_INFO, - NGX_ERROR_IGNORE_ECONNRESET + NGX_ERROR_IGNORE_ECONNRESET, + NGX_ERROR_IGNORE_EINVAL } ngx_connection_log_error_e; @@ -123,10 +127,8 @@ struct ngx_connection_s { ngx_ssl_connection_t *ssl; #endif -#if (NGX_HAVE_IOCP) struct sockaddr *local_sockaddr; socklen_t local_socklen; -#endif ngx_buf_t *buffer; @@ -134,7 +136,7 @@ struct ngx_connection_s { unsigned buffered:8; - unsigned log_error:2; /* ngx_connection_log_error_e */ + unsigned log_error:3; /* ngx_connection_log_error_e */ unsigned single_connection:1; unsigned unexpected_eof:1; diff --git a/src/core/ngx_cpuinfo.c b/src/core/ngx_cpuinfo.c --- a/src/core/ngx_cpuinfo.c +++ b/src/core/ngx_cpuinfo.c @@ -72,7 +72,7 @@ void ngx_cpuinfo(void) { u_char *vendor; - uint32_t vbuf[5], cpu[4]; + uint32_t vbuf[5], cpu[4], model; vbuf[0] = 0; vbuf[1] = 0; @@ -103,8 +103,10 @@ ngx_cpuinfo(void) case 6: ngx_cacheline_size = 32; - if ((cpu[0] & 0xf0) >= 0xd0) { - /* Intel Core */ + model = ((cpu[0] & 0xf0000) >> 8) | (cpu[0] & 0xf0); + + if (model >= 0xd0) { + /* Intel Core, Core 2, Atom */ ngx_cacheline_size = 64; } 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 @@ -136,7 +136,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) } if (ngx_list_init(&cycle->open_files, pool, n, sizeof(ngx_open_file_t)) - == NGX_ERROR) + != NGX_OK) { ngx_destroy_pool(pool); return NULL; @@ -155,7 +155,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) } if (ngx_list_init(&cycle->shared_memory, pool, n, sizeof(ngx_shm_zone_t)) - == NGX_ERROR) + != NGX_OK) { ngx_destroy_pool(pool); return NULL; @@ -359,8 +359,9 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) continue; } - file[i].fd = ngx_open_file(file[i].name.data, NGX_FILE_RDWR, - NGX_FILE_CREATE_OR_OPEN|NGX_FILE_APPEND, + file[i].fd = ngx_open_file(file[i].name.data, + NGX_FILE_APPEND, + NGX_FILE_CREATE_OR_OPEN, NGX_FILE_DEFAULT_ACCESS); ngx_log_debug3(NGX_LOG_DEBUG_CORE, log, 0, @@ -876,23 +877,47 @@ ngx_destroy_cycle_pools(ngx_conf_t *conf static ngx_int_t ngx_cmp_sockaddr(struct sockaddr *sa1, struct sockaddr *sa2) { - struct sockaddr_in *sin1, *sin2; + struct sockaddr_in *sin1, *sin2; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin61, *sin62; +#endif - /* AF_INET only */ - - if (sa1->sa_family != AF_INET || sa2->sa_family != AF_INET) { + if (sa1->sa_family != sa2->sa_family) { return NGX_DECLINED; } - sin1 = (struct sockaddr_in *) sa1; - sin2 = (struct sockaddr_in *) sa2; + switch (sa1->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin61 = (struct sockaddr_in6 *) sa1; + sin62 = (struct sockaddr_in6 *) sa2; + + if (sin61->sin6_port != sin61->sin6_port) { + return NGX_DECLINED; + } + + if (ngx_memcmp(&sin61->sin6_addr, &sin62->sin6_addr, 16) != 0) { + return NGX_DECLINED; + } - if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) { - return NGX_DECLINED; - } + break; +#endif + + default: /* AF_INET */ + + sin1 = (struct sockaddr_in *) sa1; + sin2 = (struct sockaddr_in *) sa2; - if (sin1->sin_port != sin2->sin_port) { - return NGX_DECLINED; + if (sin1->sin_port != sin2->sin_port) { + return NGX_DECLINED; + } + + if (sin1->sin_addr.s_addr != sin2->sin_addr.s_addr) { + return NGX_DECLINED; + } + + break; } return NGX_OK; @@ -1040,9 +1065,8 @@ ngx_reopen_files(ngx_cycle_t *cycle, ngx file[i].pos = file[i].buffer; } - fd = ngx_open_file(file[i].name.data, NGX_FILE_RDWR, - NGX_FILE_CREATE_OR_OPEN|NGX_FILE_APPEND, - NGX_FILE_DEFAULT_ACCESS); + fd = ngx_open_file(file[i].name.data, NGX_FILE_APPEND, + NGX_FILE_CREATE_OR_OPEN, NGX_FILE_DEFAULT_ACCESS); ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "reopen file \"%s\", old:%d new:%d", 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 @@ -259,12 +259,12 @@ ngx_conf_set_path_slot(ngx_conf_t *cf, n path->name.len--; } - if (ngx_conf_full_name(cf->cycle, &path->name, 0) == NGX_ERROR) { + if (ngx_conf_full_name(cf->cycle, &path->name, 0) != NGX_OK) { return NULL; } path->len = 0; - path->cleaner = (ngx_gc_handler_pt) cmd->post; + path->manager = (ngx_path_manager_pt) cmd->post; path->conf_file = cf->conf_file->file.name.data; path->line = cf->conf_file->line; @@ -293,6 +293,49 @@ ngx_conf_set_path_slot(ngx_conf_t *cf, n char * +ngx_conf_merge_path_value(ngx_conf_t *cf, ngx_path_t **path, ngx_path_t *prev, + ngx_path_init_t *init) +{ + if (*path) { + return NGX_CONF_OK; + } + + if (prev) { + *path = prev; + return NGX_CONF_OK; + } + + *path = ngx_palloc(cf->pool, sizeof(ngx_path_t)); + if (*path == NULL) { + return NGX_CONF_ERROR; + } + + (*path)->name = init->name; + + if (ngx_conf_full_name(cf->cycle, &(*path)->name, 0) != NGX_OK) { + return NGX_CONF_ERROR; + } + + (*path)->level[0] = init->level[0]; + (*path)->level[1] = init->level[1]; + (*path)->level[2] = init->level[2]; + + (*path)->len = init->level[0] + (init->level[0] ? 1 : 0) + + init->level[1] + (init->level[1] ? 1 : 0) + + init->level[2] + (init->level[2] ? 1 : 0); + + (*path)->manager = NULL; + (*path)->conf_file = NULL; + + if (ngx_add_path(cf, path) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +char * ngx_conf_set_access_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *confp = conf; 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 @@ -11,65 +11,73 @@ #include #include -typedef struct ngx_path_s ngx_path_t; - -#include - struct ngx_file_s { - ngx_fd_t fd; - ngx_str_t name; - ngx_file_info_t info; + ngx_fd_t fd; + ngx_str_t name; + ngx_file_info_t info; - off_t offset; - off_t sys_offset; + off_t offset; + off_t sys_offset; - ngx_log_t *log; + ngx_log_t *log; - unsigned valid_info:1; - unsigned directio:1; + unsigned valid_info:1; + unsigned directio:1; }; #define NGX_MAX_PATH_LEVEL 3 -struct ngx_path_s { - ngx_str_t name; - size_t len; - size_t level[3]; - ngx_gc_handler_pt cleaner; + +typedef time_t (*ngx_path_manager_pt) (void *data); + - u_char *conf_file; - ngx_uint_t line; -}; +typedef struct { + ngx_str_t name; + size_t len; + size_t level[3]; + + ngx_path_manager_pt manager; + void *data; + + u_char *conf_file; + ngx_uint_t line; +} ngx_path_t; typedef struct { - ngx_file_t file; - off_t offset; - ngx_path_t *path; - ngx_pool_t *pool; - char *warn; + ngx_str_t name; + size_t level[3]; +} ngx_path_init_t; + - ngx_uint_t access; +typedef struct { + ngx_file_t file; + off_t offset; + ngx_path_t *path; + ngx_pool_t *pool; + char *warn; - unsigned log_level:8; - unsigned persistent:1; - unsigned clean:1; + ngx_uint_t access; + + unsigned log_level:8; + unsigned persistent:1; + unsigned clean:1; } ngx_temp_file_t; typedef struct { - ngx_uint_t access; - ngx_uint_t path_access; - time_t time; - ngx_fd_t fd; - ngx_err_t rename_error; + ngx_uint_t access; + 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; + unsigned create_path:1; + unsigned delete_file:1; + unsigned log_rename_error:1; - ngx_log_t *log; + ngx_log_t *log; } ngx_ext_rename_file_t; @@ -113,40 +121,9 @@ 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); +char *ngx_conf_merge_path_value(ngx_conf_t *cf, ngx_path_t **path, + ngx_path_t *prev, ngx_path_init_t *init); char *ngx_conf_set_access_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -#define ngx_conf_merge_path_value(curr, prev, path, l1, l2, l3, clean, cf) \ - if (curr == NULL) { \ - if (prev == NULL) { \ - curr = ngx_palloc(cf->pool, sizeof(ngx_path_t)); \ - if (curr == NULL) { \ - return NGX_CONF_ERROR; \ - } \ - \ - curr->name.len = sizeof(path) - 1; \ - curr->name.data = (u_char *) path; \ - \ - if (ngx_conf_full_name(cf->cycle, &curr->name, 0) == NGX_ERROR) { \ - return NGX_CONF_ERROR; \ - } \ - \ - curr->level[0] = l1; \ - curr->level[1] = l2; \ - curr->level[2] = l3; \ - curr->len = l1 + l2 + l3 + (l1 ? 1:0) + (l2 ? 1:0) + (l3 ? 1:0); \ - curr->cleaner = clean; \ - curr->conf_file = NULL; \ - \ - if (ngx_add_path(cf, &curr) == NGX_ERROR) { \ - return NGX_CONF_ERROR; \ - } \ - \ - } else { \ - curr = prev; \ - } \ - } - - - #endif /* _NGX_FILE_H_INCLUDED_ */ diff --git a/src/core/ngx_garbage_collector.c b/src/core/ngx_garbage_collector.c deleted file mode 100644 --- a/src/core/ngx_garbage_collector.c +++ /dev/null @@ -1,217 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#include -#include - - - -ngx_int_t ngx_collect_garbage(ngx_gc_t *ctx, ngx_str_t *dname, ngx_int_t level) -{ - int rc; - u_char *last; - size_t len; - ngx_err_t err; - ngx_str_t fname, buf; - ngx_dir_t dir; - - buf.len = 0; -#if (NGX_SUPPRESS_WARN) - buf.data = NULL; - fname.data = NULL; -#endif - - ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->log, 0, - "gc dir \"%s\":%d", dname->data, dname->len); - - if (ngx_open_dir(dname, &dir) == NGX_ERROR) { - ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, - ngx_open_dir_n " \"%s\" failed", dname->data); - return NGX_ERROR; - } - - for ( ;; ) { - ngx_set_errno(0); - if (ngx_read_dir(&dir) == NGX_ERROR) { - err = ngx_errno; - - if (err != NGX_ENOMOREFILES) { - ngx_log_error(NGX_LOG_CRIT, ctx->log, err, - ngx_read_dir_n " \"%s\" failed", dname->data); - rc = NGX_ERROR; - - } else { - rc = NGX_OK; - } - - break; - } - - len = ngx_de_namelen(&dir); - - ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->log, 0, - "gc name \"%s\":%d", ngx_de_name(&dir), len); - - if (len == 1 && ngx_de_name(&dir)[0] == '.') { - continue; - } - - if (len == 2 - && ngx_de_name(&dir)[0] == '.' - && ngx_de_name(&dir)[1] == '.') - { - continue; - } - - fname.len = dname->len + 1+ len; - - if (fname.len + NGX_DIR_MASK_LEN > buf.len) { - - if (buf.len) { - ngx_free(buf.data); - } - - buf.len = dname->len + 1 + len + NGX_DIR_MASK_LEN; - - buf.data = ngx_alloc(buf.len + 1, ctx->log); - if (buf.data == NULL) { - return NGX_ABORT; - } - } - - last = ngx_cpymem(buf.data, dname->data, dname->len); - *last++ = '/'; - ngx_memcpy(last, ngx_de_name(&dir), len + 1); - fname.data = buf.data; - - ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, - "gc path: \"%s\"", fname.data); - - if (!dir.valid_info) { - if (ngx_de_info(fname.data, &dir) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, - ngx_de_info_n " \"%s\" failed", fname.data); - continue; - } - } - - if (ngx_de_is_dir(&dir)) { - - ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, - "gc enter dir \"%s\"", fname.data); - - if (level == -1 - /* there can not be directory on the last level */ - || level == NGX_MAX_PATH_LEVEL - /* an directory from the old path hierarchy */ - || len != ctx->path->level[level]) - { - if (ngx_collect_garbage(ctx, &fname, -1) == NGX_ABORT) { - return NGX_ABORT; - } - - fname.data[fname.len] = '\0'; - - ngx_log_error(NGX_LOG_NOTICE, ctx->log, 0, - "delete old hierachy directory \"%s\"", - fname.data); - - if (ngx_delete_dir(fname.data) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, - ngx_delete_dir_n " \"%s\" failed", - fname.data); - } else { - ctx->deleted++; - ctx->freed += ngx_de_size(&dir); - } - - continue; - } - - if (ngx_collect_garbage(ctx, &fname, level + 1) == NGX_ABORT) { - return NGX_ABORT; - } - - } else if (ngx_de_is_file(&dir)) { - - ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0, - "gc file \"%s\"", fname.data); - - if (level == -1 - || (level < NGX_MAX_PATH_LEVEL && ctx->path->level[level] != 0)) - { - if (ngx_delete_file(fname.data) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, - ngx_delete_file_n " \"%s\" failed", - fname.data); - } else { - ctx->deleted++; - ctx->freed += ngx_de_size(&dir); - } - - continue; - } - - if (ctx->handler(ctx, &fname, &dir) == NGX_ABORT) { - return NGX_ABORT; - } - - } else { - ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, - "the file \"%s\" has unknown type, deleting", - fname.data); - - if (ngx_delete_file(fname.data) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, - ngx_delete_file_n " \"%s\" failed", fname.data); - } else { - ctx->deleted++; - ctx->freed += ngx_de_size(&dir); - } - } - } - - if (buf.len) { - ngx_free(buf.data); - } - - if (ngx_close_dir(&dir) == NGX_ERROR) { - ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, - ngx_close_dir_n " \"%s\" failed", fname.data); - } - - return rc; -} - - -ngx_int_t ngx_garbage_collector_temp_handler(ngx_gc_t *ctx, ngx_str_t *name, - ngx_dir_t *dir) -{ - /* - * We use mtime only and do not use atime because: - * on NTFS access time has a resolution of 1 hour, - * on NT FAT access time has a resolution of 1 day, - * Unices have the mount option "noatime". - */ - - if (ngx_time() - ngx_de_mtime(dir) < 3600) { - return NGX_OK; - } - - ngx_log_error(NGX_LOG_NOTICE, ctx->log, 0, - "delete the stale temporary file \"%s\"", name->data); - - if (ngx_delete_file(name->data) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, - ngx_delete_file_n " \"%s\" failed", name->data); - return NGX_ERROR; - } - - ctx->deleted++; - ctx->freed += ngx_de_size(dir); - - return NGX_OK; -} diff --git a/src/core/ngx_garbage_collector.h b/src/core/ngx_garbage_collector.h deleted file mode 100644 --- a/src/core/ngx_garbage_collector.h +++ /dev/null @@ -1,31 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#ifndef _NGX_GARBAGE_COLLECTOR_H_INCLUDED_ -#define _NGX_GARBAGE_COLLECTOR_H_INCLUDED_ - - -typedef struct ngx_gc_s ngx_gc_t; - -typedef ngx_int_t (*ngx_gc_handler_pt) (ngx_gc_t *ctx, ngx_str_t *name, - ngx_dir_t *dir); - - -struct ngx_gc_s { - ngx_path_t *path; - u_int deleted; - off_t freed; - ngx_gc_handler_pt handler; - ngx_log_t *log; -}; - - -ngx_int_t ngx_collect_garbage(ngx_gc_t *ctx, ngx_str_t *dname, ngx_int_t level); -ngx_int_t ngx_garbage_collector_temp_handler(ngx_gc_t *ctx, ngx_str_t *name, - ngx_dir_t *dir); - - -#endif /* _NGX_GARBAGE_COLLECTOR_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 @@ -589,7 +589,7 @@ ngx_hash_wildcard_init(ngx_hash_init_t * wdc->value = names[n].value; } - name->value = (void *) ((uintptr_t) wdc | (dot ? 3 : 1)); + name->value = (void *) ((uintptr_t) wdc | (dot ? 3 : 2)); } else if (dot) { name->value = (void *) ((uintptr_t) name->value | 1); diff --git a/src/core/ngx_inet.c b/src/core/ngx_inet.c --- a/src/core/ngx_inet.c +++ b/src/core/ngx_inet.c @@ -8,11 +8,13 @@ #include +#if (NGX_HAVE_INET6) +static size_t ngx_inet6_ntop(u_char *p, u_char *text, size_t len); +#endif static ngx_int_t ngx_parse_unix_domain_url(ngx_pool_t *pool, ngx_url_t *u); static ngx_int_t ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u); - +static ngx_int_t ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u); -/* AF_INET only */ in_addr_t ngx_inet_addr(u_char *text, size_t len) @@ -57,25 +59,58 @@ ngx_inet_addr(u_char *text, size_t len) } -/* AF_INET only */ - size_t -ngx_sock_ntop(struct sockaddr *sa, u_char *text, size_t len) +ngx_sock_ntop(struct sockaddr *sa, u_char *text, size_t len, ngx_uint_t port) { - u_char *p; - struct sockaddr_in *sin; + u_char *p; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + size_t n; + struct sockaddr_in6 *sin6; +#endif - if (sa->sa_family == AF_INET) { + switch (sa->sa_family) { + + case AF_INET: sin = (struct sockaddr_in *) sa; p = (u_char *) &sin->sin_addr; - return ngx_snprintf(text, len, "%ud.%ud.%ud.%ud", - p[0], p[1], p[2], p[3]) - - text; + if (port) { + p = ngx_snprintf(text, len, "%ud.%ud.%ud.%ud:%d", + p[0], p[1], p[2], p[3], ntohs(sin->sin_port)); + } else { + p = ngx_snprintf(text, len, "%ud.%ud.%ud.%ud", + p[0], p[1], p[2], p[3]); + } + + return (p - text); + +#if (NGX_HAVE_INET6) + + case AF_INET6: + + sin6 = (struct sockaddr_in6 *) sa; + + n = 0; + + if (port) { + text[n++] = '['; + } + + n = ngx_inet6_ntop((u_char *) &sin6->sin6_addr, &text[n], len); + + if (port) { + n = ngx_sprintf(&text[1 + n], "]:%d", + ntohs(sin6->sin6_port)) - text; + } + + return n; +#endif + + default: + return 0; } - - return 0; } @@ -84,42 +119,132 @@ ngx_inet_ntop(int family, void *addr, u_ { u_char *p; - if (family == AF_INET) { + switch (family) { - p = (u_char *) addr; + case AF_INET: + + p = addr; return ngx_snprintf(text, len, "%ud.%ud.%ud.%ud", p[0], p[1], p[2], p[3]) - text; + +#if (NGX_HAVE_INET6) + + case AF_INET6: + return ngx_inet6_ntop(addr, text, len); + +#endif + + default: + return 0; + } +} + + +#if (NGX_HAVE_INET6) + +static size_t +ngx_inet6_ntop(u_char *p, u_char *text, size_t len) +{ + u_char *dst; + size_t max, n; + ngx_uint_t i, zero, last; + + if (len < NGX_INET6_ADDRSTRLEN) { + return 0; } - return 0; + zero = (ngx_uint_t) -1; + last = (ngx_uint_t) -1; + max = 1; + n = 0; + + for (i = 0; i < 16; i += 2) { + + if (p[i] || p[i + 1]) { + + if (max < n) { + zero = last; + max = n; + } + + n = 0; + continue; + } + + if (n++ == 0) { + last = i; + } + } + + if (max < n) { + zero = last; + max = n; + } + + dst = text; + n = 16; + + if (zero == 0) { + + if ((max == 5 && p[10] == 0xff && p[11] == 0xff) + || (max == 6) + || (max == 7 && p[14] != 0 && p[15] != 1)) + { + n = 12; + } + + *dst++ = ':'; + } + + for (i = 0; i < n; i += 2) { + + if (i == zero) { + *dst++ = ':'; + i += (max - 1) * 2; + continue; + } + + dst = ngx_sprintf(dst, "%uxi", p[i] * 256 + p[i + 1]); + + if (i < 14) { + *dst++ = ':'; + } + } + + if (n == 12) { + dst = ngx_sprintf(dst, "%ud.%ud.%ud.%ud", p[12], p[13], p[14], p[15]); + } + + return dst - text; } +#endif + /* AF_INET only */ ngx_int_t -ngx_ptocidr(ngx_str_t *text, void *cidr) +ngx_ptocidr(ngx_str_t *text, ngx_cidr_t *cidr) { - u_char *addr, *mask, *last; - ngx_int_t shift; - ngx_inet_cidr_t *in_cidr; + u_char *addr, *mask, *last; + ngx_int_t shift; - in_cidr = cidr; addr = text->data; last = addr + text->len; mask = ngx_strlchr(addr, last, '/'); - in_cidr->addr = ngx_inet_addr(addr, (mask ? mask : last) - addr); + cidr->u.in.addr = ngx_inet_addr(addr, (mask ? mask : last) - addr); - if (in_cidr->addr == INADDR_NONE) { + if (cidr->u.in.addr == INADDR_NONE) { return NGX_ERROR; } if (mask == NULL) { - in_cidr->mask = 0xffffffff; + cidr->family = AF_INET; + cidr->u.in.mask = 0xffffffff; return NGX_OK; } @@ -130,26 +255,28 @@ ngx_ptocidr(ngx_str_t *text, void *cidr) return NGX_ERROR; } + cidr->family = AF_INET; + if (shift == 0) { /* the x86 compilers use the shl instruction that shifts by modulo 32 */ - in_cidr->mask = 0; + cidr->u.in.mask = 0; - if (in_cidr->addr == 0) { + if (cidr->u.in.addr == 0) { return NGX_OK; } return NGX_DONE; } - in_cidr->mask = htonl((ngx_uint_t) (0 - (1 << (32 - shift)))); + cidr->u.in.mask = htonl((ngx_uint_t) (0 - (1 << (32 - shift)))); - if (in_cidr->addr == (in_cidr->addr & in_cidr->mask)) { + if (cidr->u.in.addr == (cidr->u.in.addr & cidr->u.in.mask)) { return NGX_OK; } - in_cidr->addr &= in_cidr->mask; + cidr->u.in.addr &= cidr->u.in.mask; return NGX_DONE; } @@ -171,6 +298,10 @@ ngx_parse_url(ngx_pool_t *pool, ngx_url_ return NGX_ERROR; } + if (p[0] == '[') { + return ngx_parse_inet6_url(pool, u); + } + return ngx_parse_inet_url(pool, u); } @@ -209,13 +340,17 @@ ngx_parse_unix_domain_url(ngx_pool_t *po u->host.len = len++; u->host.data = path; - u->family = AF_UNIX; if (len > sizeof(saun->sun_path)) { u->err = "too long path in the unix domain socket"; return NGX_ERROR; } + u->socklen = sizeof(struct sockaddr_un); + saun = (struct sockaddr_un *) &u->sockaddr; + saun->sun_family = AF_UNIX; + (void) ngx_cpystrn((u_char *) saun->sun_path, path, len); + u->addrs = ngx_pcalloc(pool, sizeof(ngx_peer_addr_t)); if (u->addrs == NULL) { return NGX_ERROR; @@ -226,6 +361,7 @@ ngx_parse_unix_domain_url(ngx_pool_t *po return NGX_ERROR; } + u->family = AF_UNIX; u->naddrs = 1; saun->sun_family = AF_UNIX; @@ -251,10 +387,15 @@ ngx_parse_unix_domain_url(ngx_pool_t *po static ngx_int_t ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u) { - u_char *p, *host, *port, *last, *uri, *args; - size_t len; - ngx_int_t n; - struct hostent *h; + u_char *p, *host, *port, *last, *uri, *args; + size_t len; + ngx_int_t n; + struct hostent *h; + struct sockaddr_in *sin; + + u->socklen = sizeof(struct sockaddr_in); + sin = (struct sockaddr_in *) &u->sockaddr; + sin->sin_family = AF_INET; u->family = AF_INET; @@ -311,6 +452,7 @@ ngx_parse_inet_url(ngx_pool_t *pool, ngx } u->port = (in_port_t) n; + sin->sin_port = htons((in_port_t) n); u->port_text.len = len; u->port_text.data = port; @@ -334,10 +476,13 @@ ngx_parse_inet_url(ngx_pool_t *pool, ngx } u->port = (in_port_t) n; + sin->sin_port = htons((in_port_t) n); u->port_text.len = last - host; u->port_text.data = host; + u->wildcard = 1; + return NGX_OK; } } @@ -374,8 +519,9 @@ ngx_parse_inet_url(ngx_pool_t *pool, ngx (void) ngx_cpystrn(p, host, len); u->addr.in_addr = inet_addr((const char *) p); + sin->sin_addr.s_addr = inet_addr((const char *) p); - if (u->addr.in_addr == INADDR_NONE) { + if (sin->sin_addr.s_addr == INADDR_NONE) { h = gethostbyname((const char *) p); if (h == NULL || h->h_addr_list[0] == NULL) { @@ -385,16 +531,24 @@ ngx_parse_inet_url(ngx_pool_t *pool, ngx } u->addr.in_addr = *(in_addr_t *) (h->h_addr_list[0]); + sin->sin_addr.s_addr = *(in_addr_t *) (h->h_addr_list[0]); + } + + if (sin->sin_addr.s_addr == INADDR_ANY) { + u->wildcard = 1; } ngx_free(p); } else { u->addr.in_addr = INADDR_ANY; + sin->sin_addr.s_addr = INADDR_ANY; + u->wildcard = 1; } if (u->no_port) { u->port = u->default_port; + sin->sin_port = htons(u->default_port); } if (u->listen) { @@ -409,11 +563,134 @@ ngx_parse_inet_url(ngx_pool_t *pool, ngx } +static ngx_int_t +ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u) +{ +#if (NGX_HAVE_INET6) + int rc; + u_char *p, *host, *port, *last, *uri; + size_t len; + ngx_int_t n; + struct sockaddr_in6 *sin6; + + u->socklen = sizeof(struct sockaddr_in6); + sin6 = (struct sockaddr_in6 *) &u->sockaddr; + sin6->sin6_family = AF_INET6; + + host = u->url.data + 1; + + last = u->url.data + u->url.len; + + p = ngx_strlchr(host, last, ']'); + + if (p == NULL) { + u->err = "invalid host"; + return NGX_ERROR; + } + + if (last - p) { + + port = p + 1; + + uri = ngx_strlchr(port, last, '/'); + + if (uri) { + if (u->listen || !u->uri_part) { + u->err = "invalid host"; + return NGX_ERROR; + } + + u->uri.len = last - uri; + u->uri.data = uri; + } + + if (*port == ':') { + port++; + + len = last - port; + + if (len == 0) { + u->err = "invalid port"; + return NGX_ERROR; + } + + n = ngx_atoi(port, len); + + if (n < 1 || n > 65536) { + u->err = "invalid port"; + return NGX_ERROR; + } + + u->port = (in_port_t) n; + sin6->sin6_port = htons((in_port_t) n); + + u->port_text.len = len; + u->port_text.data = port; + + } else { + u->no_port = 1; + } + } + + len = p - host; + + if (len == 0) { + u->err = "no host"; + return NGX_ERROR; + } + + u->host.len = len++; + u->host.data = host; + + p = ngx_alloc(len, pool->log); + if (p == NULL) { + return NGX_ERROR; + } + + (void) ngx_cpystrn(p, host, len); + + rc = inet_pton(AF_INET6, (const char *) p, &sin6->sin6_addr); + + ngx_free(p); + + if (rc == 0) { + u->err = "invalid IPv6 address"; + return NGX_ERROR; + } + + if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { + u->wildcard = 1; + } + + u->family = AF_INET6; + + if (u->no_resolve) { + return NGX_OK; + } + + if (u->no_port) { + u->port = u->default_port; + sin6->sin6_port = htons(u->default_port); + } + + return NGX_OK; + +#else + + u->err = "the INET6 sockets are not supported on this platform"; + + return NGX_ERROR; + +#endif +} + + ngx_int_t ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u) { u_char *p, *host; size_t len; + in_port_t port; in_addr_t in_addr; ngx_uint_t i; struct hostent *h; @@ -428,6 +705,8 @@ ngx_inet_resolve_host(ngx_pool_t *pool, /* AF_INET only */ + port = htons(u->port); + in_addr = inet_addr((char *) host); if (in_addr == INADDR_NONE) { @@ -464,22 +743,22 @@ ngx_inet_resolve_host(ngx_pool_t *pool, } sin->sin_family = AF_INET; - sin->sin_port = htons(u->port); + sin->sin_port = port; sin->sin_addr.s_addr = *(in_addr_t *) (h->h_addr_list[i]); u->addrs[i].sockaddr = (struct sockaddr *) sin; u->addrs[i].socklen = sizeof(struct sockaddr_in); - len = NGX_INET_ADDRSTRLEN + sizeof(":65536") - 1; + len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1; p = ngx_pnalloc(pool, len); if (p == NULL) { return NGX_ERROR; } - len = ngx_sock_ntop((struct sockaddr *) sin, p, len); + len = ngx_sock_ntop((struct sockaddr *) sin, p, len, 1); - u->addrs[i].name.len = ngx_sprintf(&p[len], ":%d", u->port) - p; + u->addrs[i].name.len = len; u->addrs[i].name.data = p; } @@ -502,18 +781,19 @@ ngx_inet_resolve_host(ngx_pool_t *pool, u->naddrs = 1; sin->sin_family = AF_INET; - sin->sin_port = htons(u->port); + sin->sin_port = port; sin->sin_addr.s_addr = in_addr; u->addrs[0].sockaddr = (struct sockaddr *) sin; u->addrs[0].socklen = sizeof(struct sockaddr_in); - p = ngx_pnalloc(pool, u->host.len + sizeof(":65536") - 1); + p = ngx_pnalloc(pool, u->host.len + sizeof(":65535") - 1); if (p == NULL) { return NGX_ERROR; } - u->addrs[0].name.len = ngx_sprintf(p, "%V:%d", &u->host, u->port) - p; + u->addrs[0].name.len = ngx_sprintf(p, "%V:%d", + &u->host, ntohs(port)) - p; u->addrs[0].name.data = p; } diff --git a/src/core/ngx_inet.h b/src/core/ngx_inet.h --- a/src/core/ngx_inet.h +++ b/src/core/ngx_inet.h @@ -12,57 +12,102 @@ #include -#define NGX_INET_ADDRSTRLEN (sizeof("255.255.255.255") - 1) +#define NGX_INET_ADDRSTRLEN (sizeof("255.255.255.255") - 1) +#define NGX_INET6_ADDRSTRLEN \ + (sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") - 1) + +#define NGX_SOCKADDR_STRLEN (NGX_INET6_ADDRSTRLEN + sizeof(":65535") - 1) + + +/* + * TODO: autoconfigure NGX_SOCKADDRLEN as + * sizeof(struct sockaddr_storage) + * sizeof(struct sockaddr_un) + * sizeof(struct sockaddr_in6) + * sizeof(struct sockaddr_in) + */ + +#if (NGX_HAVE_UNIX_DOMAIN) +#define NGX_SOCKADDRLEN sizeof(struct sockaddr_un) +#else +#define NGX_SOCKADDRLEN 512 +#endif typedef struct { - in_addr_t addr; - in_addr_t mask; -} ngx_inet_cidr_t; + in_addr_t addr; + in_addr_t mask; +} ngx_in_cidr_t; + + +#if (NGX_HAVE_INET6) + +typedef struct { + struct in6_addr addr; + struct in6_addr mask; +} ngx_in6_cidr_t; + +#endif + + +typedef struct { + ngx_uint_t family; + union { + ngx_in_cidr_t in; +#if (NGX_HAVE_INET6) + ngx_in6_cidr_t in6; +#endif + } u; +} ngx_cidr_t; typedef union { - in_addr_t in_addr; + in_addr_t in_addr; } ngx_url_addr_t; typedef struct { - struct sockaddr *sockaddr; - socklen_t socklen; - ngx_str_t name; + struct sockaddr *sockaddr; + socklen_t socklen; + ngx_str_t name; } ngx_peer_addr_t; typedef struct { - ngx_str_t url; - ngx_str_t host; - ngx_str_t port_text; - ngx_str_t uri; + ngx_str_t url; + ngx_str_t host; + ngx_str_t port_text; + ngx_str_t uri; - in_port_t port; - in_port_t default_port; - int family; + in_port_t port; + in_port_t default_port; + int family; - unsigned listen:1; - unsigned uri_part:1; - unsigned no_resolve:1; - unsigned one_addr:1; + unsigned listen:1; + unsigned uri_part:1; + unsigned no_resolve:1; + unsigned one_addr:1; - unsigned no_port:1; + unsigned no_port:1; + unsigned wildcard:1; - ngx_url_addr_t addr; + ngx_url_addr_t addr; + + socklen_t socklen; + u_char sockaddr[NGX_SOCKADDRLEN]; - ngx_peer_addr_t *addrs; - ngx_uint_t naddrs; + ngx_peer_addr_t *addrs; + ngx_uint_t naddrs; - char *err; + char *err; } ngx_url_t; in_addr_t ngx_inet_addr(u_char *text, size_t len); -size_t ngx_sock_ntop(struct sockaddr *sa, u_char *text, size_t len); +size_t ngx_sock_ntop(struct sockaddr *sa, u_char *text, size_t len, + ngx_uint_t port); size_t ngx_inet_ntop(int family, void *addr, u_char *text, size_t len); -ngx_int_t ngx_ptocidr(ngx_str_t *text, void *cidr); +ngx_int_t ngx_ptocidr(ngx_str_t *text, ngx_cidr_t *cidr); ngx_int_t ngx_parse_url(ngx_pool_t *pool, ngx_url_t *u); ngx_int_t ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u); diff --git a/src/core/ngx_log.c b/src/core/ngx_log.c --- a/src/core/ngx_log.c +++ b/src/core/ngx_log.c @@ -200,8 +200,10 @@ ngx_log_init(void) ngx_stderr_fileno = GetStdHandle(STD_ERROR_HANDLE); - ngx_stderr.fd = ngx_open_file(NGX_ERROR_LOG_PATH, NGX_FILE_RDWR, - NGX_FILE_CREATE_OR_OPEN|NGX_FILE_APPEND, 0); + ngx_stderr.fd = ngx_open_file((u_char *) NGX_ERROR_LOG_PATH, + NGX_FILE_APPEND, + NGX_FILE_CREATE_OR_OPEN, + NGX_FILE_DEFAULT_ACCESS); if (ngx_stderr.fd == NGX_INVALID_FILE) { ngx_message_box("nginx", MB_OK, ngx_errno, @@ -210,14 +212,6 @@ ngx_log_init(void) return NULL; } - if (ngx_file_append_mode(ngx_stderr.fd) == NGX_ERROR) { - ngx_message_box("nginx", MB_OK, ngx_errno, - "Could not open error log file: " - ngx_file_append_mode_n " \"" NGX_ERROR_LOG_PATH - "\" failed"); - return NULL; - } - #else ngx_stderr.fd = STDERR_FILENO; @@ -329,7 +323,7 @@ ngx_set_error_log(ngx_conf_t *cf, ngx_co cf->cycle->new_log->file->name = value[1]; if (ngx_conf_full_name(cf->cycle, &cf->cycle->new_log->file->name, 0) - == NGX_ERROR) + != NGX_OK) { return NGX_CONF_ERROR; } diff --git a/src/core/ngx_open_file_cache.c b/src/core/ngx_open_file_cache.c --- a/src/core/ngx_open_file_cache.c +++ b/src/core/ngx_open_file_cache.c @@ -466,8 +466,7 @@ ngx_open_and_stat_file(u_char *name, ngx fd = ngx_open_file(name, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); } else { - fd = ngx_open_file(name, NGX_FILE_RDWR, - NGX_FILE_CREATE_OR_OPEN|NGX_FILE_APPEND, + fd = ngx_open_file(name, NGX_FILE_APPEND, NGX_FILE_CREATE_OR_OPEN, NGX_FILE_DEFAULT_ACCESS); } diff --git a/src/core/ngx_palloc.c b/src/core/ngx_palloc.c --- a/src/core/ngx_palloc.c +++ b/src/core/ngx_palloc.c @@ -326,6 +326,27 @@ ngx_pool_cleanup_add(ngx_pool_t *p, size void +ngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd) +{ + ngx_pool_cleanup_t *c; + ngx_pool_cleanup_file_t *cf; + + for (c = p->cleanup; c; c = c->next) { + if (c->handler == ngx_pool_cleanup_file) { + + cf = c->data; + + if (cf->fd == fd) { + c->handler(cf); + c->handler = NULL; + return; + } + } + } +} + + +void ngx_pool_cleanup_file(void *data) { ngx_pool_cleanup_file_t *c = data; diff --git a/src/core/ngx_palloc.h b/src/core/ngx_palloc.h --- a/src/core/ngx_palloc.h +++ b/src/core/ngx_palloc.h @@ -82,6 +82,7 @@ ngx_int_t ngx_pfree(ngx_pool_t *pool, vo ngx_pool_cleanup_t *ngx_pool_cleanup_add(ngx_pool_t *p, size_t size); +void ngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd); void ngx_pool_cleanup_file(void *data); void ngx_pool_delete_file(void *data); diff --git a/src/core/ngx_shmtx.h b/src/core/ngx_shmtx.h --- a/src/core/ngx_shmtx.h +++ b/src/core/ngx_shmtx.h @@ -57,7 +57,15 @@ ngx_shmtx_trylock(ngx_shmtx_t *mtx) return 0; } - ngx_log_abort(err, ngx_trylock_fd_n " failed"); +#if __osf__ /* Tru64 UNIX */ + + if (err == NGX_EACCESS) { + return 0; + } + +#endif + + ngx_log_abort(err, ngx_trylock_fd_n " %s failed", mtx->name); return 0; } @@ -74,7 +82,7 @@ ngx_shmtx_lock(ngx_shmtx_t *mtx) return; } - ngx_log_abort(err, ngx_lock_fd_n " failed"); + ngx_log_abort(err, ngx_lock_fd_n " %s failed", mtx->name); } @@ -89,7 +97,7 @@ ngx_shmtx_unlock(ngx_shmtx_t *mtx) return; } - ngx_log_abort(err, ngx_unlock_fd_n " failed"); + ngx_log_abort(err, ngx_unlock_fd_n " %s failed", mtx->name); } diff --git a/src/core/ngx_slab.c b/src/core/ngx_slab.c --- a/src/core/ngx_slab.c +++ b/src/core/ngx_slab.c @@ -6,23 +6,6 @@ #include #include -/* - - 12 - 2048 2 11 - 1024 4 10 - 512 8 9 - 256 16 8 - - 128 32 4 32 7 - - 64 64 8 63 6 1 - 32 128 16 127 5 1 - 16 256 32 254 4 2 - 8 512 64 504 3 8 - - */ - #define NGX_SLAB_PAGE_MASK 3 #define NGX_SLAB_PAGE 0 @@ -80,6 +63,8 @@ static ngx_slab_page_t *ngx_slab_alloc_p ngx_uint_t pages); static void ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page, ngx_uint_t pages); +static void ngx_slab_error(ngx_slab_pool_t *pool, ngx_uint_t level, + char *text); static ngx_uint_t ngx_slab_max_size; @@ -147,11 +132,8 @@ ngx_slab_init(ngx_slab_pool_t *pool) pool->pages->slab = pages; } -#if 0 - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "slab: %p, %p, %ui, %d", - pool, pool->start, pages, - (pool->end - pool->start) / ngx_pagesize - pages); -#endif + pool->log_ctx = &pool->zero; + pool->zero = '\0'; } @@ -438,8 +420,7 @@ ngx_slab_free_locked(ngx_slab_pool_t *po ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0, "slab free: %p", p); if ((u_char *) p < pool->start || (u_char *) p > pool->end) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, - "ngx_slab_free(): outside of pool"); + ngx_slab_error(pool, NGX_LOG_ALERT, "ngx_slab_free(): outside of pool"); goto fail; } @@ -587,14 +568,14 @@ ngx_slab_free_locked(ngx_slab_pool_t *po } if (slab == NGX_SLAB_PAGE_FREE) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, - "ngx_slab_free(): page is already free"); + ngx_slab_error(pool, NGX_LOG_ALERT, + "ngx_slab_free(): page is already free"); goto fail; } if (slab == NGX_SLAB_PAGE_BUSY) { - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, - "ngx_slab_free(): pointer to wrong page"); + ngx_slab_error(pool, NGX_LOG_ALERT, + "ngx_slab_free(): pointer to wrong page"); goto fail; } @@ -620,15 +601,15 @@ done: wrong_chunk: - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, - "ngx_slab_free(): pointer to wrong chunk"); + ngx_slab_error(pool, NGX_LOG_ALERT, + "ngx_slab_free(): pointer to wrong chunk"); goto fail; chunk_already_free: - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, - "ngx_slab_free(): chunk is already free"); + ngx_slab_error(pool, NGX_LOG_ALERT, + "ngx_slab_free(): chunk is already free"); fail: @@ -679,8 +660,7 @@ ngx_slab_alloc_pages(ngx_slab_pool_t *po } } - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, NGX_ENOMEM, - "ngx_slab_alloc(): failed"); + ngx_slab_error(pool, NGX_LOG_CRIT, "ngx_slab_alloc() failed: no memory"); return NULL; } @@ -711,3 +691,10 @@ ngx_slab_free_pages(ngx_slab_pool_t *poo pool->free.next = page; } + + +static void +ngx_slab_error(ngx_slab_pool_t *pool, ngx_uint_t level, char *text) +{ + ngx_log_error(level, ngx_cycle->log, 0, "%s%s", text, pool->log_ctx); +} diff --git a/src/core/ngx_slab.h b/src/core/ngx_slab.h --- a/src/core/ngx_slab.h +++ b/src/core/ngx_slab.h @@ -34,6 +34,9 @@ typedef struct { u_char *end; ngx_shmtx_t mutex; + + u_char *log_ctx; + u_char zero; } ngx_slab_pool_t; 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 @@ -1040,18 +1040,16 @@ ngx_event_debug_connection(ngx_conf_t *c ngx_str_t *value; ngx_event_debug_t *dc; struct hostent *h; - ngx_inet_cidr_t in_cidr; + ngx_cidr_t cidr; value = cf->args->elts; - /* AF_INET only */ - dc = ngx_array_push(&ecf->debug_connection); if (dc == NULL) { return NGX_CONF_ERROR; } - rc = ngx_ptocidr(&value[1], &in_cidr); + rc = ngx_ptocidr(&value[1], &cidr); if (rc == NGX_DONE) { ngx_conf_log_error(NGX_LOG_WARN, cf, 0, @@ -1060,8 +1058,18 @@ ngx_event_debug_connection(ngx_conf_t *c } if (rc == NGX_OK) { - dc->mask = in_cidr.mask; - dc->addr = in_cidr.addr; + + /* AF_INET only */ + + if (cidr.family != AF_INET) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"debug_connection\" supports IPv4 only"); + return NGX_CONF_ERROR; + } + + dc->mask = cidr.u.in.mask; + dc->addr = cidr.u.in.addr; + return NGX_CONF_OK; } diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c --- a/src/event/ngx_event_accept.c +++ b/src/event/ngx_event_accept.c @@ -9,10 +9,6 @@ #include -/* the buffer size is enough to hold "struct sockaddr_un" */ -#define NGX_SOCKLEN 512 - - static ngx_int_t ngx_enable_accept_events(ngx_cycle_t *cycle); static ngx_int_t ngx_disable_accept_events(ngx_cycle_t *cycle); static void ngx_close_accepted_connection(ngx_connection_t *c); @@ -29,7 +25,7 @@ ngx_event_accept(ngx_event_t *ev) ngx_listening_t *ls; ngx_connection_t *c, *lc; ngx_event_conf_t *ecf; - char sa[NGX_SOCKLEN]; + u_char sa[NGX_SOCKADDRLEN]; ecf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_event_core_module); @@ -48,7 +44,7 @@ ngx_event_accept(ngx_event_t *ev) "accept on %V, ready: %d", &ls->addr_text, ev->available); do { - socklen = NGX_SOCKLEN; + socklen = NGX_SOCKADDRLEN; s = accept(lc->fd, (struct sockaddr *) sa, &socklen); @@ -153,8 +149,10 @@ ngx_event_accept(ngx_event_t *ev) c->log = log; c->pool->log = log; + c->socklen = socklen; c->listening = ls; - c->socklen = socklen; + c->local_sockaddr = ls->sockaddr; + c->local_socklen = ls->socklen; c->unexpected_eof = 1; @@ -208,7 +206,7 @@ ngx_event_accept(ngx_event_t *ev) } c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->addr_text.data, - ls->addr_text_max_len); + ls->addr_text_max_len, 0); if (c->addr_text.len == 0) { ngx_close_accepted_connection(c); return; diff --git a/src/event/ngx_event_connect.c b/src/event/ngx_event_connect.c --- a/src/event/ngx_event_connect.c +++ b/src/event/ngx_event_connect.c @@ -155,6 +155,7 @@ ngx_event_connect_peer(ngx_peer_connecti */ || err == NGX_EAGAIN #endif + || err == NGX_ECONNRESET || err == NGX_ENETDOWN || err == NGX_ENETUNREACH || err == NGX_EHOSTDOWN 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 @@ -10,7 +10,7 @@ typedef struct { - ngx_str_t engine; + ngx_uint_t engine; /* unsigned engine:1; */ } ngx_openssl_conf_t; @@ -37,26 +37,17 @@ static void ngx_ssl_session_rbtree_inser ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); static void *ngx_openssl_create_conf(ngx_cycle_t *cycle); -static char *ngx_openssl_init_conf(ngx_cycle_t *cycle, void *conf); +static char *ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static void ngx_openssl_exit(ngx_cycle_t *cycle); -#if !(NGX_SSL_ENGINE) -static char *ngx_openssl_noengine(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); -#endif - static ngx_command_t ngx_openssl_commands[] = { { ngx_string("ssl_engine"), NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, -#if (NGX_SSL_ENGINE) - ngx_conf_set_str_slot, -#else - ngx_openssl_noengine, -#endif + ngx_openssl_engine, 0, - offsetof(ngx_openssl_conf_t, engine), + 0, NULL }, ngx_null_command @@ -66,7 +57,7 @@ static ngx_command_t ngx_openssl_comman static ngx_core_module_t ngx_openssl_module_ctx = { ngx_string("openssl"), ngx_openssl_create_conf, - ngx_openssl_init_conf + NULL }; @@ -198,7 +189,7 @@ ngx_int_t ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, ngx_str_t *key) { - if (ngx_conf_full_name(cf->cycle, cert, 1) == NGX_ERROR) { + if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) { return NGX_ERROR; } @@ -211,7 +202,7 @@ ngx_ssl_certificate(ngx_conf_t *cf, ngx_ return NGX_ERROR; } - if (ngx_conf_full_name(cf->cycle, key, 1) == NGX_ERROR) { + if (ngx_conf_full_name(cf->cycle, key, 1) != NGX_OK) { return NGX_ERROR; } @@ -242,7 +233,7 @@ ngx_ssl_client_certificate(ngx_conf_t *c return NGX_OK; } - if (ngx_conf_full_name(cf->cycle, cert, 1) == NGX_ERROR) { + if (ngx_conf_full_name(cf->cycle, cert, 1) != NGX_OK) { return NGX_ERROR; } @@ -400,7 +391,7 @@ ngx_ssl_dhparam(ngx_conf_t *cf, ngx_ssl_ return NGX_OK; } - if (ngx_conf_full_name(cf->cycle, file, 1) == NGX_ERROR) { + if (ngx_conf_full_name(cf->cycle, file, 1) != NGX_OK) { return NGX_ERROR; } @@ -1421,6 +1412,7 @@ ngx_ssl_session_cache(ngx_ssl_t *ssl, ng static ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data) { + size_t len; ngx_slab_pool_t *shpool; ngx_ssl_session_cache_t *cache; @@ -1441,6 +1433,16 @@ ngx_ssl_session_cache_init(ngx_shm_zone_ ngx_queue_init(&cache->expire_queue); + len = sizeof(" in SSL session shared cache \"\"") + shm_zone->name.len; + + shpool->log_ctx = ngx_slab_alloc(shpool, len); + if (shpool->log_ctx == NULL) { + return NGX_ERROR; + } + + ngx_sprintf(shpool->log_ctx, " in SSL session shared cache \"%V\"%Z", + &shm_zone->name); + shm_zone->data = cache; return NGX_OK; @@ -2113,8 +2115,7 @@ ngx_openssl_create_conf(ngx_cycle_t *cyc /* * set by ngx_pcalloc(): * - * oscf->engine.len = 0; - * oscf->engine.data = NULL; + * oscf->engine = 0; */ return oscf; @@ -2122,53 +2123,54 @@ ngx_openssl_create_conf(ngx_cycle_t *cyc static char * -ngx_openssl_init_conf(ngx_cycle_t *cycle, void *conf) +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; - - if (oscf->engine.len == 0) { - return NGX_CONF_OK; + ENGINE *engine; + ngx_str_t *value; + + if (oscf->engine) { + return "is duplicate"; } - engine = ENGINE_by_id((const char *) oscf->engine.data); + oscf->engine = 1; + + value = cf->args->elts; + + engine = ENGINE_by_id((const char *) value[1].data); if (engine == NULL) { - ngx_ssl_error(NGX_LOG_WARN, cycle->log, 0, - "ENGINE_by_id(\"%V\") failed", &oscf->engine); + ngx_ssl_error(NGX_LOG_WARN, cf->log, 0, + "ENGINE_by_id(\"%V\") failed", &value[1]); return NGX_CONF_ERROR; } if (ENGINE_set_default(engine, ENGINE_METHOD_ALL) == 0) { - ngx_ssl_error(NGX_LOG_WARN, cycle->log, 0, + ngx_ssl_error(NGX_LOG_WARN, cf->log, 0, "ENGINE_set_default(\"%V\", ENGINE_METHOD_ALL) failed", - &oscf->engine); + &value[1]); + + ENGINE_free(engine); + return NGX_CONF_ERROR; } ENGINE_free(engine); -#endif - return NGX_CONF_OK; -} - - -#if !(NGX_SSL_ENGINE) - -static char * -ngx_openssl_noengine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ + +#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 diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c --- a/src/event/ngx_event_pipe.c +++ b/src/event/ngx_event_pipe.c @@ -423,7 +423,7 @@ ngx_event_pipe_write_to_downstream(ngx_e size_t bsize; ngx_int_t rc; ngx_uint_t flush, prev_last_shadow; - ngx_chain_t *out, **ll, *cl; + ngx_chain_t *out, **ll, *cl, file; ngx_connection_t *downstream; downstream = p->downstream; @@ -488,6 +488,18 @@ ngx_event_pipe_write_to_downstream(ngx_e p->in = NULL; } + if (p->cacheable && p->buf_to_file) { + + file.buf = p->buf_to_file; + file.next = NULL; + + if (ngx_write_chain_to_temp_file(p->temp_file, &file) + == NGX_ERROR) + { + return NGX_ABORT; + } + } + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe write downstream done"); 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 @@ -9,8 +9,6 @@ #include -/* AF_INET only */ - typedef struct { in_addr_t mask; in_addr_t addr; @@ -103,6 +101,10 @@ ngx_http_access_handler(ngx_http_request /* AF_INET only */ + if (r->connection->sockaddr->sa_family != AF_INET) { + return NGX_DECLINED; + } + sin = (struct sockaddr_in *) r->connection->sockaddr; rule = alcf->rules->elts; @@ -139,7 +141,7 @@ ngx_http_access_rule(ngx_conf_t *cf, ngx ngx_int_t rc; ngx_str_t *value; - ngx_inet_cidr_t in_cidr; + ngx_cidr_t cidr; ngx_http_access_rule_t *rule; if (alcf->rules == NULL) { @@ -166,7 +168,7 @@ ngx_http_access_rule(ngx_conf_t *cf, ngx return NGX_CONF_OK; } - rc = ngx_ptocidr(&value[1], &in_cidr); + rc = ngx_ptocidr(&value[1], &cidr); if (rc == NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", @@ -174,13 +176,19 @@ ngx_http_access_rule(ngx_conf_t *cf, ngx return NGX_CONF_ERROR; } + if (cidr.family != AF_INET) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"allow\" 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", &value[1]); } - rule->mask = in_cidr.mask; - rule->addr = in_cidr.addr; + rule->mask = cidr.u.in.mask; + rule->addr = cidr.u.in.addr; return NGX_CONF_OK; } 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 @@ -13,13 +13,13 @@ typedef struct { - ngx_str_t passwd; + ngx_str_t passwd; } ngx_http_auth_basic_ctx_t; typedef struct { - ngx_str_t realm; - ngx_str_t user_file; + ngx_str_t realm; + ngx_http_complex_value_t user_file; } ngx_http_auth_basic_loc_conf_t; @@ -34,6 +34,8 @@ static char *ngx_http_auth_basic_merge_l void *parent, void *child); static ngx_int_t ngx_http_auth_basic_init(ngx_conf_t *cf); static char *ngx_http_auth_basic(ngx_conf_t *cf, void *post, void *data); +static char *ngx_http_auth_basic_user_file(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static ngx_conf_post_handler_pt ngx_http_auth_basic_p = ngx_http_auth_basic; @@ -51,7 +53,7 @@ static ngx_command_t ngx_http_auth_basi { ngx_string("auth_basic_user_file"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF |NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_http_auth_basic_user_file, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_auth_basic_loc_conf_t, user_file), NULL }, @@ -98,8 +100,9 @@ ngx_http_auth_basic_handler(ngx_http_req ssize_t n; ngx_fd_t fd; ngx_int_t rc; - ngx_str_t pwd; - ngx_uint_t i, login, left, passwd; + ngx_err_t err; + ngx_str_t pwd, user_file; + ngx_uint_t i, level, login, left, passwd; ngx_file_t file; ngx_http_auth_basic_ctx_t *ctx; ngx_http_auth_basic_loc_conf_t *alcf; @@ -112,7 +115,7 @@ ngx_http_auth_basic_handler(ngx_http_req alcf = ngx_http_get_module_loc_conf(r, ngx_http_auth_basic_module); - if (alcf->realm.len == 0 || alcf->user_file.len == 0) { + if (alcf->realm.len == 0 || alcf->user_file.value.len == 0) { return NGX_DECLINED; } @@ -126,6 +129,10 @@ ngx_http_auth_basic_handler(ngx_http_req rc = ngx_http_auth_basic_user(r); if (rc == NGX_DECLINED) { + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "no user/password was provided for basic authentication"); + return ngx_http_auth_basic_set_realm(r, &alcf->realm); } @@ -133,18 +140,34 @@ ngx_http_auth_basic_handler(ngx_http_req return NGX_HTTP_INTERNAL_SERVER_ERROR; } - fd = ngx_open_file(alcf->user_file.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); + if (ngx_http_complex_value(r, &alcf->user_file, &user_file) != NGX_OK) { + return NGX_ERROR; + } + + fd = ngx_open_file(user_file.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); if (fd == NGX_INVALID_FILE) { - ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, - ngx_open_file_n " \"%s\" failed", alcf->user_file.data); - return NGX_HTTP_INTERNAL_SERVER_ERROR; + err = ngx_errno; + + if (err == NGX_ENOENT) { + level = NGX_LOG_ERR; + rc = NGX_HTTP_FORBIDDEN; + + } else { + level = NGX_LOG_CRIT; + rc = NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + ngx_log_error(level, r->connection->log, err, + ngx_open_file_n " \"%s\" failed", user_file.data); + + return rc; } ngx_memzero(&file, sizeof(ngx_file_t)); file.fd = fd; - file.name = alcf->user_file; + file.name = user_file; file.log = r->connection->log; state = sw_login; @@ -172,9 +195,16 @@ ngx_http_auth_basic_handler(ngx_http_req switch (state) { case sw_login: - if (login == 0 && buf[i] == '#') { - state = sw_skip; - break; + if (login == 0) { + + if (buf[i] == '#' || buf[i] == CR) { + state = sw_skip; + break; + } + + if (buf[i] == LF) { + break; + } } if (buf[i] != r->headers_in.user.data[login]) { @@ -242,6 +272,10 @@ ngx_http_auth_basic_handler(ngx_http_req return ngx_http_auth_basic_crypt_handler(r, NULL, &pwd, &alcf->realm); } + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "user \"%V\" was not found in \"%V\"", + &r->headers_in.user, &user_file); + return ngx_http_auth_basic_set_realm(r, &alcf->realm); } @@ -257,8 +291,8 @@ ngx_http_auth_basic_crypt_handler(ngx_ht &encrypted); ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "rc: %d user: \"%V\" salt: \"%s\"", - rc, &r->headers_in.user, passwd->data); + "rc: %d user: \"%V\" salt: \"%s\"", + rc, &r->headers_in.user, passwd->data); if (rc == NGX_OK) { if (ngx_strcmp(encrypted, passwd->data) == 0) { @@ -268,6 +302,10 @@ ngx_http_auth_basic_crypt_handler(ngx_ht ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "encrypted: \"%s\"", encrypted); + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "user \"%V\": password mismatch", + &r->headers_in.user); + return ngx_http_auth_basic_set_realm(r, realm); } @@ -351,12 +389,7 @@ ngx_http_auth_basic_merge_loc_conf(ngx_c conf->realm = prev->realm; } - if (conf->user_file.data) { - if (ngx_conf_full_name(cf->cycle, &conf->user_file, 1) != NGX_OK) { - return NGX_CONF_ERROR; - } - - } else { + if (conf->user_file.value.len == 0) { conf->user_file = prev->user_file; } @@ -414,3 +447,33 @@ ngx_http_auth_basic(ngx_conf_t *cf, void return NGX_CONF_OK; } + + +static char * +ngx_http_auth_basic_user_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_auth_basic_loc_conf_t *alcf = conf; + + ngx_str_t *value; + ngx_http_compile_complex_value_t ccv; + + if (alcf->user_file.value.len) { + return "is duplicate"; + } + + value = cf->args->elts; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &alcf->user_file; + ccv.zero = 1; + ccv.conf_prefix = 1; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} 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 @@ -318,6 +318,10 @@ ngx_http_browser(ngx_http_request_t *r, if (c == '.') { version += ver * scale; + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "version: \"%ui\" \"%ui\"", + modern[i].version, version); + if (version > modern[i].version) { return NGX_HTTP_MODERN_BROWSER; } @@ -339,6 +343,8 @@ ngx_http_browser(ngx_http_request_t *r, if (version >= modern[i].version) { return NGX_HTTP_MODERN_BROWSER; } + + return NGX_HTTP_ANCIENT_BROWSER; } if (!cf->modern_unlisted_browsers) { 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 @@ -1421,19 +1421,21 @@ ngx_http_charset_create_main_conf(ngx_co } if (ngx_array_init(&mcf->charsets, cf->pool, 2, sizeof(ngx_http_charset_t)) - == NGX_ERROR) + != NGX_OK) { return NGX_CONF_ERROR; } if (ngx_array_init(&mcf->tables, cf->pool, 1, - sizeof(ngx_http_charset_tables_t)) == NGX_ERROR) + sizeof(ngx_http_charset_tables_t)) + != NGX_OK) { return NGX_CONF_ERROR; } if (ngx_array_init(&mcf->recodes, cf->pool, 2, - sizeof(ngx_http_charset_recode_t)) == NGX_ERROR) + sizeof(ngx_http_charset_recode_t)) + != NGX_OK) { return NGX_CONF_ERROR; } diff --git a/src/http/modules/ngx_http_empty_gif_module.c b/src/http/modules/ngx_http_empty_gif_module.c --- a/src/http/modules/ngx_http_empty_gif_module.c +++ b/src/http/modules/ngx_http_empty_gif_module.c @@ -122,6 +122,7 @@ ngx_http_empty_gif_handler(ngx_http_requ return rc; } + r->headers_out.content_type_len = sizeof("image/gif") - 1; r->headers_out.content_type.len = sizeof("image/gif") - 1; r->headers_out.content_type.data = (u_char *) "image/gif"; 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 @@ -23,6 +23,10 @@ typedef struct { ngx_array_t *fastcgi_lengths; ngx_array_t *fastcgi_values; +#if (NGX_HTTP_CACHE) + ngx_http_complex_value_t cache_key; +#endif + #if (NGX_PCRE) ngx_regex_t *split_regex; ngx_str_t split_name; @@ -116,6 +120,9 @@ typedef struct { static ngx_int_t ngx_http_fastcgi_eval(ngx_http_request_t *r, ngx_http_fastcgi_loc_conf_t *flcf); +#if (NGX_HTTP_CACHE) +static ngx_int_t ngx_http_fastcgi_create_key(ngx_http_request_t *r); +#endif static ngx_int_t ngx_http_fastcgi_create_request(ngx_http_request_t *r); static ngx_int_t ngx_http_fastcgi_reinit_request(ngx_http_request_t *r); static ngx_int_t ngx_http_fastcgi_process_header(ngx_http_request_t *r); @@ -144,6 +151,13 @@ static char *ngx_http_fastcgi_split_path ngx_command_t *cmd, void *conf); static char *ngx_http_fastcgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +#if (NGX_HTTP_CACHE) +static char *ngx_http_fastcgi_cache(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_http_fastcgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +#endif + static char *ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post, void *data); @@ -169,6 +183,9 @@ static ngx_conf_bitmask_t ngx_http_fast }; +ngx_module_t ngx_http_fastcgi_module; + + static ngx_command_t ngx_http_fastcgi_commands[] = { { ngx_string("fastcgi_pass"), @@ -283,12 +300,58 @@ static ngx_command_t ngx_http_fastcgi_c offsetof(ngx_http_fastcgi_loc_conf_t, upstream.busy_buffers_size_conf), NULL }, +#if (NGX_HTTP_CACHE) + + { ngx_string("fastcgi_cache"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_http_fastcgi_cache, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("fastcgi_cache_key"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_http_fastcgi_cache_key, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("fastcgi_cache_path"), + NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE, + ngx_http_file_cache_set_slot, + 0, + 0, + &ngx_http_fastcgi_module }, + + { ngx_string("fastcgi_cache_valid"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_http_file_cache_valid_set_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_valid), + NULL }, + + { ngx_string("proxy_cache_min_uses"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_min_uses), + NULL }, + + { ngx_string("fastcgi_cache_use_stale"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_conf_set_bitmask_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.cache_use_stale), + &ngx_http_fastcgi_next_upstream_masks }, + +#endif + { ngx_string("fastcgi_temp_path"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234, ngx_conf_set_path_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_fastcgi_loc_conf_t, upstream.temp_path), - (void *) ngx_garbage_collector_temp_handler }, + NULL }, { ngx_string("fastcgi_max_temp_file_size"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, @@ -436,6 +499,11 @@ static ngx_str_t ngx_http_fastcgi_hide_ }; +static ngx_path_init_t ngx_http_fastcgi_temp_path = { + ngx_string(NGX_HTTP_FASTCGI_TEMP_PATH), { 1, 2, 0 } +}; + + static ngx_int_t ngx_http_fastcgi_handler(ngx_http_request_t *r) { @@ -486,6 +554,9 @@ ngx_http_fastcgi_handler(ngx_http_reques u->conf = &flcf->upstream; +#if (NGX_HTTP_CACHE) + u->create_key = ngx_http_fastcgi_create_key; +#endif u->create_request = ngx_http_fastcgi_create_request; u->reinit_request = ngx_http_fastcgi_reinit_request; u->process_header = ngx_http_fastcgi_process_header; @@ -539,7 +610,7 @@ ngx_http_fastcgi_eval(ngx_http_request_t if (u.no_port) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "no port in upstream \"%V\"", &u.url); + "no port in upstream \"%V\"", &u.url); return NGX_ERROR; } @@ -564,6 +635,31 @@ ngx_http_fastcgi_eval(ngx_http_request_t } +#if (NGX_HTTP_CACHE) + +static ngx_int_t +ngx_http_fastcgi_create_key(ngx_http_request_t *r) +{ + ngx_str_t *key; + ngx_http_fastcgi_loc_conf_t *flcf; + + key = ngx_array_push(&r->cache->keys); + if (key == NULL) { + return NGX_ERROR; + } + + flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); + + if (ngx_http_complex_value(r, &flcf->cache_key, key) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_OK; +} + +#endif + + static ngx_int_t ngx_http_fastcgi_create_request(ngx_http_request_t *r) { @@ -1271,12 +1367,9 @@ ngx_http_fastcgi_process_header(ngx_http u->headers_in.status_line.data = (u_char *) "200 OK"; } - u->state->status = u->headers_in.status_n; -#if 0 - if (u->cacheable) { - u->cacheable = ngx_http_upstream_is_cacheable(r); + if (u->state) { + u->state->status = u->headers_in.status_n; } -#endif break; } @@ -1725,6 +1818,7 @@ ngx_http_fastcgi_create_loc_conf(ngx_con * * conf->upstream.bufs.num = 0; * conf->upstream.next_upstream = 0; + * conf->upstream.use_stale_cache = 0; * conf->upstream.temp_path = NULL; * conf->upstream.hide_headers_hash = { NULL, 0 }; * conf->upstream.uri = { 0, NULL }; @@ -1755,6 +1849,12 @@ ngx_http_fastcgi_create_loc_conf(ngx_con conf->upstream.pass_request_headers = NGX_CONF_UNSET; conf->upstream.pass_request_body = NGX_CONF_UNSET; +#if (NGX_HTTP_CACHE) + conf->upstream.cache = NGX_CONF_UNSET_PTR; + conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT; + conf->upstream.cache_valid = NGX_CONF_UNSET_PTR; +#endif + conf->upstream.hide_headers = NGX_CONF_UNSET_PTR; conf->upstream.pass_headers = NGX_CONF_UNSET_PTR; @@ -1923,10 +2023,48 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf |NGX_HTTP_UPSTREAM_FT_OFF; } - ngx_conf_merge_path_value(conf->upstream.temp_path, + if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path, prev->upstream.temp_path, - NGX_HTTP_FASTCGI_TEMP_PATH, 1, 2, 0, - ngx_garbage_collector_temp_handler, cf); + &ngx_http_fastcgi_temp_path) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + +#if (NGX_HTTP_CACHE) + + ngx_conf_merge_ptr_value(conf->upstream.cache, + prev->upstream.cache, NULL); + + if (conf->upstream.cache && conf->upstream.cache->data == NULL) { + ngx_shm_zone_t *shm_zone; + + shm_zone = conf->upstream.cache; + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"fastcgi_cache\" zone \"%V\" is unknown", + &shm_zone->name); + + return NGX_CONF_ERROR; + } + + ngx_conf_merge_uint_value(conf->upstream.cache_min_uses, + prev->upstream.cache_min_uses, 1); + + ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale, + prev->upstream.cache_use_stale, + (NGX_CONF_BITMASK_SET + |NGX_HTTP_UPSTREAM_FT_OFF)); + + if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) { + conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET + |NGX_HTTP_UPSTREAM_FT_OFF; + } + + ngx_conf_merge_ptr_value(conf->upstream.cache_valid, + prev->upstream.cache_valid, NULL); + +#endif ngx_conf_merge_value(conf->upstream.pass_request_headers, prev->upstream.pass_request_headers, 1); @@ -2401,6 +2539,66 @@ ngx_http_fastcgi_store(ngx_conf_t *cf, n } +#if (NGX_HTTP_CACHE) + +static char * +ngx_http_fastcgi_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_fastcgi_loc_conf_t *flcf = conf; + + ngx_str_t *value; + + value = cf->args->elts; + + if (flcf->upstream.cache != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + if (ngx_strcmp(value[1].data, "off") == 0) { + flcf->upstream.cache = NULL; + return NGX_CONF_OK; + } + + flcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, + &ngx_http_fastcgi_module); + if (flcf->upstream.cache == NULL) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +static char * +ngx_http_fastcgi_cache_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_fastcgi_loc_conf_t *flcf = conf; + + ngx_str_t *value; + ngx_http_compile_complex_value_t ccv; + + value = cf->args->elts; + + if (flcf->cache_key.value.len) { + return "is duplicate"; + } + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &flcf->cache_key; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + +#endif + + static char * ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post, void *data) { 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 @@ -175,6 +175,10 @@ ngx_http_geo_addr(ngx_http_request_t *r, ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http geo started: %V", &r->connection->addr_text); + if (r->connection->sockaddr->sa_family != AF_INET) { + return 0; + } + sin = (struct sockaddr_in *) r->connection->sockaddr; return ntohl(sin->sin_addr.s_addr); } @@ -774,7 +778,7 @@ ngx_http_geo_cidr(ngx_conf_t *cf, ngx_ht ngx_int_t rc, del; ngx_str_t *net; ngx_uint_t i; - ngx_inet_cidr_t cidrin; + ngx_cidr_t cidr; ngx_http_variable_value_t *val, *old; if (ctx->tree == NULL) { @@ -785,8 +789,8 @@ ngx_http_geo_cidr(ngx_conf_t *cf, ngx_ht } if (ngx_strcmp(value[0].data, "default") == 0) { - cidrin.addr = 0; - cidrin.mask = 0; + cidr.u.in.addr = 0; + cidr.u.in.mask = 0; net = &value[0]; } else { @@ -800,11 +804,11 @@ ngx_http_geo_cidr(ngx_conf_t *cf, ngx_ht } if (ngx_strcmp(net->data, "255.255.255.255") == 0) { - cidrin.addr = 0xffffffff; - cidrin.mask = 0xffffffff; + cidr.u.in.addr = 0xffffffff; + cidr.u.in.mask = 0xffffffff; } else { - rc = ngx_ptocidr(net, &cidrin); + rc = ngx_ptocidr(net, &cidr); if (rc == NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, @@ -812,18 +816,25 @@ ngx_http_geo_cidr(ngx_conf_t *cf, ngx_ht 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); } - cidrin.addr = ntohl(cidrin.addr); - cidrin.mask = ntohl(cidrin.mask); + cidr.u.in.addr = ntohl(cidr.u.in.addr); + cidr.u.in.mask = ntohl(cidr.u.in.mask); } if (del) { - if (ngx_radix32tree_delete(ctx->tree, cidrin.addr, cidrin.mask) + if (ngx_radix32tree_delete(ctx->tree, cidr.u.in.addr, + cidr.u.in.mask) != NGX_OK) { ngx_conf_log_error(NGX_LOG_WARN, cf, 0, @@ -841,7 +852,7 @@ ngx_http_geo_cidr(ngx_conf_t *cf, ngx_ht } for (i = 2; i; i--) { - rc = ngx_radix32tree_insert(ctx->tree, cidrin.addr, cidrin.mask, + rc = ngx_radix32tree_insert(ctx->tree, cidr.u.in.addr, cidr.u.in.mask, (uintptr_t) val); if (rc == NGX_OK) { return NGX_CONF_OK; @@ -854,13 +865,13 @@ ngx_http_geo_cidr(ngx_conf_t *cf, ngx_ht /* rc == NGX_BUSY */ old = (ngx_http_variable_value_t *) - ngx_radix32tree_find(ctx->tree, cidrin.addr & cidrin.mask); + ngx_radix32tree_find(ctx->tree, cidr.u.in.addr & cidr.u.in.mask); ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "duplicate network \"%V\", value: \"%v\", old value: \"%v\"", net, val, old); - rc = ngx_radix32tree_delete(ctx->tree, cidrin.addr, cidrin.mask); + rc = ngx_radix32tree_delete(ctx->tree, cidr.u.in.addr, cidr.u.in.mask); if (rc == NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid radix tree"); 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 @@ -19,6 +19,7 @@ typedef struct { ngx_bufs_t bufs; + size_t postpone_gzipping; ngx_int_t level; size_t wbits; size_t memlevel; @@ -84,7 +85,7 @@ struct gztrailer { static void ngx_http_gzip_filter_memory(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx); -static ngx_int_t ngx_http_gzip_filter_copy_recycled(ngx_http_gzip_ctx_t *ctx, +static ngx_int_t ngx_http_gzip_filter_buffer(ngx_http_gzip_ctx_t *ctx, ngx_chain_t *in); static ngx_int_t ngx_http_gzip_filter_deflate_start(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx); @@ -170,6 +171,13 @@ static ngx_command_t ngx_http_gzip_filt offsetof(ngx_http_gzip_conf_t, memlevel), &ngx_http_gzip_hash_p }, + { ngx_string("postpone_gzipping"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_gzip_conf_t, postpone_gzipping), + NULL }, + { ngx_string("gzip_no_buffer"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -257,7 +265,7 @@ ngx_http_gzip_header_filter(ngx_http_req ngx_http_set_ctx(r, ctx, ngx_http_gzip_filter_module); ctx->request = r; - ctx->buffering = 1; + ctx->buffering = (conf->postpone_gzipping != 0); ngx_http_gzip_filter_memory(r, ctx); @@ -301,8 +309,17 @@ ngx_http_gzip_body_filter(ngx_http_reque if (ctx->buffering) { + /* + * With default memory settings zlib starts to output gzipped data + * only after it has got about 90K, so it makes sense to allocate + * zlib memory (200-400K) only after we have enough data to compress. + * Although we copy buffers, nevertheless for not big responses + * this allows to allocate zlib memory, to compress and to output + * the response in one step using hot CPU cache. + */ + if (in) { - switch (ngx_http_gzip_filter_copy_recycled(ctx, in)) { + switch (ngx_http_gzip_filter_buffer(ctx, in)) { case NGX_OK: return NGX_OK; @@ -327,7 +344,7 @@ ngx_http_gzip_body_filter(ngx_http_reque } if (in) { - if (ngx_chain_add_copy(r->pool, &ctx->in, in) == NGX_ERROR) { + if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) { goto failed; } } @@ -482,12 +499,13 @@ ngx_http_gzip_filter_memory(ngx_http_req static ngx_int_t -ngx_http_gzip_filter_copy_recycled(ngx_http_gzip_ctx_t *ctx, ngx_chain_t *in) +ngx_http_gzip_filter_buffer(ngx_http_gzip_ctx_t *ctx, ngx_chain_t *in) { - size_t size, buffered; - ngx_buf_t *b, *buf; - ngx_chain_t *cl, **ll; - ngx_http_request_t *r; + size_t size, buffered; + ngx_buf_t *b, *buf; + ngx_chain_t *cl, **ll; + ngx_http_request_t *r; + ngx_http_gzip_conf_t *conf; r = ctx->request; @@ -501,6 +519,8 @@ ngx_http_gzip_filter_copy_recycled(ngx_h ll = &cl->next; } + conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module); + while (in) { cl = ngx_alloc_chain_link(r->pool); if (cl == NULL) { @@ -512,25 +532,11 @@ ngx_http_gzip_filter_copy_recycled(ngx_h size = b->last - b->pos; buffered += size; - if (b->flush || b->last_buf) { - ctx->buffering = 0; - - } else if (buffered > ctx->allocated / 2) { - - /* - * With default memory settings zlib starts to output gzipped data - * only after it has got about 90K, so it makes sense to allocate - * zlib memory (200-400K) only after we have enough data - * to compress. Although we copy recycled buffers, nevertheless - * for responses up to 120K this allows to allocate zlib memory, - * to compress and to output the response in one step - * using hot CPU cache. - */ - + if (b->flush || b->last_buf || buffered > conf->postpone_gzipping) { ctx->buffering = 0; } - if (ctx->buffering && size && b->recycled) { + if (ctx->buffering && size) { buf = ngx_create_temp_buf(r->pool, size); if (buf == NULL) { @@ -1077,9 +1083,10 @@ ngx_http_gzip_create_conf(ngx_conf_t *cf conf->enable = NGX_CONF_UNSET; conf->no_buffer = NGX_CONF_UNSET; + conf->postpone_gzipping = NGX_CONF_UNSET_SIZE; conf->level = NGX_CONF_UNSET; - conf->wbits = (size_t) NGX_CONF_UNSET; - conf->memlevel = (size_t) NGX_CONF_UNSET; + conf->wbits = NGX_CONF_UNSET_SIZE; + conf->memlevel = NGX_CONF_UNSET_SIZE; conf->min_length = NGX_CONF_UNSET; return conf; @@ -1093,16 +1100,18 @@ ngx_http_gzip_merge_conf(ngx_conf_t *cf, ngx_http_gzip_conf_t *conf = child; ngx_conf_merge_value(conf->enable, prev->enable, 0); + ngx_conf_merge_value(conf->no_buffer, prev->no_buffer, 0); ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, (128 * 1024) / ngx_pagesize, ngx_pagesize); + ngx_conf_merge_size_value(conf->postpone_gzipping, prev->postpone_gzipping, + 0); ngx_conf_merge_value(conf->level, prev->level, 1); ngx_conf_merge_size_value(conf->wbits, prev->wbits, MAX_WBITS); ngx_conf_merge_size_value(conf->memlevel, prev->memlevel, MAX_MEM_LEVEL - 1); ngx_conf_merge_value(conf->min_length, prev->min_length, 20); - ngx_conf_merge_value(conf->no_buffer, prev->no_buffer, 0); if (ngx_http_merge_types(cf, conf->types_keys, &conf->types, prev->types_keys, &prev->types, 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 @@ -16,18 +16,18 @@ typedef ngx_int_t (*ngx_http_set_header_ typedef struct { - ngx_str_t name; - ngx_uint_t offset; - ngx_http_set_header_pt handler; + ngx_str_t name; + ngx_uint_t offset; + ngx_http_set_header_pt handler; } ngx_http_set_header_t; struct ngx_http_header_val_s { - ngx_table_elt_t value; - ngx_uint_t offset; - ngx_http_set_header_pt handler; - ngx_array_t *lengths; - ngx_array_t *values; + ngx_http_complex_value_t value; + ngx_uint_t hash; + ngx_str_t key; + ngx_http_set_header_pt handler; + ngx_uint_t offset; }; @@ -162,16 +162,8 @@ ngx_http_headers_filter(ngx_http_request h = conf->headers->elts; for (i = 0; i < conf->headers->nelts; i++) { - if (h[i].lengths == NULL) { - value = h[i].value.value; - - } else { - if (ngx_http_script_run(r, &value, h[i].lengths->elts, 0, - h[i].values->elts) - == NULL) - { - return NGX_ERROR; - } + if (ngx_http_complex_value(r, &h[i].value, &value) != NGX_OK) { + return NGX_ERROR; } if (h[i].handler(r, &h[i], &value) != NGX_OK) { @@ -331,8 +323,8 @@ ngx_http_add_header(ngx_http_request_t * return NGX_ERROR; } - h->hash = hv->value.hash; - h->key = hv->value.key; + h->hash = hv->hash; + h->key = hv->key; h->value = *value; } @@ -414,8 +406,8 @@ ngx_http_set_last_modified(ngx_http_requ } } - h->hash = hv->value.hash; - h->key = hv->value.key; + h->hash = hv->hash; + h->key = hv->key; h->value = *value; return NGX_OK; @@ -578,12 +570,11 @@ ngx_http_headers_add(ngx_conf_t *cf, ngx { ngx_http_headers_conf_t *hcf = conf; - ngx_int_t n; - ngx_str_t *value; - ngx_uint_t i; - ngx_http_header_val_t *h; - ngx_http_set_header_t *sh; - ngx_http_script_compile_t sc; + ngx_str_t *value; + ngx_uint_t i; + ngx_http_header_val_t *hv; + ngx_http_set_header_t *set; + ngx_http_compile_complex_value_t ccv; value = cf->args->elts; @@ -595,47 +586,40 @@ ngx_http_headers_add(ngx_conf_t *cf, ngx } } - h = ngx_array_push(hcf->headers); - if (h == NULL) { + hv = ngx_array_push(hcf->headers); + if (hv == NULL) { return NGX_CONF_ERROR; } - h->value.hash = 1; - h->value.key = value[1]; - h->value.value = value[2]; - h->offset = 0; - h->handler = ngx_http_add_header; - h->lengths = NULL; - h->values = NULL; + hv->hash = 1; + hv->key = value[1]; + hv->handler = ngx_http_add_header; + hv->offset = 0; - sh = ngx_http_set_headers; - for (i = 0; sh[i].name.len; i++) { - if (ngx_strcasecmp(value[1].data, sh[i].name.data) != 0) { + set = ngx_http_set_headers; + for (i = 0; set[i].name.len; i++) { + if (ngx_strcasecmp(value[1].data, set[i].name.data) != 0) { continue; } - h->offset = sh[i].offset; - h->handler = sh[i].handler; + hv->offset = set[i].offset; + hv->handler = set[i].handler; + break; } - n = ngx_http_script_variables_count(&value[2]); - - if (n == 0) { + if (value[2].len == 0) { + ngx_memzero(&hv->value, sizeof(ngx_http_complex_value_t)); return NGX_CONF_OK; } - ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); - sc.cf = cf; - sc.source = &value[2]; - sc.lengths = &h->lengths; - sc.values = &h->values; - sc.variables = n; - sc.complete_lengths = 1; - sc.complete_values = 1; + ccv.cf = cf; + ccv.value = &value[2]; + ccv.complex_value = &hv->value; - if (ngx_http_script_compile(&sc) != NGX_OK) { + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { return NGX_CONF_ERROR; } 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 @@ -198,7 +198,7 @@ ngx_http_index_handler(ngx_http_request_ path.len = e.pos - path.data; - *e.pos++ = '\0'; + *e.pos = '\0'; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 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 @@ -224,11 +224,6 @@ ngx_http_limit_req_handler(ngx_http_requ node = ngx_slab_alloc_locked(ctx->shpool, n); if (node == NULL) { ngx_shmtx_unlock(&ctx->shpool->mutex); - - ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, - "could not allocate memory in zone \"%V\"", - &lrcf->shm_zone->name); - return NGX_HTTP_SERVICE_UNAVAILABLE; } } @@ -457,6 +452,7 @@ ngx_http_limit_req_init_zone(ngx_shm_zon { ngx_http_limit_req_ctx_t *octx = data; + size_t len; ngx_rbtree_node_t *sentinel; ngx_http_limit_req_ctx_t *ctx; @@ -500,6 +496,16 @@ ngx_http_limit_req_init_zone(ngx_shm_zon ngx_queue_init(ctx->queue); + len = sizeof(" in limit_req zone \"\"") + shm_zone->name.len; + + ctx->shpool->log_ctx = ngx_slab_alloc(ctx->shpool, len); + if (ctx->shpool->log_ctx == NULL) { + return NGX_ERROR; + } + + ngx_sprintf(ctx->shpool->log_ctx, " in limit_req zone \"%V\"%Z", + &shm_zone->name); + return NGX_OK; } diff --git a/src/http/modules/ngx_http_limit_zone_module.c b/src/http/modules/ngx_http_limit_zone_module.c --- a/src/http/modules/ngx_http_limit_zone_module.c +++ b/src/http/modules/ngx_http_limit_zone_module.c @@ -210,11 +210,6 @@ ngx_http_limit_zone_handler(ngx_http_req node = ngx_slab_alloc_locked(shpool, n); if (node == NULL) { ngx_shmtx_unlock(&shpool->mutex); - - ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, - "could not allocate memory in zone \"%V\"", - &lzcf->shm_zone->name); - return NGX_HTTP_SERVICE_UNAVAILABLE; } @@ -321,6 +316,7 @@ ngx_http_limit_zone_init_zone(ngx_shm_zo { ngx_http_limit_zone_ctx_t *octx = data; + size_t len; ngx_slab_pool_t *shpool; ngx_rbtree_node_t *sentinel; ngx_http_limit_zone_ctx_t *ctx; @@ -356,6 +352,15 @@ ngx_http_limit_zone_init_zone(ngx_shm_zo ngx_rbtree_init(ctx->rbtree, sentinel, ngx_http_limit_zone_rbtree_insert_value); + len = sizeof(" in limit_zone \"\"") + shm_zone->name.len; + + shpool->log_ctx = ngx_slab_alloc(shpool, len); + if (shpool->log_ctx == NULL) { + return NGX_ERROR; + } + + ngx_sprintf(shpool->log_ctx, " in limit_zone \"%V\"%Z", &shm_zone->name); + return NGX_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 @@ -863,7 +863,7 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx } } else { - if (ngx_conf_full_name(cf->cycle, &value[1], 0) == NGX_ERROR) { + if (ngx_conf_full_name(cf->cycle, &value[1], 0) != NGX_OK) { return NGX_CONF_ERROR; } 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 @@ -374,7 +374,7 @@ ngx_http_map(ngx_conf_t *cf, ngx_command if (ngx_strcmp(value[0].data, "include") == 0) { file = value[1]; - if (ngx_conf_full_name(cf->cycle, &file, 1) == NGX_ERROR){ + if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK){ return NGX_CONF_ERROR; } diff --git a/src/http/modules/ngx_http_not_modified_filter_module.c b/src/http/modules/ngx_http_not_modified_filter_module.c --- a/src/http/modules/ngx_http_not_modified_filter_module.c +++ b/src/http/modules/ngx_http_not_modified_filter_module.c @@ -83,6 +83,7 @@ ngx_int_t ngx_http_not_modified_header_f } r->headers_out.status = NGX_HTTP_NOT_MODIFIED; + r->headers_out.status_line.len = 0; r->headers_out.content_type.len = 0; ngx_http_clear_content_length(r); ngx_http_clear_accept_ranges(r); 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 @@ -32,6 +32,7 @@ struct ngx_http_proxy_redirect_s { typedef struct { + ngx_str_t key_start; ngx_str_t schema; ngx_str_t host_header; ngx_str_t port; @@ -89,6 +90,9 @@ typedef struct { static ngx_int_t ngx_http_proxy_eval(ngx_http_request_t *r, ngx_http_proxy_ctx_t *ctx, ngx_http_proxy_loc_conf_t *plcf); +#if (NGX_HTTP_CACHE) +static ngx_int_t ngx_http_proxy_create_key(ngx_http_request_t *r); +#endif static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r); static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r); static ngx_int_t ngx_http_proxy_process_status_line(ngx_http_request_t *r); @@ -116,6 +120,8 @@ static ngx_int_t ngx_http_proxy_add_vari static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child); +static ngx_int_t ngx_http_proxy_merge_headers(ngx_conf_t *cf, + ngx_http_proxy_loc_conf_t *conf, ngx_http_proxy_loc_conf_t *prev); static char *ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -123,6 +129,10 @@ static char *ngx_http_proxy_redirect(ngx void *conf); static char *ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +#if (NGX_HTTP_CACHE) +static char *ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +#endif static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data); @@ -135,8 +145,7 @@ static char *ngx_http_proxy_upstream_fai static ngx_int_t ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf); #endif -static ngx_int_t ngx_http_proxy_set_vars(ngx_pool_t *pool, ngx_url_t *u, - ngx_http_proxy_vars_t *v); +static void ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v); static ngx_conf_post_t ngx_http_proxy_lowat_post = @@ -157,6 +166,9 @@ static ngx_conf_bitmask_t ngx_http_prox }; +ngx_module_t ngx_http_proxy_module; + + static ngx_command_t ngx_http_proxy_commands[] = { { ngx_string("proxy_pass"), @@ -306,12 +318,51 @@ static ngx_command_t ngx_http_proxy_com offsetof(ngx_http_proxy_loc_conf_t, upstream.busy_buffers_size_conf), NULL }, +#if (NGX_HTTP_CACHE) + + { ngx_string("proxy_cache"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_http_proxy_cache, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("proxy_cache_path"), + NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE, + ngx_http_file_cache_set_slot, + 0, + 0, + &ngx_http_proxy_module }, + + { ngx_string("proxy_cache_valid"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_http_file_cache_valid_set_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_valid), + NULL }, + + { ngx_string("proxy_cache_min_uses"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_min_uses), + NULL }, + + { ngx_string("proxy_cache_use_stale"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_conf_set_bitmask_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_use_stale), + &ngx_http_proxy_next_upstream_masks }, + +#endif + { ngx_string("proxy_temp_path"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234, ngx_conf_set_path_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_path), - (void *) ngx_garbage_collector_temp_handler }, + NULL }, { ngx_string("proxy_max_temp_file_size"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, @@ -455,6 +506,11 @@ static ngx_http_variable_t ngx_http_pro }; +static ngx_path_init_t ngx_http_proxy_temp_path = { + ngx_string(NGX_HTTP_PROXY_TEMP_PATH), { 1, 2, 0 } +}; + + static ngx_int_t ngx_http_proxy_handler(ngx_http_request_t *r) { @@ -502,6 +558,9 @@ ngx_http_proxy_handler(ngx_http_request_ u->conf = &plcf->upstream; +#if (NGX_HTTP_CACHE) + u->create_key = ngx_http_proxy_create_key; +#endif u->create_request = ngx_http_proxy_create_request; u->reinit_request = ngx_http_proxy_reinit_request; u->process_header = ngx_http_proxy_process_status_line; @@ -537,11 +596,12 @@ static ngx_int_t ngx_http_proxy_eval(ngx_http_request_t *r, ngx_http_proxy_ctx_t *ctx, ngx_http_proxy_loc_conf_t *plcf) { - u_char *p; - size_t add; - u_short port; - ngx_str_t proxy; - ngx_url_t u; + u_char *p; + size_t add; + u_short port; + ngx_str_t proxy; + ngx_url_t url; + ngx_http_upstream_t *u; if (ngx_http_script_run(r, &proxy, plcf->proxy_lengths->elts, 0, plcf->proxy_values->elts) @@ -571,70 +631,162 @@ ngx_http_proxy_eval(ngx_http_request_t * return NGX_ERROR; } - r->upstream->schema.len = add; - r->upstream->schema.data = proxy.data; - - ngx_memzero(&u, sizeof(ngx_url_t)); - - u.url.len = proxy.len - add; - u.url.data = proxy.data + add; - u.default_port = port; - u.uri_part = 1; - u.no_resolve = 1; - - if (ngx_parse_url(r->pool, &u) != NGX_OK) { - if (u.err) { + u = r->upstream; + + u->schema.len = add; + u->schema.data = proxy.data; + + ngx_memzero(&url, sizeof(ngx_url_t)); + + url.url.len = proxy.len - add; + url.url.data = proxy.data + add; + url.default_port = port; + url.uri_part = 1; + url.no_resolve = 1; + + if (ngx_parse_url(r->pool, &url) != NGX_OK) { + if (url.err) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "%s in upstream \"%V\"", u.err, &u.url); + "%s in upstream \"%V\"", url.err, &url.url); } return NGX_ERROR; } - if (u.uri.len && u.uri.data[0] == '?') { - p = ngx_pnalloc(r->pool, u.uri.len + 1); + if (url.uri.len && url.uri.data[0] == '?') { + p = ngx_pnalloc(r->pool, url.uri.len + 1); if (p == NULL) { return NGX_ERROR; } *p++ = '/'; - ngx_memcpy(p, u.uri.data, u.uri.len); - - u.uri.len++; - u.uri.data = p - 1; + ngx_memcpy(p, url.uri.data, url.uri.len); + + url.uri.len++; + url.uri.data = p - 1; } - if (ngx_http_proxy_set_vars(r->pool, &u, &ctx->vars) != NGX_OK) { + ctx->vars.key_start = u->schema; + + ngx_http_proxy_set_vars(&url, &ctx->vars); + + u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t)); + if (u->resolved == NULL) { return NGX_ERROR; } - r->upstream->resolved = ngx_pcalloc(r->pool, - sizeof(ngx_http_upstream_resolved_t)); - if (r->upstream->resolved == NULL) { - return NGX_ERROR; - } - - if (u.addrs && u.addrs[0].sockaddr) { - r->upstream->resolved->sockaddr = u.addrs[0].sockaddr; - r->upstream->resolved->socklen = u.addrs[0].socklen; - r->upstream->resolved->naddrs = 1; - r->upstream->resolved->host = u.addrs[0].name; + if (url.addrs && url.addrs[0].sockaddr) { + u->resolved->sockaddr = url.addrs[0].sockaddr; + u->resolved->socklen = url.addrs[0].socklen; + u->resolved->naddrs = 1; + u->resolved->host = url.addrs[0].name; } else { - r->upstream->resolved->host = u.host; - r->upstream->resolved->port = (in_port_t) (u.no_port ? u.default_port: - u.port); - r->upstream->resolved->no_port = u.no_port; + u->resolved->host = url.host; + u->resolved->port = (in_port_t) (url.no_port ? port : url.port); + u->resolved->no_port = url.no_port; } return NGX_OK; } +#if (NGX_HTTP_CACHE) + +static ngx_int_t +ngx_http_proxy_create_key(ngx_http_request_t *r) +{ + size_t len, loc_len; + u_char *p; + uintptr_t escape; + ngx_str_t *key; + ngx_http_upstream_t *u; + ngx_http_proxy_ctx_t *ctx; + ngx_http_proxy_loc_conf_t *plcf; + + u = r->upstream; + + plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); + + ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module); + + key = ngx_array_push(&r->cache->keys); + if (key == NULL) { + return NGX_ERROR; + } + + *key = ctx->vars.key_start; + + key = ngx_array_push(&r->cache->keys); + if (key == NULL) { + return NGX_ERROR; + } + + if (plcf->proxy_lengths) { + + *key = ctx->vars.uri; + u->uri = ctx->vars.uri; + + return NGX_OK; + + } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main) + { + *key = r->unparsed_uri; + u->uri = r->unparsed_uri; + + return NGX_OK; + } + + loc_len = (r->valid_location && ctx->vars.uri.len) ? plcf->location.len : 0; + + if (r->quoted_uri || r->internal) { + escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len, + r->uri.len - loc_len, NGX_ESCAPE_URI); + } else { + escape = 0; + } + + len = ctx->vars.uri.len + r->uri.len - loc_len + escape + + sizeof("?") - 1 + r->args.len; + + p = ngx_pnalloc(r->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + key->data = p; + + if (r->valid_location) { + p = ngx_copy(p, ctx->vars.uri.data, ctx->vars.uri.len); + } + + if (escape) { + ngx_escape_uri(p, r->uri.data + loc_len, + r->uri.len - loc_len, NGX_ESCAPE_URI); + p += r->uri.len - loc_len + escape; + + } else { + p = ngx_copy(p, r->uri.data + loc_len, r->uri.len - loc_len); + } + + if (r->args.len > 0) { + *p++ = '?'; + p = ngx_copy(p, r->args.data, r->args.len); + } + + key->len = p - key->data; + u->uri = *key; + + return NGX_OK; +} + +#endif + + static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r) { - size_t len, loc_len, body_len; + size_t len, uri_len, loc_len, body_len; uintptr_t escape; ngx_buf_t *b; ngx_str_t method; @@ -675,12 +827,12 @@ ngx_http_proxy_create_request(ngx_http_r ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module); if (plcf->proxy_lengths) { - len += ctx->vars.uri.len; + uri_len = ctx->vars.uri.len; } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main) { unparsed_uri = 1; - len += r->unparsed_uri.len; + uri_len = r->unparsed_uri.len; } else { loc_len = (r->valid_location && ctx->vars.uri.len) ? @@ -691,10 +843,18 @@ ngx_http_proxy_create_request(ngx_http_r r->uri.len - loc_len, NGX_ESCAPE_URI); } - len += ctx->vars.uri.len + r->uri.len - loc_len + escape - + sizeof("?") - 1 + r->args.len; + uri_len = ctx->vars.uri.len + r->uri.len - loc_len + escape + + sizeof("?") - 1 + r->args.len; } + if (uri_len == 0) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "zero length URI to proxy"); + return NGX_ERROR; + } + + len += uri_len; + ngx_http_script_flush_no_cacheable_variables(r, plcf->flushes); if (plcf->body_set_len) { @@ -980,6 +1140,17 @@ ngx_http_proxy_process_status_line(ngx_h u = r->upstream; if (rc == NGX_HTTP_PROXY_PARSE_NO_HEADER) { + +#if (NGX_HTTP_CACHE) + + if (r->cache) { + r->http_version = NGX_HTTP_VERSION_9; + u->headers_in.status_n = NGX_HTTP_OK; + return NGX_OK; + } + +#endif + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "upstream sent no valid HTTP/1.0 header"); @@ -996,8 +1167,11 @@ ngx_http_proxy_process_status_line(ngx_h return NGX_OK; } + if (u->state) { + u->state->status = ctx->status; + } + u->headers_in.status_n = ctx->status; - u->state->status = ctx->status; u->headers_in.status_line.len = ctx->status_end - ctx->status_start; u->headers_in.status_line.data = ngx_pnalloc(r->pool, @@ -1638,6 +1812,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_ * * conf->upstream.bufs.num = 0; * conf->upstream.next_upstream = 0; + * conf->upstream.use_stale_cache = 0; * conf->upstream.temp_path = NULL; * conf->upstream.hide_headers_hash = { NULL, 0 }; * conf->upstream.uri = { 0, NULL }; @@ -1675,6 +1850,12 @@ ngx_http_proxy_create_loc_conf(ngx_conf_ conf->upstream.pass_request_headers = NGX_CONF_UNSET; conf->upstream.pass_request_body = NGX_CONF_UNSET; +#if (NGX_HTTP_CACHE) + conf->upstream.cache = NGX_CONF_UNSET_PTR; + conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT; + conf->upstream.cache_valid = NGX_CONF_UNSET_PTR; +#endif + conf->upstream.hide_headers = NGX_CONF_UNSET_PTR; conf->upstream.pass_headers = NGX_CONF_UNSET_PTR; @@ -1702,16 +1883,11 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t ngx_http_proxy_loc_conf_t *prev = parent; ngx_http_proxy_loc_conf_t *conf = child; - u_char *p; - size_t size; - uintptr_t *code; - ngx_uint_t i; - ngx_keyval_t *src, *s, *h; - ngx_hash_key_t *hk; - ngx_hash_init_t hash; - ngx_http_proxy_redirect_t *pr; - ngx_http_script_compile_t sc; - ngx_http_script_copy_code_t *copy; + size_t size; + ngx_keyval_t *s; + ngx_hash_init_t hash; + ngx_http_proxy_redirect_t *pr; + ngx_http_script_compile_t sc; if (conf->upstream.store != 0) { ngx_conf_merge_value(conf->upstream.store, @@ -1850,10 +2026,49 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t |NGX_HTTP_UPSTREAM_FT_OFF; } - ngx_conf_merge_path_value(conf->upstream.temp_path, + if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path, prev->upstream.temp_path, - NGX_HTTP_PROXY_TEMP_PATH, 1, 2, 0, - ngx_garbage_collector_temp_handler, cf); + &ngx_http_proxy_temp_path) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + +#if (NGX_HTTP_CACHE) + + ngx_conf_merge_ptr_value(conf->upstream.cache, + prev->upstream.cache, NULL); + + if (conf->upstream.cache && conf->upstream.cache->data == NULL) { + ngx_shm_zone_t *shm_zone; + + shm_zone = conf->upstream.cache; + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"proxy_cache\" zone \"%V\" is unknown", + &shm_zone->name); + + return NGX_CONF_ERROR; + } + + ngx_conf_merge_uint_value(conf->upstream.cache_min_uses, + prev->upstream.cache_min_uses, 1); + + ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale, + prev->upstream.cache_use_stale, + (NGX_CONF_BITMASK_SET + |NGX_HTTP_UPSTREAM_FT_OFF)); + + if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) { + conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET + |NGX_HTTP_UPSTREAM_FT_OFF; + } + + ngx_conf_merge_ptr_value(conf->upstream.cache_valid, + prev->upstream.cache_valid, NULL); + +#endif if (conf->method.len == 0) { conf->method = prev->method; @@ -1984,6 +2199,27 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t s->value.data = (u_char *) "$proxy_internal_body_length"; } + if (ngx_http_proxy_merge_headers(cf, conf, prev) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_proxy_merge_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf, + ngx_http_proxy_loc_conf_t *prev) +{ + u_char *p; + size_t size; + uintptr_t *code; + ngx_uint_t i; + ngx_keyval_t *src, *s, *h; + ngx_hash_key_t *hk; + ngx_hash_init_t hash; + ngx_http_script_compile_t sc; + ngx_http_script_copy_code_t *copy; if (conf->headers_source == NULL) { conf->flushes = prev->flushes; @@ -1994,31 +2230,31 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t } if (conf->headers_set_hash.buckets) { - return NGX_CONF_OK; + return NGX_OK; } conf->headers_names = ngx_array_create(cf->pool, 4, sizeof(ngx_hash_key_t)); if (conf->headers_names == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } if (conf->headers_source == NULL) { conf->headers_source = ngx_array_create(cf->pool, 4, sizeof(ngx_keyval_t)); if (conf->headers_source == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } } conf->headers_set_len = ngx_array_create(cf->pool, 64, 1); if (conf->headers_set_len == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } conf->headers_set = ngx_array_create(cf->pool, 512, 1); if (conf->headers_set == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } @@ -2034,7 +2270,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t s = ngx_array_push(conf->headers_source); if (s == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } *s = *h; @@ -2052,7 +2288,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t hk = ngx_array_push(conf->headers_names); if (hk == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } hk->key = src[i].key; @@ -2067,7 +2303,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t copy = ngx_array_push_n(conf->headers_set_len, sizeof(ngx_http_script_copy_code_t)); if (copy == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } copy->code = (ngx_http_script_code_pt) @@ -2084,7 +2320,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t copy = ngx_array_push_n(conf->headers_set, size); if (copy == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } copy->code = ngx_http_script_copy_code; @@ -2102,7 +2338,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t copy = ngx_array_push_n(conf->headers_set_len, sizeof(ngx_http_script_copy_code_t)); if (copy == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } copy->code = (ngx_http_script_code_pt) @@ -2116,7 +2352,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t copy = ngx_array_push_n(conf->headers_set, size); if (copy == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } copy->code = ngx_http_script_copy_code; @@ -2136,14 +2372,14 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t sc.values = &conf->headers_set; if (ngx_http_script_compile(&sc) != NGX_OK) { - return NGX_CONF_ERROR; + return NGX_ERROR; } copy = ngx_array_push_n(conf->headers_set_len, sizeof(ngx_http_script_copy_code_t)); if (copy == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } copy->code = (ngx_http_script_code_pt) @@ -2157,7 +2393,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t copy = ngx_array_push_n(conf->headers_set, size); if (copy == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } copy->code = ngx_http_script_copy_code; @@ -2169,14 +2405,14 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t)); if (code == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } *code = (uintptr_t) NULL; code = ngx_array_push_n(conf->headers_set, sizeof(uintptr_t)); if (code == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } *code = (uintptr_t) NULL; @@ -2184,7 +2420,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t)); if (code == NULL) { - return NGX_CONF_ERROR; + return NGX_ERROR; } *code = (uintptr_t) NULL; @@ -2202,10 +2438,10 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t conf->headers_names->nelts) != NGX_OK) { - return NGX_CONF_ERROR; + return NGX_ERROR; } - return NGX_CONF_OK; + return NGX_OK; } @@ -2298,16 +2534,16 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_ return NGX_CONF_ERROR; } - if (ngx_http_proxy_set_vars(cf->pool, &u, &plcf->vars) != NGX_OK) { - return NGX_CONF_ERROR; - } - plcf->vars.schema.len = add; plcf->vars.schema.data = url->data; - plcf->location = clcf->name; + plcf->vars.key_start = plcf->vars.schema; + + ngx_http_proxy_set_vars(&u, &plcf->vars); clcf->handler = ngx_http_proxy_handler; + plcf->location = clcf->name; + if (clcf->named #if (NGX_PCRE) || clcf->regex @@ -2473,6 +2709,38 @@ ngx_http_proxy_store(ngx_conf_t *cf, ngx } +#if (NGX_HTTP_CACHE) + +static char * +ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_proxy_loc_conf_t *plcf = conf; + + ngx_str_t *value; + + value = cf->args->elts; + + if (plcf->upstream.cache != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + if (ngx_strcmp(value[1].data, "off") == 0) { + plcf->upstream.cache = NULL; + return NGX_CONF_OK; + } + + plcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0, + &ngx_http_proxy_module); + if (plcf->upstream.cache == NULL) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + +#endif + + static char * ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data) { @@ -2563,12 +2831,13 @@ ngx_http_proxy_set_ssl(ngx_conf_t *cf, n #endif -static ngx_int_t -ngx_http_proxy_set_vars(ngx_pool_t *pool, ngx_url_t *u, - ngx_http_proxy_vars_t *v) +static void +ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v) { if (u->family != AF_UNIX) { + if (u->no_port || u->port == u->default_port) { + v->host_header = u->host; if (u->default_port == 80) { @@ -2586,14 +2855,15 @@ ngx_http_proxy_set_vars(ngx_pool_t *pool v->port = u->port_text; } + v->key_start.len += v->host_header.len; + } else { v->host_header.len = sizeof("localhost") - 1; v->host_header.data = (u_char *) "localhost"; v->port.len = 0; v->port.data = (u_char *) ""; + v->key_start.len += sizeof("unix:") - 1 + u->host.len + 1; } v->uri = u->uri; - - return NGX_OK; } diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c --- a/src/http/modules/ngx_http_range_filter_module.c +++ b/src/http/modules/ngx_http_range_filter_module.c @@ -187,7 +187,7 @@ ngx_http_range_header_filter(ngx_http_re } if (ngx_array_init(&ctx->ranges, r->pool, 1, sizeof(ngx_http_range_t)) - == NGX_ERROR) + != NGX_OK) { return NGX_ERROR; } @@ -199,6 +199,7 @@ ngx_http_range_header_filter(ngx_http_re ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module); r->headers_out.status = NGX_HTTP_PARTIAL_CONTENT; + r->headers_out.status_line.len = 0; if (ctx->ranges.nelts == 1) { return ngx_http_range_singlepart_header(r, ctx); @@ -708,6 +709,7 @@ static ngx_int_t ngx_http_range_multipart_body(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in) { + off_t body_start; ngx_buf_t *b, *buf; ngx_uint_t i; ngx_chain_t *out, *hcl, *rcl, *dcl, **ll; @@ -717,6 +719,12 @@ ngx_http_range_multipart_body(ngx_http_r buf = in->buf; range = ctx->ranges.elts; +#if (NGX_HTTP_CACHE) + body_start = r->cached ? r->cache->body_start : 0; +#else + body_start = 0; +#endif + for (i = 0; i < ctx->ranges.nelts; i++) { /* @@ -777,8 +785,8 @@ ngx_http_range_multipart_body(ngx_http_r b->file = buf->file; if (buf->in_file) { - b->file_pos = range[i].start; - b->file_last = range[i].end; + b->file_pos = body_start + range[i].start; + b->file_last = body_start + range[i].end; } if (ngx_buf_in_memory(buf)) { 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 @@ -14,8 +14,6 @@ #define NGX_HTTP_REALIP_HEADER 2 -/* AF_INET only */ - typedef struct { in_addr_t mask; in_addr_t addr; @@ -209,6 +207,10 @@ found: /* AF_INET only */ + if (r->connection->sockaddr->sa_family != AF_INET) { + return NGX_DECLINED; + } + sin = (struct sockaddr_in *) c->sockaddr; from = rlcf->from->elts; @@ -280,7 +282,7 @@ ngx_http_realip_from(ngx_conf_t *cf, ngx ngx_int_t rc; ngx_str_t *value; - ngx_inet_cidr_t in_cidr; + ngx_cidr_t cidr; ngx_http_realip_from_t *from; if (rlcf->from == NULL) { @@ -298,7 +300,7 @@ ngx_http_realip_from(ngx_conf_t *cf, ngx value = cf->args->elts; - rc = ngx_ptocidr(&value[1], &in_cidr); + rc = ngx_ptocidr(&value[1], &cidr); if (rc == NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", @@ -306,13 +308,19 @@ ngx_http_realip_from(ngx_conf_t *cf, ngx return NGX_CONF_ERROR; } + if (cidr.family != AF_INET) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"realip_from\" 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", &value[1]); } - from->mask = in_cidr.mask; - from->addr = in_cidr.addr; + from->mask = cidr.u.in.mask; + from->addr = cidr.u.in.addr; return NGX_CONF_OK; } 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 @@ -12,7 +12,6 @@ typedef struct { ngx_array_t *codes; /* uintptr_t */ - ngx_uint_t captures; ngx_uint_t stack_size; ngx_flag_t log; @@ -157,16 +156,6 @@ ngx_http_rewrite_handler(ngx_http_reques return NGX_HTTP_INTERNAL_SERVER_ERROR; } - if (rlcf->captures) { - e->captures = ngx_palloc(r->pool, rlcf->captures * sizeof(int)); - if (e->captures == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - } else { - e->captures = NULL; - } - e->ip = rlcf->codes->elts; e->request = r; e->quote = 1; @@ -436,10 +425,6 @@ ngx_http_rewrite(ngx_conf_t *cf, ngx_com if (regex->ncaptures) { regex->ncaptures = (regex->ncaptures + 1) * 3; - - if (lcf->captures < regex->ncaptures) { - lcf->captures = regex->ncaptures; - } } regex_end = ngx_http_script_add_code(lcf->codes, @@ -618,11 +603,6 @@ ngx_http_rewrite_if(ngx_conf_t *cf, ngx_ } - if (lcf->captures < nlcf->captures) { - lcf->captures = nlcf->captures; - } - - if (elts != lcf->codes->elts) { if_code = (ngx_http_script_if_code_t *) ((u_char *) if_code + ((u_char *) lcf->codes->elts - elts)); @@ -777,10 +757,6 @@ ngx_http_rewrite_if_condition(ngx_conf_t if (n) { regex->ncaptures = (n + 1) * 3; - - if (lcf->captures < regex->ncaptures) { - lcf->captures = regex->ncaptures; - } } return NGX_CONF_OK; 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 @@ -397,7 +397,7 @@ ngx_http_ssi_body_filter(ngx_http_reques /* add the incoming chain to the chain ctx->in */ if (in) { - if (ngx_chain_add_copy(r->pool, &ctx->in, in) == NGX_ERROR) { + if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) { return NGX_ERROR; } } @@ -2060,7 +2060,7 @@ ngx_http_ssi_stub_output(ngx_http_reques out = data; if (!r->header_sent) { - if (ngx_http_set_content_type(r) == NGX_ERROR) { + if (ngx_http_set_content_type(r) != NGX_OK) { return NGX_ERROR; } 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 @@ -10,17 +10,14 @@ typedef struct { - ngx_str_t match; - ngx_str_t sub; - - ngx_hash_t types; + ngx_str_t match; + ngx_http_complex_value_t value; - ngx_array_t *sub_lengths; - ngx_array_t *sub_values; + ngx_hash_t types; - ngx_flag_t once; + ngx_flag_t once; - ngx_array_t *types_keys; + ngx_array_t *types_keys; } ngx_http_sub_loc_conf_t; @@ -31,27 +28,27 @@ typedef enum { typedef struct { - ngx_str_t match; + ngx_str_t match; - ngx_uint_t once; /* unsigned once:1 */ + ngx_uint_t once; /* unsigned once:1 */ - ngx_buf_t *buf; + ngx_buf_t *buf; - u_char *pos; - u_char *copy_start; - u_char *copy_end; + u_char *pos; + u_char *copy_start; + u_char *copy_end; - ngx_chain_t *in; - ngx_chain_t *out; - ngx_chain_t **last_out; - ngx_chain_t *busy; - ngx_chain_t *free; + ngx_chain_t *in; + ngx_chain_t *out; + ngx_chain_t **last_out; + ngx_chain_t *busy; + ngx_chain_t *free; - ngx_str_t sub; + ngx_str_t sub; - ngx_uint_t state; - size_t saved; - size_t looked; + ngx_uint_t state; + size_t saved; + size_t looked; } ngx_http_sub_ctx_t; @@ -154,7 +151,6 @@ ngx_http_sub_header_filter(ngx_http_requ ctx->match = slcf->match; ctx->last_out = &ctx->out; - ctx->sub = slcf->sub; r->filter_need_in_memory = 1; @@ -204,7 +200,7 @@ ngx_http_sub_body_filter(ngx_http_reques /* add the incoming chain to the chain ctx->in */ if (in) { - if (ngx_chain_add_copy(r->pool, &ctx->in, in) == NGX_ERROR) { + if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) { return NGX_ERROR; } } @@ -346,9 +342,8 @@ ngx_http_sub_body_filter(ngx_http_reques if (ctx->sub.data == NULL) { - if (ngx_http_script_run(r, &ctx->sub, slcf->sub_lengths->elts, - 0, slcf->sub_values->elts) - == NULL) + if (ngx_http_complex_value(r, &slcf->value, &ctx->sub) + != NGX_OK) { return NGX_ERROR; } @@ -609,9 +604,8 @@ ngx_http_sub_filter(ngx_conf_t *cf, ngx_ { ngx_http_sub_loc_conf_t *slcf = conf; - ngx_str_t *value; - ngx_int_t n; - ngx_http_script_compile_t sc; + ngx_str_t *value; + ngx_http_compile_complex_value_t ccv; if (slcf->match.len) { return "is duplicate"; @@ -623,24 +617,13 @@ ngx_http_sub_filter(ngx_conf_t *cf, ngx_ slcf->match = value[1]; - n = ngx_http_script_variables_count(&value[2]); - - if (n == 0) { - slcf->sub = value[2]; - return NGX_CONF_OK; - } - - ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); - sc.cf = cf; - sc.source = &value[2]; - sc.lengths = &slcf->sub_lengths; - sc.values = &slcf->sub_values; - sc.variables = n; - sc.complete_lengths = 1; - sc.complete_values = 1; + ccv.cf = cf; + ccv.value = &value[2]; + ccv.complex_value = &slcf->value; - if (ngx_http_script_compile(&sc) != NGX_OK) { + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { return NGX_CONF_ERROR; } @@ -684,10 +667,8 @@ ngx_http_sub_merge_conf(ngx_conf_t *cf, ngx_conf_merge_value(conf->once, prev->once, 1); ngx_conf_merge_str_value(conf->match, prev->match, ""); - if (conf->sub.data == NULL && conf->sub_lengths == NULL) { - conf->sub = prev->sub; - conf->sub_lengths = prev->sub_lengths; - conf->sub_values = prev->sub_values; + if (conf->value.value.len == 0) { + conf->value = prev->value; } if (ngx_http_merge_types(cf, conf->types_keys, &conf->types, diff --git a/src/http/modules/ngx_http_upstream_ip_hash_module.c b/src/http/modules/ngx_http_upstream_ip_hash_module.c --- a/src/http/modules/ngx_http_upstream_ip_hash_module.c +++ b/src/http/modules/ngx_http_upstream_ip_hash_module.c @@ -15,7 +15,6 @@ typedef struct { ngx_uint_t hash; - /* AF_INET only */ u_char addr[3]; u_char tries; @@ -111,11 +110,20 @@ ngx_http_upstream_init_ip_hash_peer(ngx_ r->upstream->peer.get = ngx_http_upstream_get_ip_hash_peer; /* AF_INET only */ - sin = (struct sockaddr_in *) r->connection->sockaddr; - p = (u_char *) &sin->sin_addr.s_addr; - iphp->addr[0] = p[0]; - iphp->addr[1] = p[1]; - iphp->addr[2] = p[2]; + + if (r->connection->sockaddr->sa_family == AF_INET) { + + sin = (struct sockaddr_in *) r->connection->sockaddr; + p = (u_char *) &sin->sin_addr.s_addr; + iphp->addr[0] = p[0]; + iphp->addr[1] = p[1]; + iphp->addr[2] = p[2]; + + } else { + iphp->addr[0] = 0; + iphp->addr[1] = 0; + iphp->addr[2] = 0; + } iphp->hash = 89; iphp->tries = 0; 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 @@ -360,10 +360,16 @@ static ngx_int_t ngx_http_userid_set_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf) { - u_char *cookie, *p; - size_t len; - ngx_str_t src, dst; - ngx_table_elt_t *set_cookie, *p3p; + u_char *cookie, *p; + size_t len; + ngx_str_t src, dst; + ngx_table_elt_t *set_cookie, *p3p; + ngx_connection_t *c; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + /* * TODO: in the threaded mode the sequencers should be in TLS and their * ranges should be divided between threads @@ -388,7 +394,28 @@ ngx_http_userid_set_uid(ngx_http_request return NGX_ERROR; } - ctx->uid_set[0] = htonl(r->in_addr); + c = r->connection; + + switch (c->local_sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) c->local_sockaddr; + + p = (u_char *) &ctx->uid_set[0]; + + *p++ = sin6->sin6_addr.s6_addr[12]; + *p++ = sin6->sin6_addr.s6_addr[13]; + *p++ = sin6->sin6_addr.s6_addr[14]; + *p = sin6->sin6_addr.s6_addr[15]; + + break; +#endif + default: /* AF_INET */ + sin = (struct sockaddr_in *) c->local_sockaddr; + ctx->uid_set[0] = sin->sin_addr.s_addr; + break; + } } else { ctx->uid_set[0] = htonl(conf->service); 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 @@ -38,14 +38,8 @@ typedef struct { typedef struct { - ngx_array_t *lengths; - ngx_array_t *values; -} ngx_http_xslt_param_t; - - -typedef struct { xsltStylesheetPtr stylesheet; - ngx_array_t params; /* ngx_http_xslt_param_t */ + ngx_array_t params; /* ngx_http_complex_value_t */ } ngx_http_xslt_sheet_t; @@ -867,30 +861,25 @@ static ngx_int_t ngx_http_xslt_params(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx, ngx_array_t *params) { - u_char *p, *last, *value, *dst, *src, **s; - size_t len; - ngx_uint_t i; - ngx_str_t string; - ngx_http_xslt_param_t *param; + u_char *p, *last, *value, *dst, *src, **s; + size_t len; + ngx_uint_t i; + ngx_str_t string; + ngx_http_complex_value_t *param; param = params->elts; for (i = 0; i < params->nelts; i++) { - if (ngx_http_script_run(r, &string, param[i].lengths->elts, 1, - param[i].values->elts) - == NULL) - { + if (ngx_http_complex_value(r, ¶m[i], &string) != NGX_OK) { return NGX_ERROR; } - last = string.data + string.len - 1; - *last = '\0'; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "xslt filter param: \"%s\"", string.data); p = string.data; + last = string.data + string.len - 1; while (p && *p) { @@ -1073,8 +1062,8 @@ ngx_http_xslt_stylesheet(ngx_conf_t *cf, ngx_pool_cleanup_t *cln; ngx_http_xslt_file_t *file; ngx_http_xslt_sheet_t *sheet; - ngx_http_xslt_param_t *param; - ngx_http_script_compile_t sc; + ngx_http_complex_value_t *param; + ngx_http_compile_complex_value_t ccv; ngx_http_xslt_filter_main_conf_t *xmcf; value = cf->args->elts; @@ -1142,7 +1131,7 @@ found: } if (ngx_array_init(&sheet->params, cf->pool, n - 2, - sizeof(ngx_http_xslt_param_t)) + sizeof(ngx_http_complex_value_t)) != NGX_OK) { return NGX_CONF_ERROR; @@ -1155,22 +1144,17 @@ found: return NGX_CONF_ERROR; } - param->lengths = NULL; - param->values = NULL; - - ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); - sc.cf = cf; - sc.source = &value[i]; - sc.lengths = ¶m->lengths; - sc.values = ¶m->values; - sc.variables = ngx_http_script_variables_count(&value[i]); - sc.complete_lengths = 1; - sc.complete_values = 1; + ccv.cf = cf; + ccv.value = &value[i]; + ccv.complex_value = param; + ccv.zero = 1; - if (ngx_http_script_compile(&sc) != NGX_OK) { + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { return NGX_CONF_ERROR; } + } return NGX_CONF_OK; diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm --- a/src/http/modules/perl/nginx.pm +++ b/src/http/modules/perl/nginx.pm @@ -47,7 +47,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '0.7.34'; +our $VERSION = '0.7.47'; require XSLoader; XSLoader::load('nginx', $VERSION); diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -19,11 +19,17 @@ static ngx_int_t ngx_http_init_phase_han static ngx_int_t ngx_http_init_server_lists(ngx_conf_t *cf, ngx_array_t *servers, ngx_array_t *in_ports); +static ngx_int_t ngx_http_add_ports(ngx_conf_t *cf, + ngx_http_core_srv_conf_t *cscf, ngx_array_t *ports, + ngx_http_listen_t *listen); +static ngx_int_t ngx_http_add_addresses(ngx_conf_t *cf, + ngx_http_core_srv_conf_t *cscf, ngx_http_conf_port_t *port, + ngx_http_listen_t *listen); static ngx_int_t ngx_http_add_address(ngx_conf_t *cf, - ngx_http_core_srv_conf_t *cscf, ngx_http_conf_in_port_t *in_port, + ngx_http_core_srv_conf_t *cscf, ngx_http_conf_port_t *port, ngx_http_listen_t *listen); static ngx_int_t ngx_http_add_names(ngx_conf_t *cf, - ngx_http_core_srv_conf_t *cscf, ngx_http_conf_in_addr_t *in_addr); + ngx_http_core_srv_conf_t *cscf, ngx_http_conf_addr_t *addr); static char *ngx_http_merge_locations(ngx_conf_t *cf, ngx_queue_t *locations, void **loc_conf, ngx_http_module_t *module, @@ -43,13 +49,23 @@ static ngx_http_location_tree_node_t * size_t prefix); static ngx_int_t ngx_http_optimize_servers(ngx_conf_t *cf, - ngx_http_core_main_conf_t *cmcf, ngx_array_t *in_ports); -static ngx_int_t ngx_http_cmp_conf_in_addrs(const void *one, const void *two); + ngx_http_core_main_conf_t *cmcf, ngx_array_t *ports); +static ngx_int_t ngx_http_server_names(ngx_conf_t *cf, + ngx_http_core_main_conf_t *cmcf, ngx_http_conf_addr_t *addr); +static ngx_int_t ngx_http_cmp_conf_addrs(const void *one, const void *two); static int ngx_libc_cdecl ngx_http_cmp_dns_wildcards(const void *one, const void *two); static ngx_int_t ngx_http_init_listening(ngx_conf_t *cf, - ngx_http_conf_in_port_t *in_port); + ngx_http_conf_port_t *port); +static ngx_listening_t *ngx_http_add_listening(ngx_conf_t *cf, + ngx_http_conf_addr_t *addr); +static ngx_int_t ngx_http_add_addrs(ngx_conf_t *cf, ngx_http_port_t *hport, + ngx_http_conf_addr_t *addr); +#if (NGX_HAVE_INET6) +static ngx_int_t ngx_http_add_addrs6(ngx_conf_t *cf, ngx_http_port_t *hport, + ngx_http_conf_addr_t *addr); +#endif ngx_uint_t ngx_http_max_module; @@ -351,8 +367,6 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma * to find quickly the server core module configuration at run-time */ - /* AF_INET only */ - if (ngx_http_init_server_lists(cf, &cmcf->servers, &in_ports) != NGX_OK) { return NGX_CONF_ERROR; } @@ -360,8 +374,6 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma /* optimize the lists of ports, addresses and server names */ - /* AF_INET only */ - if (ngx_http_optimize_servers(cf, cmcf, &in_ports) != NGX_OK) { return NGX_CONF_ERROR; } @@ -1099,16 +1111,13 @@ inclusive: static ngx_int_t ngx_http_init_server_lists(ngx_conf_t *cf, ngx_array_t *servers, - ngx_array_t *in_ports) + ngx_array_t *ports) { - ngx_uint_t s, l, p, a; + ngx_uint_t s, i; ngx_http_listen_t *listen; - ngx_http_conf_in_port_t *in_port; - ngx_http_conf_in_addr_t *in_addr; ngx_http_core_srv_conf_t **cscfp; - if (ngx_array_init(in_ports, cf->temp_pool, 2, - sizeof(ngx_http_conf_in_port_t)) + if (ngx_array_init(ports, cf->temp_pool, 2, sizeof(ngx_http_conf_port_t)) != NGX_OK) { return NGX_ERROR; @@ -1122,92 +1131,11 @@ ngx_http_init_server_lists(ngx_conf_t *c /* "listen" directives */ listen = cscfp[s]->listen.elts; - for (l = 0; l < cscfp[s]->listen.nelts; l++) { - - /* AF_INET only */ - - in_port = in_ports->elts; - for (p = 0; p < in_ports->nelts; p++) { - - if (listen[l].port != in_port[p].port) { - continue; - } - - /* the port is already in the port list */ - - in_addr = in_port[p].addrs.elts; - for (a = 0; a < in_port[p].addrs.nelts; a++) { - - if (listen[l].addr != in_addr[a].addr) { - continue; - } - - /* the address is already in the address list */ - - if (ngx_http_add_names(cf, cscfp[s], &in_addr[a]) != NGX_OK) - { - return NGX_ERROR; - } - - /* - * check the duplicate "default" server - * for this address:port - */ - - if (listen[l].conf.default_server) { - - if (in_addr[a].default_server) { - ngx_log_error(NGX_LOG_ERR, cf->log, 0, - "the duplicate default server in %s:%ui", - listen[l].file_name, listen[l].line); - - return NGX_ERROR; - } - - in_addr[a].core_srv_conf = cscfp[s]; - in_addr[a].default_server = 1; -#if (NGX_HTTP_SSL) - in_addr[a].ssl = listen[l].conf.ssl; -#endif - in_addr[a].listen_conf = &listen[l].conf; - } - - goto found; - } - - /* - * add the address to the addresses list that - * bound to this port - */ - - if (ngx_http_add_address(cf, cscfp[s], &in_port[p], &listen[l]) - != NGX_OK) - { - return NGX_ERROR; - } - - goto found; - } - - /* add the port to the in_port list */ - - in_port = ngx_array_push(in_ports); - if (in_port == NULL) { + for (i = 0; i < cscfp[s]->listen.nelts; i++) { + + if (ngx_http_add_ports(cf, cscfp[s], ports, &listen[i]) != NGX_OK) { return NGX_ERROR; } - - in_port->port = listen[l].port; - in_port->addrs.elts = NULL; - - if (ngx_http_add_address(cf, cscfp[s], in_port, &listen[l]) - != NGX_OK) - { - return NGX_ERROR; - } - - found: - - continue; } } @@ -1215,6 +1143,140 @@ ngx_http_init_server_lists(ngx_conf_t *c } +static ngx_int_t +ngx_http_add_ports(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, + ngx_array_t *ports, ngx_http_listen_t *listen) +{ + in_port_t p; + ngx_uint_t i; + struct sockaddr *sa; + struct sockaddr_in *sin; + ngx_http_conf_port_t *port; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + + sa = (struct sockaddr *) &listen->sockaddr; + + switch (sa->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) sa; + p = sin6->sin6_port; + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) sa; + p = sin->sin_port; + break; + } + + port = ports->elts; + for (i = 0; i < ports->nelts; i++) { + + if (p != port[i].port || sa->sa_family != port[i].family) { + continue; + } + + /* a port is already in the in_port list */ + + return ngx_http_add_addresses(cf, cscf, &port[i], listen); + } + + /* add a port to the in_port list */ + + port = ngx_array_push(ports); + if (port == NULL) { + return NGX_ERROR; + } + + port->family = sa->sa_family; + port->port = p; + port->addrs.elts = NULL; + + return ngx_http_add_address(cf, cscf, port, listen); +} + + +static ngx_int_t +ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, + ngx_http_conf_port_t *port, ngx_http_listen_t *listen) +{ + u_char *p; + size_t len, off; + ngx_uint_t i; + struct sockaddr *sa; + ngx_http_conf_addr_t *addr; + + /* + * we can not compare whole sockaddr struct's as kernel + * may fill some fields in inherited sockaddr struct's + */ + + sa = (struct sockaddr *) &listen->sockaddr; + + switch (sa->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + off = offsetof(struct sockaddr_in6, sin6_addr); + len = 16; + break; +#endif + + default: /* AF_INET */ + off = offsetof(struct sockaddr_in, sin_addr); + len = 4; + break; + } + + p = listen->sockaddr + off; + + addr = port->addrs.elts; + + for (i = 0; i < port->addrs.nelts; i++) { + + if (ngx_memcmp(p, (u_char *) addr[i].sockaddr + off, len) != 0) { + continue; + } + + /* the address is already in the address list */ + + if (ngx_http_add_names(cf, cscf, &addr[i]) != NGX_OK) { + return NGX_ERROR; + } + + /* check the duplicate "default" server for this address:port */ + + if (listen->conf.default_server) { + + if (addr[i].default_server) { + ngx_log_error(NGX_LOG_ERR, cf->log, 0, + "the duplicate default server in %s:%ui", + listen->file_name, listen->line); + + return NGX_ERROR; + } + + addr[i].core_srv_conf = cscf; + addr[i].default_server = 1; +#if (NGX_HTTP_SSL) + addr[i].ssl = listen->conf.ssl; +#endif + addr[i].listen_conf = &listen->conf; + } + + return NGX_OK; + } + + /* add the address to the addresses list that bound to this port */ + + return ngx_http_add_address(cf, cscf, port, listen); +} + + /* * add the server address, the server names and the server core module * configurations to the port (in_port) @@ -1222,60 +1284,62 @@ ngx_http_init_server_lists(ngx_conf_t *c static ngx_int_t ngx_http_add_address(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, - ngx_http_conf_in_port_t *in_port, ngx_http_listen_t *listen) + ngx_http_conf_port_t *port, ngx_http_listen_t *listen) { - ngx_http_conf_in_addr_t *in_addr; - - if (in_port->addrs.elts == NULL) { - if (ngx_array_init(&in_port->addrs, cf->temp_pool, 4, - sizeof(ngx_http_conf_in_addr_t)) + ngx_http_conf_addr_t *addr; + + if (port->addrs.elts == NULL) { + if (ngx_array_init(&port->addrs, cf->temp_pool, 4, + sizeof(ngx_http_conf_addr_t)) != NGX_OK) { return NGX_ERROR; } } - in_addr = ngx_array_push(&in_port->addrs); - if (in_addr == NULL) { + addr = ngx_array_push(&port->addrs); + if (addr == NULL) { return NGX_ERROR; } - in_addr->addr = listen->addr; - in_addr->hash.buckets = NULL; - in_addr->hash.size = 0; - in_addr->wc_head = NULL; - in_addr->wc_tail = NULL; - in_addr->names.elts = NULL; + addr->sockaddr = (struct sockaddr *) &listen->sockaddr; + addr->socklen = listen->socklen; + addr->hash.buckets = NULL; + addr->hash.size = 0; + addr->wc_head = NULL; + addr->wc_tail = NULL; + addr->names.elts = NULL; #if (NGX_PCRE) - in_addr->nregex = 0; - in_addr->regex = NULL; + addr->nregex = 0; + addr->regex = NULL; #endif - in_addr->core_srv_conf = cscf; - in_addr->default_server = listen->conf.default_server; - in_addr->bind = listen->conf.bind; + addr->core_srv_conf = cscf; + addr->default_server = listen->conf.default_server; + addr->bind = listen->conf.bind; + addr->wildcard = listen->conf.wildcard; #if (NGX_HTTP_SSL) - in_addr->ssl = listen->conf.ssl; + addr->ssl = listen->conf.ssl; #endif - in_addr->listen_conf = &listen->conf; - - return ngx_http_add_names(cf, cscf, in_addr); + addr->listen_conf = &listen->conf; + + return ngx_http_add_names(cf, cscf, addr); } /* * add the server names and the server core module - * configurations to the address:port (in_addr) + * configurations to the address:port */ static ngx_int_t ngx_http_add_names(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf, - ngx_http_conf_in_addr_t *in_addr) + ngx_http_conf_addr_t *addr) { ngx_uint_t i; ngx_http_server_name_t *server_names, *name; - if (in_addr->names.elts == NULL) { - if (ngx_array_init(&in_addr->names, cf->temp_pool, 4, + if (addr->names.elts == NULL) { + if (ngx_array_init(&addr->names, cf->temp_pool, 4, sizeof(ngx_http_server_name_t)) != NGX_OK) { @@ -1293,7 +1357,7 @@ ngx_http_add_names(ngx_conf_t *cf, ngx_h ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "name: %V", &server_names[i].name); - name = ngx_array_push(&in_addr->names); + name = ngx_array_push(&addr->names); if (name == NULL) { return NGX_ERROR; } @@ -1307,187 +1371,189 @@ ngx_http_add_names(ngx_conf_t *cf, ngx_h static ngx_int_t ngx_http_optimize_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf, - ngx_array_t *in_ports) + ngx_array_t *ports) +{ + ngx_uint_t s, p, a; + ngx_http_conf_port_t *port; + ngx_http_conf_addr_t *addr; + ngx_http_server_name_t *name; + + port = ports->elts; + for (p = 0; p < ports->nelts; p++) { + + ngx_sort(port[p].addrs.elts, (size_t) port[p].addrs.nelts, + sizeof(ngx_http_conf_addr_t), ngx_http_cmp_conf_addrs); + + /* + * check whether all name-based servers have the same + * configuraiton as a default server for given address:port + */ + + addr = port[p].addrs.elts; + for (a = 0; a < port[p].addrs.nelts; a++) { + + name = addr[a].names.elts; + for (s = 0; s < addr[a].names.nelts; s++) { + + if (addr[a].core_srv_conf == name[s].core_srv_conf +#if (NGX_PCRE) + && name[s].captures == 0 +#endif + ) + { + continue; + } + + if (ngx_http_server_names(cf, cmcf, &addr[a]) != NGX_OK) { + return NGX_ERROR; + } + + break; + } + } + + if (ngx_http_init_listening(cf, &port[p]) != NGX_OK) { + return NGX_ERROR; + } + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_server_names(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf, + ngx_http_conf_addr_t *addr) { ngx_int_t rc; - ngx_uint_t s, p, a; + ngx_uint_t s; ngx_hash_init_t hash; ngx_http_server_name_t *name; ngx_hash_keys_arrays_t ha; - ngx_http_conf_in_port_t *in_port; - ngx_http_conf_in_addr_t *in_addr; #if (NGX_PCRE) ngx_uint_t regex, i; + + regex = 0; #endif - in_port = in_ports->elts; - for (p = 0; p < in_ports->nelts; p++) { - - ngx_sort(in_port[p].addrs.elts, (size_t) in_port[p].addrs.nelts, - sizeof(ngx_http_conf_in_addr_t), ngx_http_cmp_conf_in_addrs); - - /* - * check whether all name-based servers have - * the same configuraiton as the default server - */ - - in_addr = in_port[p].addrs.elts; - for (a = 0; a < in_port[p].addrs.nelts; a++) { - - name = in_addr[a].names.elts; - for (s = 0; s < in_addr[a].names.nelts; s++) { - - if (in_addr[a].core_srv_conf != name[s].core_srv_conf) { - goto virtual_names; - } - } - - /* - * if all name-based servers have the same configuration - * as the default server, then we do not need to check - * them at run-time at all - */ - - in_addr[a].names.nelts = 0; - - continue; - - virtual_names: - - ngx_memzero(&ha, sizeof(ngx_hash_keys_arrays_t)); - - ha.temp_pool = ngx_create_pool(16384, cf->log); - if (ha.temp_pool == NULL) { - return NGX_ERROR; - } - - ha.pool = cf->pool; - - if (ngx_hash_keys_array_init(&ha, NGX_HASH_LARGE) != NGX_OK) { - goto failed; - } - -#if (NGX_PCRE) - regex = 0; -#endif - - name = in_addr[a].names.elts; - - for (s = 0; s < in_addr[a].names.nelts; s++) { + ngx_memzero(&ha, sizeof(ngx_hash_keys_arrays_t)); + + ha.temp_pool = ngx_create_pool(16384, cf->log); + if (ha.temp_pool == NULL) { + return NGX_ERROR; + } + + ha.pool = cf->pool; + + if (ngx_hash_keys_array_init(&ha, NGX_HASH_LARGE) != NGX_OK) { + goto failed; + } + + name = addr->names.elts; + + for (s = 0; s < addr->names.nelts; s++) { #if (NGX_PCRE) - if (name[s].regex) { - regex++; - continue; - } + if (name[s].regex) { + regex++; + continue; + } #endif - rc = ngx_hash_add_key(&ha, &name[s].name, name[s].core_srv_conf, - NGX_HASH_WILDCARD_KEY); - - if (rc == NGX_ERROR) { - return NGX_ERROR; - } - - if (rc == NGX_DECLINED) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "invalid server name or wildcard \"%V\" on %s", - &name[s].name, in_addr[a].listen_conf->addr); - return NGX_ERROR; - } - - if (rc == NGX_BUSY) { - ngx_log_error(NGX_LOG_WARN, cf->log, 0, - "conflicting server name \"%V\" on %s, ignored", - &name[s].name, in_addr[a].listen_conf->addr); - } - } - - hash.key = ngx_hash_key_lc; - hash.max_size = cmcf->server_names_hash_max_size; - hash.bucket_size = cmcf->server_names_hash_bucket_size; - hash.name = "server_names_hash"; - hash.pool = cf->pool; - - if (ha.keys.nelts) { - hash.hash = &in_addr[a].hash; - hash.temp_pool = NULL; - - if (ngx_hash_init(&hash, ha.keys.elts, ha.keys.nelts) != NGX_OK) - { - goto failed; - } - } - - if (ha.dns_wc_head.nelts) { - - ngx_qsort(ha.dns_wc_head.elts, - (size_t) ha.dns_wc_head.nelts, - sizeof(ngx_hash_key_t), - ngx_http_cmp_dns_wildcards); - - hash.hash = NULL; - hash.temp_pool = ha.temp_pool; - - if (ngx_hash_wildcard_init(&hash, ha.dns_wc_head.elts, - ha.dns_wc_head.nelts) - != NGX_OK) - { - goto failed; - } - - in_addr[a].wc_head = (ngx_hash_wildcard_t *) hash.hash; - } - - if (ha.dns_wc_tail.nelts) { - - ngx_qsort(ha.dns_wc_tail.elts, - (size_t) ha.dns_wc_tail.nelts, - sizeof(ngx_hash_key_t), - ngx_http_cmp_dns_wildcards); - - hash.hash = NULL; - hash.temp_pool = ha.temp_pool; - - if (ngx_hash_wildcard_init(&hash, ha.dns_wc_tail.elts, - ha.dns_wc_tail.nelts) - != NGX_OK) - { - goto failed; - } - - in_addr[a].wc_tail = (ngx_hash_wildcard_t *) hash.hash; - } - - ngx_destroy_pool(ha.temp_pool); + rc = ngx_hash_add_key(&ha, &name[s].name, name[s].core_srv_conf, + NGX_HASH_WILDCARD_KEY); + + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (rc == NGX_DECLINED) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "invalid server name or wildcard \"%V\" on %s", + &name[s].name, addr->listen_conf->addr); + return NGX_ERROR; + } + + if (rc == NGX_BUSY) { + ngx_log_error(NGX_LOG_WARN, cf->log, 0, + "conflicting server name \"%V\" on %s, ignored", + &name[s].name, addr->listen_conf->addr); + } + } + + hash.key = ngx_hash_key_lc; + hash.max_size = cmcf->server_names_hash_max_size; + hash.bucket_size = cmcf->server_names_hash_bucket_size; + hash.name = "server_names_hash"; + hash.pool = cf->pool; + + if (ha.keys.nelts) { + hash.hash = &addr->hash; + hash.temp_pool = NULL; + + if (ngx_hash_init(&hash, ha.keys.elts, ha.keys.nelts) != NGX_OK) { + goto failed; + } + } + + if (ha.dns_wc_head.nelts) { + + ngx_qsort(ha.dns_wc_head.elts, (size_t) ha.dns_wc_head.nelts, + sizeof(ngx_hash_key_t), ngx_http_cmp_dns_wildcards); + + hash.hash = NULL; + hash.temp_pool = ha.temp_pool; + + if (ngx_hash_wildcard_init(&hash, ha.dns_wc_head.elts, + ha.dns_wc_head.nelts) + != NGX_OK) + { + goto failed; + } + + addr->wc_head = (ngx_hash_wildcard_t *) hash.hash; + } + + if (ha.dns_wc_tail.nelts) { + + ngx_qsort(ha.dns_wc_tail.elts, (size_t) ha.dns_wc_tail.nelts, + sizeof(ngx_hash_key_t), ngx_http_cmp_dns_wildcards); + + hash.hash = NULL; + hash.temp_pool = ha.temp_pool; + + if (ngx_hash_wildcard_init(&hash, ha.dns_wc_tail.elts, + ha.dns_wc_tail.nelts) + != NGX_OK) + { + goto failed; + } + + addr->wc_tail = (ngx_hash_wildcard_t *) hash.hash; + } + + ngx_destroy_pool(ha.temp_pool); #if (NGX_PCRE) - if (regex == 0) { - continue; - } - - in_addr[a].nregex = regex; - in_addr[a].regex = ngx_palloc(cf->pool, - regex * sizeof(ngx_http_server_name_t)); - - if (in_addr[a].regex == NULL) { - return NGX_ERROR; - } - - for (i = 0, s = 0; s < in_addr[a].names.nelts; s++) { - if (name[s].regex) { - in_addr[a].regex[i++] = name[s]; - } - } -#endif - } - - if (ngx_http_init_listening(cf, &in_port[p]) != NGX_OK) { - return NGX_ERROR; + if (regex == 0) { + return NGX_OK; + } + + addr->nregex = regex; + addr->regex = ngx_palloc(cf->pool, regex * sizeof(ngx_http_server_name_t)); + if (addr->regex == NULL) { + return NGX_ERROR; + } + + for (i = 0, s = 0; s < addr->names.nelts; s++) { + if (name[s].regex) { + addr->regex[i++] = name[s]; } } +#endif + return NGX_OK; failed: @@ -1499,15 +1565,15 @@ failed: static ngx_int_t -ngx_http_cmp_conf_in_addrs(const void *one, const void *two) +ngx_http_cmp_conf_addrs(const void *one, const void *two) { - ngx_http_conf_in_addr_t *first, *second; - - first = (ngx_http_conf_in_addr_t *) one; - second = (ngx_http_conf_in_addr_t *) two; - - if (first->addr == INADDR_ANY) { - /* the INADDR_ANY must be the last resort, shift it to the end */ + ngx_http_conf_addr_t *first, *second; + + first = (ngx_http_conf_addr_t *) one; + second = (ngx_http_conf_addr_t *) two; + + if (first->wildcard) { + /* a wildcard address must be the last resort, shift it to the end */ return 1; } @@ -1540,171 +1606,299 @@ ngx_http_cmp_dns_wildcards(const void *o static ngx_int_t -ngx_http_init_listening(ngx_conf_t *cf, ngx_http_conf_in_port_t *in_port) +ngx_http_init_listening(ngx_conf_t *cf, ngx_http_conf_port_t *port) { - ngx_uint_t i, a, last, bind_all, done; + ngx_uint_t i, last, bind_wildcard; ngx_listening_t *ls; - ngx_http_in_port_t *hip; - ngx_http_conf_in_addr_t *in_addr; - ngx_http_virtual_names_t *vn; - ngx_http_core_loc_conf_t *clcf; - ngx_http_core_srv_conf_t *cscf; - - in_addr = in_port->addrs.elts; - last = in_port->addrs.nelts; + ngx_http_port_t *hport; + ngx_http_conf_addr_t *addr; + + addr = port->addrs.elts; + last = port->addrs.nelts; /* - * if there is a binding to a "*:port" then we need to bind() - * to the "*:port" only and ignore other bindings + * If there is a binding to an "*:port" then we need to bind() to + * the "*:port" only and ignore other implicit bindings. The bindings + * have been already sorted: explicit bindings are on the start, then + * implicit bindings go, and wildcard binding is in the end. */ - if (in_addr[last - 1].addr == INADDR_ANY) { - in_addr[last - 1].bind = 1; - bind_all = 0; + if (addr[last - 1].wildcard) { + addr[last - 1].bind = 1; + bind_wildcard = 1; } else { - bind_all = 1; + bind_wildcard = 0; } - a = 0; - - while (a < last) { - - if (!bind_all && !in_addr[a].bind) { - a++; + i = 0; + + while (i < last) { + + if (bind_wildcard && !addr[i].bind) { + i++; continue; } - ls = ngx_listening_inet_stream_socket(cf, in_addr[a].addr, - in_port->port); + ls = ngx_http_add_listening(cf, &addr[i]); if (ls == NULL) { return NGX_ERROR; } - ls->addr_ntop = 1; - - ls->handler = ngx_http_init_connection; - - cscf = in_addr[a].core_srv_conf; - ls->pool_size = cscf->connection_pool_size; - ls->post_accept_timeout = cscf->client_header_timeout; - - clcf = cscf->ctx->loc_conf[ngx_http_core_module.ctx_index]; - - ls->log = *clcf->err_log; - ls->log.data = &ls->addr_text; - ls->log.handler = ngx_accept_log_error; - -#if (NGX_WIN32) - { - ngx_iocp_conf_t *iocpcf; - - iocpcf = ngx_event_get_conf(cf->cycle->conf_ctx, ngx_iocp_module); - if (iocpcf->acceptex_read) { - ls->post_accept_buffer_size = cscf->client_header_buffer_size; - } - } -#endif - - ls->backlog = in_addr[a].listen_conf->backlog; - ls->rcvbuf = in_addr[a].listen_conf->rcvbuf; - ls->sndbuf = in_addr[a].listen_conf->sndbuf; - -#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) - ls->accept_filter = in_addr[a].listen_conf->accept_filter; -#endif - -#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) - ls->deferred_accept = in_addr[a].listen_conf->deferred_accept; -#endif - - hip = ngx_palloc(cf->pool, sizeof(ngx_http_in_port_t)); - if (hip == NULL) { - return NGX_ERROR; - } - - hip->port = in_port->port; - - hip->port_text.data = ngx_pnalloc(cf->pool, 7); - if (hip->port_text.data == NULL) { + hport = ngx_pcalloc(cf->pool, sizeof(ngx_http_port_t)); + if (hport == NULL) { return NGX_ERROR; } - ls->servers = hip; - - hip->port_text.len = ngx_sprintf(hip->port_text.data, ":%d", hip->port) - - hip->port_text.data; - - in_addr = in_port->addrs.elts; - - if (in_addr[a].bind && in_addr[a].addr != INADDR_ANY) { - hip->naddrs = 1; - done = 0; - - } else if (in_port->addrs.nelts > 1 - && in_addr[last - 1].addr == INADDR_ANY) - { - hip->naddrs = last; - done = 1; + ls->servers = hport; + + if (i == last - 1) { + hport->naddrs = last; } else { - hip->naddrs = 1; - done = 0; - } - - hip->addrs = ngx_pcalloc(cf->pool, - hip->naddrs * sizeof(ngx_http_in_addr_t)); - if (hip->addrs == NULL) { - return NGX_ERROR; + hport->naddrs = 1; + i = 0; } - for (i = 0; i < hip->naddrs; i++) { - hip->addrs[i].addr = in_addr[i].addr; - hip->addrs[i].core_srv_conf = in_addr[i].core_srv_conf; - -#if (NGX_HTTP_SSL) - hip->addrs[i].ssl = in_addr[i].ssl; -#endif - - if (in_addr[i].hash.buckets == NULL - && (in_addr[i].wc_head == NULL - || in_addr[i].wc_head->hash.buckets == NULL) - && (in_addr[i].wc_head == NULL - || in_addr[i].wc_head->hash.buckets == NULL)) - { - continue; - } - - vn = ngx_palloc(cf->pool, sizeof(ngx_http_virtual_names_t)); - if (vn == NULL) { + switch (ls->sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + if (ngx_http_add_addrs6(cf, hport, addr) != NGX_OK) { return NGX_ERROR; } - hip->addrs[i].virtual_names = vn; - - vn->names.hash = in_addr[i].hash; - vn->names.wc_head = in_addr[i].wc_head; - vn->names.wc_tail = in_addr[i].wc_tail; -#if (NGX_PCRE) - vn->nregex = in_addr[i].nregex; - vn->regex = in_addr[i].regex; + break; #endif + default: /* AF_INET */ + if (ngx_http_add_addrs(cf, hport, addr) != NGX_OK) { + return NGX_ERROR; + } + break; } - if (done) { - return NGX_OK; - } - - in_addr++; - in_port->addrs.elts = in_addr; + addr++; last--; - - a = 0; } return NGX_OK; } +static ngx_listening_t * +ngx_http_add_listening(ngx_conf_t *cf, ngx_http_conf_addr_t *addr) +{ + ngx_listening_t *ls; + struct sockaddr *sa; + ngx_http_core_loc_conf_t *clcf; + ngx_http_core_srv_conf_t *cscf; + u_char text[NGX_SOCKADDR_STRLEN]; + + ls = ngx_array_push(&cf->cycle->listening); + if (ls == NULL) { + return NULL; + } + + ngx_memzero(ls, sizeof(ngx_listening_t)); + + sa = ngx_palloc(cf->pool, addr->socklen); + if (sa == NULL) { + return NULL; + } + + ngx_memcpy(sa, addr->sockaddr, addr->socklen); + + ls->sockaddr = sa; + ls->socklen = addr->socklen; + + ls->addr_text.len = ngx_sock_ntop(sa, text, NGX_SOCKADDR_STRLEN, 1); + + ls->addr_text.data = ngx_pnalloc(cf->pool, ls->addr_text.len); + if (ls->addr_text.data == NULL) { + return NULL; + } + + ngx_memcpy(ls->addr_text.data, text, ls->addr_text.len); + + ls->fd = (ngx_socket_t) -1; + ls->type = SOCK_STREAM; + + switch (ls->sockaddr->sa_family) { +#if (NGX_HAVE_INET6) + case AF_INET6: + ls->addr_text_max_len = NGX_INET6_ADDRSTRLEN; + break; +#endif + case AF_INET: + ls->addr_text_max_len = NGX_INET_ADDRSTRLEN; + break; + default: + ls->addr_text_max_len = NGX_SOCKADDR_STRLEN; + break; + } + + ls->addr_ntop = 1; + + ls->handler = ngx_http_init_connection; + + cscf = addr->core_srv_conf; + ls->pool_size = cscf->connection_pool_size; + ls->post_accept_timeout = cscf->client_header_timeout; + + clcf = cscf->ctx->loc_conf[ngx_http_core_module.ctx_index]; + + ls->log = *clcf->err_log; + ls->log.data = &ls->addr_text; + ls->log.handler = ngx_accept_log_error; + +#if (NGX_WIN32) + { + ngx_iocp_conf_t *iocpcf; + + iocpcf = ngx_event_get_conf(cf->cycle->conf_ctx, ngx_iocp_module); + if (iocpcf->acceptex_read) { + ls->post_accept_buffer_size = cscf->client_header_buffer_size; + } + } +#endif + + ls->backlog = addr->listen_conf->backlog; + ls->rcvbuf = addr->listen_conf->rcvbuf; + ls->sndbuf = addr->listen_conf->sndbuf; + +#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) + ls->accept_filter = addr->listen_conf->accept_filter; +#endif + +#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) + ls->deferred_accept = addr->listen_conf->deferred_accept; +#endif + +#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) + ls->ipv6only = addr->listen_conf->ipv6only; +#endif + + return ls; +} + + +static ngx_int_t +ngx_http_add_addrs(ngx_conf_t *cf, ngx_http_port_t *hport, + ngx_http_conf_addr_t *addr) +{ + ngx_uint_t i; + ngx_http_in_addr_t *addrs; + struct sockaddr_in *sin; + ngx_http_virtual_names_t *vn; + + hport->addrs = ngx_pcalloc(cf->pool, + hport->naddrs * sizeof(ngx_http_in_addr_t)); + if (hport->addrs == NULL) { + return NGX_ERROR; + } + + addrs = hport->addrs; + + for (i = 0; i < hport->naddrs; i++) { + + sin = (struct sockaddr_in *) addr[i].sockaddr; + addrs[i].addr = sin->sin_addr.s_addr; + addrs[i].conf.core_srv_conf = addr[i].core_srv_conf; +#if (NGX_HTTP_SSL) + addrs[i].conf.ssl = addr[i].ssl; +#endif + + if (addr[i].hash.buckets == NULL + && (addr[i].wc_head == NULL + || addr[i].wc_head->hash.buckets == NULL) + && (addr[i].wc_tail == NULL + || addr[i].wc_tail->hash.buckets == NULL) +#if (NGX_PCRE) + && addr[i].nregex == 0 +#endif + ) + { + continue; + } + + vn = ngx_palloc(cf->pool, sizeof(ngx_http_virtual_names_t)); + if (vn == NULL) { + return NGX_ERROR; + } + + addrs[i].conf.core_srv_conf->virtual_names = vn; + + vn->names.hash = addr[i].hash; + vn->names.wc_head = addr[i].wc_head; + vn->names.wc_tail = addr[i].wc_tail; +#if (NGX_PCRE) + vn->nregex = addr[i].nregex; + vn->regex = addr[i].regex; +#endif + } + + return NGX_OK; +} + + +#if (NGX_HAVE_INET6) + +static ngx_int_t +ngx_http_add_addrs6(ngx_conf_t *cf, ngx_http_port_t *hport, + ngx_http_conf_addr_t *addr) +{ + ngx_uint_t i; + ngx_http_in6_addr_t *addrs6; + struct sockaddr_in6 *sin6; + ngx_http_virtual_names_t *vn; + + hport->addrs = ngx_pcalloc(cf->pool, + hport->naddrs * sizeof(ngx_http_in6_addr_t)); + if (hport->addrs == NULL) { + return NGX_ERROR; + } + + addrs6 = hport->addrs; + + for (i = 0; i < hport->naddrs; i++) { + + sin6 = (struct sockaddr_in6 *) addr[i].sockaddr; + addrs6[i].addr6 = sin6->sin6_addr; + addrs6[i].conf.core_srv_conf = addr[i].core_srv_conf; +#if (NGX_HTTP_SSL) + addrs6[i].conf.ssl = addr[i].ssl; +#endif + + if (addr[i].hash.buckets == NULL + && (addr[i].wc_head == NULL + || addr[i].wc_head->hash.buckets == NULL) + && (addr[i].wc_head == NULL + || addr[i].wc_head->hash.buckets == NULL)) + { + continue; + } + + vn = ngx_palloc(cf->pool, sizeof(ngx_http_virtual_names_t)); + if (vn == NULL) { + return NGX_ERROR; + } + + addrs6[i].conf.core_srv_conf->virtual_names = vn; + + vn->names.hash = addr[i].hash; + vn->names.wc_head = addr[i].wc_head; + vn->names.wc_tail = addr[i].wc_tail; +#if (NGX_PCRE) + vn->nregex = addr[i].nregex; + vn->regex = addr[i].regex; +#endif + } + + return NGX_OK; +} + +#endif + + char * ngx_http_types_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -10,12 +10,13 @@ #include #include -#include -typedef struct ngx_http_request_s ngx_http_request_t; -typedef struct ngx_http_upstream_s ngx_http_upstream_t; -typedef struct ngx_http_log_ctx_s ngx_http_log_ctx_t; +typedef struct ngx_http_request_s ngx_http_request_t; +typedef struct ngx_http_upstream_s ngx_http_upstream_t; +typedef struct ngx_http_cache_s ngx_http_cache_t; +typedef struct ngx_http_file_cache_s ngx_http_file_cache_t; +typedef struct ngx_http_log_ctx_s ngx_http_log_ctx_t; typedef ngx_int_t (*ngx_http_header_handler_pt)(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); @@ -23,21 +24,18 @@ typedef u_char *(*ngx_http_log_handler_p ngx_http_request_t *sr, u_char *buf, size_t len); -#if (NGX_HTTP_CACHE) -#include -#endif -/* STUB */ -#include - #include #include #include #include #include #include +#include #include -#include +#if (NGX_HTTP_CACHE) +#include +#endif #if (NGX_HTTP_SSI) #include #endif @@ -78,6 +76,8 @@ ngx_int_t ngx_http_parse_multi_header_li ngx_str_t *name, ngx_str_t *value); ngx_int_t ngx_http_arg(ngx_http_request_t *r, u_char *name, size_t len, ngx_str_t *value); +void ngx_http_split_args(ngx_http_request_t *r, ngx_str_t *uri, + ngx_str_t *args); ngx_int_t ngx_http_find_server_conf(ngx_http_request_t *r); diff --git a/src/http/ngx_http_cache.c b/src/http/ngx_http_cache.c deleted file mode 100644 --- a/src/http/ngx_http_cache.c +++ /dev/null @@ -1,576 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#include -#include -#include - - -#if 0 - -static ngx_http_module_t ngx_http_cache_module_ctx = { - NULL, /* pre conf */ - - NULL, /* 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_cache_module = { - NGX_MODULE, - &ngx_http_cache_module_ctx, /* module context */ - NULL, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - NULL, /* init module */ - NULL /* init process */ -}; - -#endif - - -static ngx_int_t ngx_http_cache_create(ngx_http_request_t *r) -{ - ngx_str_t *key; - - if (!(r->cache = ngx_pcalloc(r->pool, sizeof(ngx_http_cache_t)))) { - return NGX_ERROR; - } - - if (ngx_array_init(&r->cache->key, r->pool, 5, sizeof(ngx_str_t)) - == NGX_ERROR) - { - return NGX_ERROR; - } - - /* preallocate the primary key */ - - if (!(key = ngx_array_push(&r->cache->key))) { - return NGX_ERROR; - } - - key->len = 0; - key->data = NULL; - - /* - * we use offsetof() because sizeof() pads the struct size to the int size - */ - - r->cache->header_size = offsetof(ngx_http_cache_header_t, key); - - r->cache->log = r->connection->log; - r->cache->file.log = r->connection->log; - - return NGX_OK; -} - - -ngx_int_t ngx_http_cache_get(ngx_http_request_t *r, ngx_http_cache_ctx_t *ctx) -{ - ngx_str_t *key; - ngx_http_cache_t *c; - - if (r->cache == NULL) { - if (ngx_http_cache_create(r) == NGX_ERROR) { - return NGX_ABORT; - } - } - - c = r->cache; - key = c->key.elts; - - if (ctx->primary) { - key[0] = ctx->key; - c->header_size += ctx->key.len; - c->key_len += ctx->key.len; - c->buf = ctx->buf; - - } else { - if (key[0].len == 0) { - key[0] = r->uri; - c->header_size += r->uri.len; - c->key_len += ctx->key.len; - } - - if (!(key = ngx_array_push(&r->cache->key))) { - return NGX_ABORT; - } - - c->header_size += ctx->key.len; - c->key_len += ctx->key.len; - } - -#if 0 - - if (ctx->memory) { - ngx_http_memory_cache_get(r, ctx); - } - -#endif - - if (ctx->file) { - return ngx_http_file_cache_get(r, ctx); - } - - return NGX_DECLINED; -} - - -#if 0 - - -ngx_http_cache_t *ngx_http_cache_get(ngx_http_cache_hash_t *hash, - ngx_http_cleanup_t *cleanup, - ngx_str_t *key, uint32_t *crc) -{ - ngx_uint_t i; - ngx_http_cache_t *c; - - *crc = ngx_crc(key->data, key->len); - - c = hash->elts + *crc % hash->hash * hash->nelts; - - if (ngx_mutex_lock(&hash->mutex) == NGX_ERROR) { - return (void *) NGX_ERROR; - } - - for (i = 0; i < hash->nelts; i++) { - if (c[i].crc == *crc - && c[i].key.len == key->len - && ngx_rstrncmp(c[i].key.data, key->data, key->len) == 0) - { -#if 0 - if (c[i].expired) { - ngx_mutex_unlock(&hash->mutex); - return (void *) NGX_AGAIN; - } -#endif - - c[i].refs++; - - if ((!(c[i].notify && (ngx_event_flags & NGX_USE_KQUEUE_EVENT))) - && (ngx_cached_time - c[i].updated >= hash->update)) - { - c[i].expired = 1; - } - - ngx_mutex_unlock(&hash->mutex); - - if (cleanup) { - cleanup->data.cache.hash = hash; - cleanup->data.cache.cache = &c[i]; - cleanup->valid = 1; - cleanup->cache = 1; - } - - return &c[i]; - } - } - - ngx_mutex_unlock(&hash->mutex); - - return NULL; -} - - -ngx_http_cache_t *ngx_http_cache_alloc(ngx_http_cache_hash_t *hash, - ngx_http_cache_t *cache, - ngx_http_cleanup_t *cleanup, - ngx_str_t *key, uint32_t crc, - ngx_str_t *value, ngx_log_t *log) -{ - time_t old; - ngx_uint_t i; - ngx_http_cache_t *c; - - old = ngx_cached_time + 1; - - c = hash->elts + crc % hash->hash * hash->nelts; - - if (ngx_mutex_lock(&hash->mutex) == NGX_ERROR) { - return (void *) NGX_ERROR; - } - - if (cache == NULL) { - - /* allocate a new entry */ - - for (i = 0; i < hash->nelts; i++) { - if (c[i].refs > 0) { - /* a busy entry */ - continue; - } - - if (c[i].key.len == 0) { - /* a free entry is found */ - cache = &c[i]; - break; - } - - /* looking for the oldest cache entry */ - - if (old > c[i].accessed) { - - old = c[i].accessed; - cache = &c[i]; - } - } - - if (cache == NULL) { - ngx_mutex_unlock(&hash->mutex); - return NULL; - } - - ngx_http_cache_free(cache, key, value, log); - - if (cache->key.data == NULL) { - cache->key.data = ngx_alloc(key->len, log); - if (cache->key.data == NULL) { - ngx_http_cache_free(cache, NULL, NULL, log); - ngx_mutex_unlock(&hash->mutex); - return NULL; - } - } - - cache->key.len = key->len; - ngx_memcpy(cache->key.data, key->data, key->len); - - } else if (value) { - ngx_http_cache_free(cache, key, value, log); - } - - if (value) { - if (cache->data.value.data == NULL) { - cache->data.value.data = ngx_alloc(value->len, log); - if (cache->data.value.data == NULL) { - ngx_http_cache_free(cache, NULL, NULL, log); - ngx_mutex_unlock(&hash->mutex); - return NULL; - } - } - - cache->data.value.len = value->len; - ngx_memcpy(cache->data.value.data, value->data, value->len); - } - - cache->crc = crc; - cache->key.len = key->len; - - cache->refs = 1; - cache->count = 0; - - cache->deleted = 0; - cache->expired = 0; - cache->memory = 0; - cache->mmap = 0; - cache->notify = 0; - - if (cleanup) { - cleanup->data.cache.hash = hash; - cleanup->data.cache.cache = cache; - cleanup->valid = 1; - cleanup->cache = 1; - } - - ngx_mutex_unlock(&hash->mutex); - - return cache; -} - - -void ngx_http_cache_free(ngx_http_cache_t *cache, - ngx_str_t *key, ngx_str_t *value, ngx_log_t *log) -{ - if (cache->memory) { - if (cache->data.value.data - && (value == NULL || value->len > cache->data.value.len)) - { - ngx_free(cache->data.value.data); - cache->data.value.data = NULL; - } - } - - /* TODO: mmap */ - - cache->data.value.len = 0; - - if (cache->fd != NGX_INVALID_FILE) { - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, - "http cache close fd: %d", cache->fd); - - if (ngx_close_file(cache->fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, - ngx_close_file_n " \"%s\" failed", - cache->key.data); - } - - cache->fd = NGX_INVALID_FILE; - } - - if (cache->key.data && (key == NULL || key->len > cache->key.len)) { - ngx_free(cache->key.data); - cache->key.data = NULL; - } - - cache->key.len = 0; - - cache->refs = 0; -} - - -void ngx_http_cache_lock(ngx_http_cache_hash_t *hash, ngx_http_cache_t *cache) -{ - if (ngx_mutex_lock(&hash->mutex) == NGX_ERROR) { - return; - } -} - - -void ngx_http_cache_unlock(ngx_http_cache_hash_t *hash, - ngx_http_cache_t *cache, ngx_log_t *log) -{ - if (ngx_mutex_lock(&hash->mutex) == NGX_ERROR) { - return; - } - - cache->refs--; - - if (cache->refs == 0 && cache->deleted) { - ngx_http_cache_free(cache, NULL, NULL, log); - } - - ngx_mutex_unlock(&hash->mutex); -} - - -#if 0 - -ngx_http_cache_add_file_event(ngx_http_cache_hash_t *hash, - ngx_http_cache_t *cache) -{ - ngx_event_t *ev; - ngx_http_cache_event_ctx_t *ctx; - - ev = &ngx_cycle->read_events[fd]; - ngx_memzero(ev, sizeof(ngx_event_t); - - ev->data = data; - ev->event_handler = ngx_http_cache_invalidate; - - return ngx_add_event(ev, NGX_VNODE_EVENT, 0); -} - - -void ngx_http_cache_invalidate(ngx_event_t *ev) -{ - ngx_http_cache_event_ctx_t *ctx; - - ctx = ev->data; - - ngx_http_cache_lock(&ctx->hash->mutex); - - if (ctx->cache->refs == 0) - ngx_http_cache_free(ctx->cache, NULL, NULL, ctx->log); - - } else { - ctx->cache->deleted = 1; - } - - ngx_http_cache_unlock(&ctx->hash->mutex); -} - -#endif - - -/* TODO: currently fd only */ - -ngx_int_t ngx_http_send_cached(ngx_http_request_t *r) -{ - ngx_int_t rc; - ngx_hunk_t *h; - ngx_chain_t out; - ngx_http_log_ctx_t *ctx; - - ctx = r->connection->log->data; - ctx->action = "sending response to client"; - - r->headers_out.status = NGX_HTTP_OK; - r->headers_out.content_length_n = r->cache->data.size; - r->headers_out.last_modified_time = r->cache->last_modified; - - if (ngx_http_set_content_type(r) != NGX_OK) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - /* we need to allocate all before the header would be sent */ - - if (!(h = ngx_pcalloc(r->pool, sizeof(ngx_hunk_t)))) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - if (!(h->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)))) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - rc = ngx_http_send_header(r); - - if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { - return rc; - } - - h->type = r->main ? NGX_HUNK_FILE : NGX_HUNK_FILE|NGX_HUNK_LAST; - - h->file_pos = 0; - h->file_last = r->cache->data.size; - - h->file->fd = r->cache->fd; - h->file->log = r->connection->log; - - out.hunk = h; - out.next = NULL; - - return ngx_http_output_filter(r, &out); -} - - -char *ngx_http_set_cache_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - char *p = conf; - - ngx_int_t i, j, dup, invalid; - ngx_str_t *value, line; - ngx_http_cache_t *c; - ngx_http_cache_hash_t *ch, **chp; - - chp = (ngx_http_cache_hash_t **) (p + cmd->offset); - if (*chp) { - return "is duplicate"; - } - - if (!(ch = ngx_pcalloc(cf->pool, sizeof(ngx_http_cache_hash_t)))) { - return NGX_CONF_ERROR; - } - *chp = ch; - - dup = 0; - invalid = 0; - - value = cf->args->elts; - - for (i = 1; i < cf->args->nelts; i++) { - - if (value[i].data[1] != '=') { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid value \"%s\"", value[i].data); - return NGX_CONF_ERROR; - } - - switch (value[i].data[0]) { - - case 'h': - if (ch->hash) { - dup = 1; - break; - } - - ch->hash = ngx_atoi(value[i].data + 2, value[i].len - 2); - if (ch->hash == (size_t) NGX_ERROR || ch->hash == 0) { - invalid = 1; - break; - } - - continue; - - case 'n': - if (ch->nelts) { - dup = 1; - break; - } - - ch->nelts = ngx_atoi(value[i].data + 2, value[i].len - 2); - if (ch->nelts == (size_t) NGX_ERROR || ch->nelts == 0) { - invalid = 1; - break; - } - - continue; - - case 'l': - if (ch->life) { - dup = 1; - break; - } - - line.len = value[i].len - 2; - line.data = value[i].data + 2; - - ch->life = ngx_parse_time(&line, 1); - if (ch->life == NGX_ERROR || ch->life == 0) { - invalid = 1; - break; - } - - continue; - - case 'u': - if (ch->update) { - dup = 1; - break; - } - - line.len = value[i].len - 2; - line.data = value[i].data + 2; - - ch->update = ngx_parse_time(&line, 1); - if (ch->update == NGX_ERROR || ch->update == 0) { - invalid = 1; - break; - } - - continue; - - default: - invalid = 1; - } - - if (dup) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "duplicate value \"%s\"", value[i].data); - return NGX_CONF_ERROR; - } - - if (invalid) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid value \"%s\"", value[i].data); - return NGX_CONF_ERROR; - } - } - - ch->elts = ngx_pcalloc(cf->pool, - ch->hash * ch->nelts * sizeof(ngx_http_cache_t)); - if (ch->elts == NULL) { - return NGX_CONF_ERROR; - } - - for (i = 0; i < (ngx_int_t) ch->hash; i++) { - c = ch->elts + i * ch->nelts; - - for (j = 0; j < (ngx_int_t) ch->nelts; j++) { - c[j].fd = NGX_INVALID_FILE; - } - } - - return NGX_CONF_OK; -} - - -#endif 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 @@ -13,145 +13,122 @@ #include -/* - * The 3 bits allows the 7 uses before the cache entry allocation. - * We can use maximum 7 bits, i.e up to the 127 uses. - */ -#define NGX_HTTP_CACHE_LAZY_ALLOCATION_BITS 3 - - -typedef struct { - uint32_t crc; - ngx_str_t key; - time_t accessed; - - unsigned refs:20; /* 1048576 references */ - - unsigned count:NGX_HTTP_CACHE_LAZY_ALLOCATION_BITS; - - unsigned deleted:1; - unsigned expired:1; - unsigned memory:1; - unsigned mmap:1; - unsigned notify:1; - - ngx_fd_t fd; -#if (NGX_USE_HTTP_FILE_CACHE_UNIQ) - ngx_file_uniq_t uniq; /* no needed with kqueue */ -#endif - time_t last_modified; - time_t updated; +/**/ +#define NGX_HTTP_CACHE_STALE 1 +#define NGX_HTTP_CACHE_AGED 2 +#define NGX_HTTP_CACHE_THE_SAME 3 +/**/ - union { - off_t size; - ngx_str_t value; - } data; -} ngx_http_cache_entry_t; - - -typedef struct { - time_t expires; - time_t last_modified; - time_t date; - off_t length; - size_t key_len; - char key[1]; -} ngx_http_cache_header_t; - - -#define NGX_HTTP_CACHE_HASH 7 -#define NGX_HTTP_CACHE_NELTS 4 - -typedef struct { - ngx_http_cache_entry_t *elts; - size_t hash; - size_t nelts; - time_t life; - time_t update; -#if (NGX_THREADS) - ngx_mutex_t mutex; -#endif - ngx_pool_t *pool; -} ngx_http_cache_hash_t; +#define NGX_HTTP_CACHE_KEY_LEN 16 typedef struct { - ngx_http_cache_hash_t *hash; - ngx_http_cache_entry_t *cache; - ngx_file_t file; - ngx_array_t key; - uint32_t crc; - u_char md5[16]; - ngx_path_t *path; - ngx_buf_t *buf; - time_t expires; - time_t last_modified; - time_t date; - off_t length; - size_t key_len; - size_t file_start; - ngx_file_uniq_t uniq; - ngx_log_t *log; + ngx_uint_t status; + time_t valid; +} ngx_http_cache_valid_t; + + +/* ngx_http_file_cache_node_t takes exactly 64 bytes on FreeBSD/i386 */ + +typedef struct { + ngx_rbtree_node_t node; + ngx_queue_t queue; + + u_char key[NGX_HTTP_CACHE_KEY_LEN + - sizeof(ngx_rbtree_key_t)]; + + unsigned count:20; + unsigned uses:10; + unsigned valid_msec:10; + unsigned error:10; + /* 7 unused bits */ + unsigned exists:1; + + ngx_file_uniq_t uniq; + time_t expire; + time_t valid_sec; + size_t body_start; + off_t length; +} ngx_http_file_cache_node_t; + - /* STUB */ - ssize_t header_size; - ngx_str_t key0; -} ngx_http_cache_t; +struct ngx_http_cache_s { + ngx_file_t file; + ngx_array_t keys; + uint32_t crc32; + u_char key[NGX_HTTP_CACHE_KEY_LEN]; + + ngx_file_uniq_t uniq; + time_t valid_sec; + time_t last_modified; + time_t date; + + size_t header_start; + size_t body_start; + off_t length; + + ngx_uint_t min_uses; + ngx_uint_t uses; + ngx_uint_t error; + ngx_uint_t valid_msec; + + ngx_buf_t *buf; + + ngx_http_file_cache_t *file_cache; + ngx_http_file_cache_node_t *node; + + unsigned updated:1; + unsigned exists:1; + unsigned temp_file:1; +}; typedef struct { - ngx_path_t *path; - ngx_str_t key; - ngx_buf_t *buf; - - unsigned file:1; - unsigned memory:1; - unsigned primary:1; -} ngx_http_cache_ctx_t; - - -#define NGX_HTTP_CACHE_STALE 1 -#define NGX_HTTP_CACHE_AGED 2 -#define NGX_HTTP_CACHE_THE_SAME 3 - - -ngx_int_t ngx_http_cache_get(ngx_http_request_t *r, ngx_http_cache_ctx_t *ctx); - -ngx_int_t ngx_http_file_cache_get(ngx_http_request_t *r, - ngx_http_cache_ctx_t *ctx); - -ngx_int_t ngx_http_file_cache_open(ngx_http_cache_t *c); - -ngx_int_t ngx_http_cache_cleaner_handler(ngx_gc_t *gc, ngx_str_t *name, - ngx_dir_t *dir); + time_t valid_sec; + time_t last_modified; + time_t date; + uint32_t crc32; + u_short valid_msec; + u_short header_start; + u_short body_start; +} ngx_http_file_cache_header_t; -#if 0 +struct ngx_http_file_cache_s { + ngx_rbtree_t *rbtree; + ngx_queue_t *queue; + ngx_slab_pool_t *shpool; -ngx_http_cache_t *ngx_http_cache_get(ngx_http_cache_hash_t *cache, - ngx_http_cleanup_t *cleanup, - ngx_str_t *key, uint32_t *crc); + ngx_path_t *path; + + ngx_atomic_t *cold; + off_t *size; -ngx_http_cache_t *ngx_http_cache_alloc(ngx_http_cache_hash_t *hash, - ngx_http_cache_t *cache, - ngx_http_cleanup_t *cleanup, - ngx_str_t *key, uint32_t crc, - ngx_str_t *value, ngx_log_t *log); -void ngx_http_cache_free(ngx_http_cache_t *cache, - ngx_str_t *key, ngx_str_t *value, ngx_log_t *log); -void ngx_http_cache_lock(ngx_http_cache_hash_t *hash, ngx_http_cache_t *cache); -void ngx_http_cache_unlock(ngx_http_cache_hash_t *hash, - ngx_http_cache_t *cache, ngx_log_t *log); + off_t max_size; + size_t bsize; + + time_t inactive; -int ngx_http_cache_update_file(ngx_http_request_t *r,ngx_http_cache_ctx_t *ctx, - ngx_str_t *temp_file); + ngx_msec_t last; + ngx_uint_t files; -int ngx_http_send_cached(ngx_http_request_t *r); + ngx_shm_zone_t *shm_zone; +}; -char *ngx_http_set_cache_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +void ngx_http_file_cache_create_key(ngx_http_request_t *r); +ngx_int_t ngx_http_file_cache_open(ngx_http_request_t *r); +void ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf); +void ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf); +ngx_int_t ngx_http_cache_send(ngx_http_request_t *); +void ngx_http_file_cache_free(ngx_http_request_t *r, ngx_temp_file_t *tf); +time_t ngx_http_file_cache_valid(ngx_array_t *cache_valid, ngx_uint_t status); -#endif + +char *ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +char *ngx_http_file_cache_valid_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); #endif /* _NGX_HTTP_CACHE_H_INCLUDED_ */ 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 @@ -119,6 +119,11 @@ static ngx_conf_enum_t ngx_http_core_if }; +static ngx_path_init_t ngx_http_client_temp_path = { + ngx_string(NGX_HTTP_CLIENT_TEMP_PATH), { 0, 0, 0 } +}; + + #if (NGX_HTTP_GZIP) static ngx_conf_enum_t ngx_http_gzip_http_version[] = { @@ -347,7 +352,7 @@ static ngx_command_t ngx_http_core_comm ngx_conf_set_path_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_core_loc_conf_t, client_body_temp_path), - (void *) ngx_garbage_collector_temp_handler }, + NULL }, { ngx_string("client_body_in_file_only"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, @@ -542,7 +547,7 @@ static ngx_command_t ngx_http_core_comm NULL }, { ngx_string("try_files"), - NGX_HTTP_LOC_CONF|NGX_CONF_2MORE, + NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE, ngx_http_core_try_files, NGX_HTTP_LOC_CONF_OFFSET, 0, @@ -1037,7 +1042,7 @@ ngx_http_core_try_files_phase(ngx_http_r { size_t len, root, alias, reserve, allocated; u_char *p, *name; - ngx_str_t path; + ngx_str_t path, args; ngx_uint_t test_dir; ngx_http_try_file_t *tf; ngx_open_file_info_t of; @@ -1086,12 +1091,8 @@ ngx_http_core_try_files_phase(ngx_http_r len = tf->name.len; } - reserve = len - r->uri.len; - /* 16 bytes are preallocation */ - reserve = reserve < 16 ? 16 : reserve + 16; - - reserve += alias; + reserve = ngx_abs((ssize_t) (len - r->uri.len)) + alias + 16; if (reserve > allocated) { @@ -1126,7 +1127,7 @@ ngx_http_core_try_files_phase(ngx_http_r path.len = e.pos - path.data; - *e.pos++ = '\0'; + *e.pos = '\0'; if (alias && ngx_strncmp(name, clcf->name.data, alias) == 0) { ngx_memcpy(name, name + alias, len - alias); @@ -1138,8 +1139,8 @@ ngx_http_core_try_files_phase(ngx_http_r tf++; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "try to use file: \"%s\"", name); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "try to use file: \"%s\" \"%s\"", name, path.data); if (tf->lengths == NULL && tf->name.len == 0) { @@ -1150,7 +1151,9 @@ ngx_http_core_try_files_phase(ngx_http_r (void) ngx_http_named_location(r, &path); } else { - (void) ngx_http_internal_redirect(r, &path, NULL); + ngx_http_split_args(r, &path, &args); + + (void) ngx_http_internal_redirect(r, &path, &args); } return NGX_OK; @@ -1197,6 +1200,11 @@ ngx_http_core_try_files_phase(ngx_http_r ngx_memcpy(p, name, path.len); } + if (ngx_http_set_exten(r) != NGX_OK) { + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return NGX_OK; + } + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "try file uri: \"%V\"", &r->uri); @@ -1336,7 +1344,7 @@ ngx_http_core_find_location(ngx_http_req ngx_int_t rc; ngx_http_core_loc_conf_t *pclcf; #if (NGX_PCRE) - ngx_int_t n; + ngx_int_t n, len; ngx_uint_t noregex; ngx_http_core_loc_conf_t *clcf, **clcfp; @@ -1370,12 +1378,26 @@ ngx_http_core_find_location(ngx_http_req if (noregex == 0 && pclcf->regex_locations) { + len = 0; + for (clcfp = pclcf->regex_locations; *clcfp; clcfp++) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "test location: ~ \"%V\"", &(*clcfp)->name); - n = ngx_regex_exec((*clcfp)->regex, &r->uri, NULL, 0); + if ((*clcfp)->captures) { + + len = (NGX_HTTP_MAX_CAPTURES + 1) * 3; + + if (r->captures == NULL) { + r->captures = ngx_palloc(r->pool, len * sizeof(int)); + if (r->captures == NULL) { + return NGX_ERROR; + } + } + } + + n = ngx_regex_exec((*clcfp)->regex, &r->uri, r->captures, len); if (n == NGX_REGEX_NO_MATCHED) { continue; @@ -1393,6 +1415,9 @@ ngx_http_core_find_location(ngx_http_req r->loc_conf = (*clcfp)->loc_conf; + r->ncaptures = len; + r->captures_data = r->uri.data; + /* look up nested locations */ rc = ngx_http_core_find_location(r); @@ -1550,7 +1575,7 @@ ngx_http_set_content_type(ngx_http_reque exten = ngx_pnalloc(r->pool, r->exten.len); if (exten == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + return NGX_ERROR; } hash = ngx_hash_strlow(exten, r->exten.data, r->exten.len); @@ -1656,13 +1681,11 @@ ngx_http_map_uri_to_path(ngx_http_reques return NULL; } - reserved += r->uri.len - alias + 1; - if (clcf->root_lengths == NULL) { *root_length = clcf->root.len; - path->len = clcf->root.len + reserved; + path->len = clcf->root.len + reserved + r->uri.len - alias + 1; path->data = ngx_pnalloc(r->pool, path->len); if (path->data == NULL) { @@ -1672,6 +1695,16 @@ ngx_http_map_uri_to_path(ngx_http_reques last = ngx_copy(path->data, clcf->root.data, clcf->root.len); } else { + +#if (NGX_PCRE) + ngx_uint_t captures; + + captures = alias && clcf->captures; + reserved += captures ? 1 : r->uri.len - alias + 1; +#else + reserved += r->uri.len - alias + 1; +#endif + if (ngx_http_script_run(r, path, clcf->root_lengths->elts, reserved, clcf->root_values->elts) == NULL) @@ -1679,13 +1712,19 @@ ngx_http_map_uri_to_path(ngx_http_reques return NULL; } - if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, path, 0)== NGX_ERROR) - { + if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, path, 0) != NGX_OK) { return NULL; } *root_length = path->len - reserved; last = path->data + *root_length; + +#if (NGX_PCRE) + if (captures) { + *last = '\0'; + return last; + } +#endif } last = ngx_cpystrn(last, r->uri.data + alias, r->uri.len - alias + 1); @@ -1769,34 +1808,60 @@ ngx_http_auth_basic_user(ngx_http_reques ngx_int_t ngx_http_server_addr(ngx_http_request_t *r, ngx_str_t *s) { - socklen_t len; - ngx_connection_t *c; - struct sockaddr_in sin; - - /* AF_INET only */ + socklen_t len; + ngx_uint_t addr; + ngx_connection_t *c; + u_char sa[NGX_SOCKADDRLEN]; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + ngx_uint_t i; + struct sockaddr_in6 *sin6; +#endif c = r->connection; - if (r->in_addr == 0) { - len = sizeof(struct sockaddr_in); - if (getsockname(c->fd, (struct sockaddr *) &sin, &len) == -1) { + switch (c->local_sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) c->local_sockaddr; + + for (addr = 0, i = 0; addr == 0 && i < 16; i++) { + addr |= sin6->sin6_addr.s6_addr[i]; + } + + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) c->local_sockaddr; + addr = sin->sin_addr.s_addr; + break; + } + + if (addr == 0) { + + len = NGX_SOCKADDRLEN; + + if (getsockname(c->fd, (struct sockaddr *) &sa, &len) == -1) { ngx_connection_error(c, ngx_socket_errno, "getsockname() failed"); return NGX_ERROR; } - r->in_addr = sin.sin_addr.s_addr; - - } else { - sin.sin_family = c->sockaddr->sa_family; - sin.sin_addr.s_addr = r->in_addr; + c->local_sockaddr = ngx_palloc(r->connection->pool, len); + if (c->local_sockaddr == NULL) { + return NGX_ERROR; + } + + c->local_socklen = len; + ngx_memcpy(c->local_sockaddr, &sa, len); } if (s == NULL) { return NGX_OK; } - s->len = ngx_sock_ntop((struct sockaddr *) &sin, s->data, - NGX_INET_ADDRSTRLEN); + s->len = ngx_sock_ntop(c->local_sockaddr, s->data, s->len, 0); return NGX_OK; } @@ -2000,7 +2065,7 @@ ngx_http_subrequest(ngx_http_request_t * if (ngx_list_init(&sr->headers_out.headers, r->pool, 20, sizeof(ngx_table_elt_t)) - == NGX_ERROR) + != NGX_OK) { return NGX_ERROR; } @@ -2055,10 +2120,6 @@ ngx_http_subrequest(ngx_http_request_t * c->data = sr; } - sr->in_addr = r->in_addr; - sr->port = r->port; - sr->port_text = r->port_text; - sr->variables = r->variables; sr->log_handler = r->log_handler; @@ -2139,6 +2200,10 @@ ngx_http_internal_redirect(ngx_http_requ ngx_http_update_location_config(r); +#if (NGX_HTTP_CACHE) + r->cache = NULL; +#endif + r->internal = 1; ngx_http_handler(r); @@ -2537,6 +2602,7 @@ ngx_http_core_regex_location(ngx_conf_t } clcf->name = *regex; + clcf->captures = (ngx_regex_capture_count(clcf->regex) > 0); return NGX_OK; @@ -2592,7 +2658,7 @@ ngx_http_core_type(ngx_conf_t *cf, ngx_c if (ngx_strcmp(value[0].data, "include") == 0) { file = value[1]; - if (ngx_conf_full_name(cf->cycle, &file, 1) == NGX_ERROR){ + if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK) { return NGX_CONF_ERROR; } @@ -2724,15 +2790,16 @@ ngx_http_core_create_srv_conf(ngx_conf_t * conf->client_large_buffers.num = 0; */ - if (ngx_array_init(&cscf->listen, cf->pool, 4, sizeof(ngx_http_listen_t)) - == NGX_ERROR) + if (ngx_array_init(&cscf->listen, cf->temp_pool, 4, + sizeof(ngx_http_listen_t)) + != NGX_OK) { return NGX_CONF_ERROR; } if (ngx_array_init(&cscf->server_names, cf->temp_pool, 4, sizeof(ngx_http_server_name_t)) - == NGX_ERROR) + != NGX_OK) { return NGX_CONF_ERROR; } @@ -2756,6 +2823,7 @@ ngx_http_core_merge_srv_conf(ngx_conf_t ngx_http_core_srv_conf_t *conf = child; ngx_http_listen_t *ls; + struct sockaddr_in *sin; ngx_http_server_name_t *sn; /* TODO: it does not merge, it inits only */ @@ -2768,18 +2836,25 @@ ngx_http_core_merge_srv_conf(ngx_conf_t ngx_memzero(ls, sizeof(ngx_http_listen_t)); - ls->addr = INADDR_ANY; + sin = (struct sockaddr_in *) &ls->sockaddr; + + sin->sin_family = AF_INET; #if (NGX_WIN32) - ls->port = 80; + sin->sin_port = htons(80); #else - /* STUB: getuid() should be cached */ - ls->port = (getuid() == 0) ? 80 : 8000; + sin->sin_port = htons((getuid() == 0) ? 80 : 8000); #endif - ls->family = AF_INET; + sin->sin_addr.s_addr = INADDR_ANY; + + ls->socklen = sizeof(struct sockaddr_in); ls->conf.backlog = NGX_LISTEN_BACKLOG; ls->conf.rcvbuf = -1; ls->conf.sndbuf = -1; + ls->conf.wildcard = 1; + + (void) ngx_sock_ntop((struct sockaddr *) &ls->sockaddr, ls->conf.addr, + NGX_SOCKADDR_STRLEN, 1); } if (conf->server_name.data == NULL) { @@ -2792,6 +2867,7 @@ ngx_http_core_merge_srv_conf(ngx_conf_t #if (NGX_PCRE) sn->regex = NULL; + sn->captures = 0; #endif sn->core_srv_conf = conf; sn->name.len = conf->server_name.len; @@ -2943,7 +3019,7 @@ ngx_http_core_merge_loc_conf(ngx_conf_t conf->root.len = sizeof("html") - 1; conf->root.data = (u_char *) "html"; - if (ngx_conf_full_name(cf->cycle, &conf->root, 0) == NGX_ERROR) { + if (ngx_conf_full_name(cf->cycle, &conf->root, 0) != NGX_OK) { return NGX_CONF_ERROR; } } @@ -3099,10 +3175,13 @@ ngx_http_core_merge_loc_conf(ngx_conf_t conf->resolver = prev->resolver; } - ngx_conf_merge_path_value(conf->client_body_temp_path, + if (ngx_conf_merge_path_value(cf, &conf->client_body_temp_path, prev->client_body_temp_path, - NGX_HTTP_CLIENT_TEMP_PATH, 0, 0, 0, - ngx_garbage_collector_temp_handler, cf); + &ngx_http_client_temp_path) + != NGX_OK) + { + return NGX_CONF_ERROR; + } ngx_conf_merge_value(conf->reset_timedout_connection, prev->reset_timedout_connection, 0); @@ -3154,8 +3233,6 @@ ngx_http_core_merge_loc_conf(ngx_conf_t } -/* AF_INET only */ - static char * ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { @@ -3196,17 +3273,18 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx ngx_memzero(ls, sizeof(ngx_http_listen_t)); - ls->family = u.family; - ls->addr = u.addr.in_addr; - ls->port = u.port; + ngx_memcpy(ls->sockaddr, u.sockaddr, u.socklen); + + ls->socklen = u.socklen; ls->file_name = cf->conf_file->file.name.data; ls->line = cf->conf_file->line; ls->conf.backlog = NGX_LISTEN_BACKLOG; ls->conf.rcvbuf = -1; ls->conf.sndbuf = -1; - - n = ngx_inet_ntop(AF_INET, &ls->addr, ls->conf.addr, NGX_INET_ADDRSTRLEN); - ngx_sprintf(&ls->conf.addr[n], ":%ui", ls->port); + ls->conf.wildcard = u.wildcard; + + (void) ngx_sock_ntop((struct sockaddr *) &ls->sockaddr, ls->conf.addr, + NGX_SOCKADDR_STRLEN, 1); if (cf->args->nelts == 2) { return NGX_CONF_OK; @@ -3305,6 +3383,45 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx continue; } + if (ngx_strncmp(value[n].data, "ipv6only=o", 10) == 0) { +#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) + struct sockaddr *sa; + + sa = (struct sockaddr *) ls->sockaddr; + + if (sa->sa_family == AF_INET6) { + + if (ngx_strcmp(&value[n].data[10], "n") == 0) { + ls->conf.ipv6only = 1; + + } else if (ngx_strcmp(&value[n].data[10], "ff") == 0) { + ls->conf.ipv6only = 2; + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid ipv6only flags \"%s\"", + &value[n].data[9]); + return NGX_CONF_ERROR; + } + + ls->conf.bind = 1; + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "ipv6only is not supported " + "on addr \"%s\", ignored", + ls->conf.addr); + } + + continue; +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "bind ipv6only is not supported " + "on this platform"); + return NGX_CONF_ERROR; +#endif + } + if (ngx_strcmp(value[n].data, "ssl") == 0) { #if (NGX_HTTP_SSL) ls->conf.ssl = 1; @@ -3394,6 +3511,7 @@ ngx_http_core_server_name(ngx_conf_t *cf #if (NGX_PCRE) sn->regex = NULL; + sn->captures = 0; #endif sn->core_srv_conf = cscf; sn->name = value[i]; @@ -3420,6 +3538,7 @@ ngx_http_core_server_name(ngx_conf_t *cf return NGX_CONF_ERROR; } + sn->captures = (ngx_regex_capture_count(sn->regex) > 0); sn->name = value[i]; } #else @@ -3472,18 +3591,6 @@ ngx_http_core_root(ngx_conf_t *cf, ngx_c return NGX_CONF_ERROR; } -#if (NGX_PCRE) - - if (lcf->regex && alias) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "the \"alias\" directive may not be used " - "inside location given by regular expression"); - - return NGX_CONF_ERROR; - } - -#endif - value = cf->args->elts; if (ngx_strstr(value[1].data, "$document_root") @@ -3516,31 +3623,43 @@ ngx_http_core_root(ngx_conf_t *cf, ngx_c } if (lcf->root.data[0] != '$') { - if (ngx_conf_full_name(cf->cycle, &lcf->root, 0) == NGX_ERROR) { + if (ngx_conf_full_name(cf->cycle, &lcf->root, 0) != NGX_OK) { return NGX_CONF_ERROR; } } n = ngx_http_script_variables_count(&lcf->root); - if (n == 0) { - return NGX_CONF_OK; + ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); + + if (n) { + sc.cf = cf; + sc.source = &lcf->root; + sc.lengths = &lcf->root_lengths; + sc.values = &lcf->root_values; + sc.variables = n; + sc.complete_lengths = 1; + sc.complete_values = 1; + + if (ngx_http_script_compile(&sc) != NGX_OK) { + return NGX_CONF_ERROR; + } } - ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); - - sc.cf = cf; - sc.source = &lcf->root; - sc.lengths = &lcf->root_lengths; - sc.values = &lcf->root_values; - sc.variables = n; - sc.complete_lengths = 1; - sc.complete_values = 1; - - if (ngx_http_script_compile(&sc) != NGX_OK) { +#if (NGX_PCRE) + + if (alias && lcf->regex + && (ngx_regex_capture_count(lcf->regex) <= 0 || sc.ncaptures == 0)) + { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the \"alias\" directive must use captures " + "inside location given by regular expression"); + return NGX_CONF_ERROR; } +#endif + return NGX_CONF_OK; } @@ -3694,13 +3813,13 @@ ngx_http_core_error_page(ngx_conf_t *cf, { ngx_http_core_loc_conf_t *lcf = conf; - u_char *args; - ngx_int_t overwrite; - ngx_str_t *value, uri; - ngx_uint_t i, n, nvar; - ngx_array_t *uri_lengths, *uri_values; - ngx_http_err_page_t *err; - ngx_http_script_compile_t sc; + u_char *p; + ngx_int_t overwrite; + ngx_str_t *value, uri, args; + ngx_uint_t i, n; + ngx_http_err_page_t *err; + ngx_http_complex_value_t cv; + ngx_http_compile_complex_value_t ccv; if (lcf->error_pages == NULL) { lcf->error_pages = ngx_array_create(cf->pool, 4, @@ -3742,29 +3861,32 @@ ngx_http_core_error_page(ngx_conf_t *cf, } uri = value[cf->args->nelts - 1]; - uri_lengths = NULL; - uri_values = NULL; - - nvar = ngx_http_script_variables_count(&uri); - - if (nvar) { - ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); - - sc.cf = cf; - sc.source = &uri; - sc.lengths = &uri_lengths; - sc.values = &uri_values; - sc.variables = nvar; - sc.complete_lengths = 1; - sc.complete_values = 1; - - if (ngx_http_script_compile(&sc) != NGX_OK) { - return NGX_CONF_ERROR; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &uri; + ccv.complex_value = &cv; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + args.len = 0; + args.data = NULL; + + if (cv.lengths == NULL) { + p = (u_char *) ngx_strchr(uri.data, '?'); + + if (p) { + cv.value.len = p - uri.data; + cv.value.data = uri.data; + p++; + args.len = (uri.data + uri.len) - p; + args.data = p; } } - args = (u_char *) ngx_strchr(uri.data, '?'); - for (i = 1; i < cf->args->nelts - n; i++) { err = ngx_array_push(lcf->error_pages); if (err == NULL) { @@ -3803,21 +3925,8 @@ ngx_http_core_error_page(ngx_conf_t *cf, } } - if (args) { - err->uri.len = args - uri.data; - err->uri.data = uri.data; - args++; - err->args.len = (uri.data + uri.len) - args; - err->args.data = args; - - } else { - err->uri = uri; - err->args.len = 0; - err->args.data = NULL; - } - - err->uri_lengths = uri_lengths; - err->uri_values = uri_values; + err->value = cv; + err->args = args; } return NGX_CONF_OK; @@ -3859,6 +3968,7 @@ ngx_http_core_try_files(ngx_conf_t *cf, if (tf[i].name.data[tf[i].name.len - 1] == '/') { tf[i].test_dir = 1; tf[i].name.len--; + tf[i].name.data[tf[i].name.len] = '\0'; } n = ngx_http_script_variables_count(&tf[i].name); 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 @@ -40,9 +40,13 @@ typedef struct ngx_http_core_loc_conf_s typedef struct { unsigned default_server:1; unsigned bind:1; + unsigned wildcard:1; #if (NGX_HTTP_SSL) unsigned ssl:1; #endif +#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) + unsigned ipv6only:2; +#endif int backlog; int rcvbuf; @@ -55,15 +59,13 @@ typedef struct { ngx_uint_t deferred_accept; #endif - u_char addr[NGX_INET_ADDRSTRLEN + sizeof(":65535")]; - + u_char addr[NGX_SOCKADDR_STRLEN + 1]; } ngx_http_listen_conf_t; typedef struct { - in_addr_t addr; - in_port_t port; - int family; + u_char sockaddr[NGX_SOCKADDRLEN]; + socklen_t socklen; u_char *file_name; ngx_uint_t line; @@ -151,6 +153,8 @@ typedef struct { /* server ctx */ ngx_http_conf_ctx_t *ctx; + ngx_http_virtual_names_t *virtual_names; + ngx_str_t server_name; size_t connection_pool_size; @@ -173,35 +177,48 @@ typedef struct { typedef struct { - in_addr_t addr; - /* the default server configuration for this address:port */ ngx_http_core_srv_conf_t *core_srv_conf; - ngx_http_virtual_names_t *virtual_names; - #if (NGX_HTTP_SSL) ngx_uint_t ssl; /* unsigned ssl:1; */ #endif -} ngx_http_in_addr_t; - - -typedef struct { - in_port_t port; - ngx_str_t port_text; - ngx_http_in_addr_t *addrs; - ngx_uint_t naddrs; -} ngx_http_in_port_t; - - -typedef struct { - in_port_t port; - ngx_array_t addrs; /* array of ngx_http_conf_in_addr_t */ -} ngx_http_conf_in_port_t; +} ngx_http_addr_conf_t; typedef struct { in_addr_t addr; + ngx_http_addr_conf_t conf; +} ngx_http_in_addr_t; + + +#if (NGX_HAVE_INET6) + +typedef struct { + struct in6_addr addr6; + ngx_http_addr_conf_t conf; +} ngx_http_in6_addr_t; + +#endif + + +typedef struct { + /* ngx_http_in_addr_t or ngx_http_in6_addr_t */ + void *addrs; + ngx_uint_t naddrs; +} ngx_http_port_t; + + +typedef struct { + ngx_int_t family; + in_port_t port; + ngx_array_t addrs; /* array of ngx_http_conf_addr_t */ +} ngx_http_conf_port_t; + + +typedef struct { + struct sockaddr *sockaddr; + socklen_t socklen; ngx_hash_t hash; ngx_hash_wildcard_t *wc_head; @@ -219,17 +236,19 @@ typedef struct { unsigned default_server:1; unsigned bind:1; + unsigned wildcard:1; #if (NGX_HTTP_SSL) unsigned ssl:1; #endif ngx_http_listen_conf_t *listen_conf; -} ngx_http_conf_in_addr_t; +} ngx_http_conf_addr_t; struct ngx_http_server_name_s { #if (NGX_PCRE) ngx_regex_t *regex; + ngx_uint_t captures; /* unsigned captures:1; */ #endif ngx_http_core_srv_conf_t *core_srv_conf; /* virtual name server conf */ ngx_str_t name; @@ -239,10 +258,8 @@ struct ngx_http_server_name_s { typedef struct { ngx_int_t status; ngx_int_t overwrite; - ngx_str_t uri; + ngx_http_complex_value_t value; ngx_str_t args; - ngx_array_t *uri_lengths; - ngx_array_t *uri_values; } ngx_http_err_page_t; @@ -259,6 +276,8 @@ struct ngx_http_core_loc_conf_s { #if (NGX_PCRE) ngx_regex_t *regex; + + unsigned captures:1; #endif unsigned noname:1; /* "if () {}" block or limit_except */ @@ -274,7 +293,9 @@ struct ngx_http_core_loc_conf_s { #endif ngx_http_location_tree_node_t *static_locations; +#if (NGX_PCRE) ngx_http_core_loc_conf_t **regex_locations; +#endif /* pointer to the modules' loc_conf */ void **loc_conf; 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 @@ -7,253 +7,1568 @@ #include #include #include - - -#if (NGX_HAVE_OPENSSL_MD5_H) -#include -#else -#include -#endif - -#if (NGX_OPENSSL_MD5) -#define MD5Init MD5_Init -#define MD5Update MD5_Update -#define MD5Final MD5_Final -#endif +#include -ngx_int_t ngx_http_file_cache_get(ngx_http_request_t *r, - ngx_http_cache_ctx_t *ctx) -{ - ngx_uint_t i; - ngx_str_t *key; - ngx_http_cache_t *c; - MD5_CTX md5; - - c = r->cache; - - c->file.name.len = ctx->path->name.len + 1 + ctx->path->len + 32; - if (!(c->file.name.data = ngx_palloc(r->pool, c->file.name.len + 1))) { - return NGX_ABORT; - } - - MD5Init(&md5); - - key = c->key.elts; - for (i = 0; i < c->key.nelts; i++) { - MD5Update(&md5, key[i].data, key[i].len); - } - - MD5Update(&md5, ctx->key.data, ctx->key.len); - - MD5Final(c->md5, &md5); - - ngx_memcpy(c->file.name.data, ctx->path->name.data, ctx->path->name.len); - - ngx_md5_text(c->file.name.data + ctx->path->name.len + 1 + ctx->path->len, - c->md5); - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "file cache key: %V, md5: %s", &ctx->key, - c->file.name.data + ctx->path->name.len + 1 + ctx->path->len); - - ngx_create_hashed_filename(&c->file, ctx->path); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "file cache name: %s", c->file.name.data); - - return ngx_http_file_cache_open(r->cache); -} +static ngx_int_t ngx_http_file_cache_exists(ngx_http_file_cache_t *cache, + ngx_http_cache_t *c); +static ngx_http_file_cache_node_t * + ngx_http_file_cache_lookup(ngx_http_file_cache_t *cache, u_char *key); +static void ngx_http_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp, + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); +static void ngx_http_file_cache_cleanup(void *data); +static time_t ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache); +static time_t ngx_http_file_cache_expire(ngx_http_file_cache_t *cache); +static void ngx_http_file_cache_delete(ngx_http_file_cache_t *cache, + ngx_queue_t *q, u_char *name); +static ngx_int_t + ngx_http_file_cache_manager_sleep(ngx_http_file_cache_t *cache); +static ngx_int_t ngx_http_file_cache_noop(ngx_tree_ctx_t *ctx, + ngx_str_t *path); +static ngx_int_t ngx_http_file_cache_manage_file(ngx_tree_ctx_t *ctx, + ngx_str_t *path); +static ngx_int_t ngx_http_file_cache_add_file(ngx_tree_ctx_t *ctx, + ngx_str_t *path); +static ngx_int_t ngx_http_file_cache_add(ngx_http_file_cache_t *cache, + ngx_http_cache_t *c); +static ngx_int_t ngx_http_file_cache_delete_file(ngx_tree_ctx_t *ctx, + ngx_str_t *path); -ngx_int_t ngx_http_file_cache_open(ngx_http_cache_t *c) -{ - ssize_t n; - ngx_err_t err; - ngx_http_cache_header_t *h; +static u_char ngx_http_file_cache_key[] = { LF, 'K', 'E', 'Y', ':', ' ' }; + - c->file.fd = ngx_open_file(c->file.name.data, - NGX_FILE_RDONLY, NGX_FILE_OPEN); - - if (c->file.fd == NGX_INVALID_FILE) { - err = ngx_errno; +static ngx_int_t +ngx_http_file_cache_init(ngx_shm_zone_t *shm_zone, void *data) +{ + ngx_http_file_cache_t *ocache = data; - if (err == NGX_ENOENT || err == NGX_ENOTDIR) { - return NGX_DECLINED; - } + size_t len; + ngx_rbtree_node_t *sentinel; + ngx_http_file_cache_t *cache; + + cache = shm_zone->data; - ngx_log_error(NGX_LOG_CRIT, c->log, ngx_errno, - ngx_open_file_n " \"%s\" failed", c->file.name.data); - return NGX_ERROR; - } - - if (c->uniq) { - if (ngx_fd_info(c->file.fd, &c->file.info) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_CRIT, c->log, ngx_errno, - ngx_fd_info_n " \"%s\" failed", c->file.name.data); + if (ocache) { + if (ngx_strcmp(cache->path->name.data, ocache->path->name.data) != 0) { + ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0, + "cache \"%V\" uses the \"%V\" cache path " + "while previously it used the \"%V\" cache path", + &shm_zone->name, &cache->path->name, + &ocache->path->name); return NGX_ERROR; } - if (ngx_file_uniq(&c->file.info) == c->uniq) { - if (ngx_close_file(c->file.fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, - ngx_close_file_n " \"%s\" failed", - c->file.name.data); + cache->rbtree = ocache->rbtree; + cache->queue = ocache->queue; + cache->shpool = ocache->shpool; + cache->cold = ocache->cold; + cache->size = ocache->size; + cache->bsize = ocache->bsize; + + cache->max_size /= cache->bsize; + + return NGX_OK; + } + + cache->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; + + cache->rbtree = ngx_slab_alloc(cache->shpool, sizeof(ngx_rbtree_t)); + if (cache->rbtree == NULL) { + return NGX_ERROR; + } + + sentinel = ngx_slab_alloc(cache->shpool, sizeof(ngx_rbtree_node_t)); + if (sentinel == NULL) { + return NGX_ERROR; + } + + ngx_rbtree_init(cache->rbtree, sentinel, + ngx_http_file_cache_rbtree_insert_value); + + cache->queue = ngx_slab_alloc(cache->shpool, sizeof(ngx_queue_t)); + if (cache->queue == NULL) { + return NGX_ERROR; + } + + ngx_queue_init(cache->queue); + + cache->cold = ngx_slab_alloc(cache->shpool, sizeof(ngx_atomic_t)); + if (cache->cold == NULL) { + return NGX_ERROR; + } + + *cache->cold = 1; + + cache->size = ngx_slab_alloc(cache->shpool, sizeof(off_t)); + if (cache->size == NULL) { + return NGX_ERROR; + } + + *cache->size = 0; + + cache->bsize = ngx_fs_bsize(cache->path->name.data); + + cache->max_size /= cache->bsize; + + len = sizeof(" in cache keys zone \"\"") + shm_zone->name.len; + + cache->shpool->log_ctx = ngx_slab_alloc(cache->shpool, len); + if (cache->shpool->log_ctx == NULL) { + return NGX_ERROR; + } + + ngx_sprintf(cache->shpool->log_ctx, " in cache keys zone \"%V\"%Z", + &shm_zone->name); + + return NGX_OK; +} + + +void +ngx_http_file_cache_create_key(ngx_http_request_t *r) +{ + size_t len; + ngx_str_t *key; + ngx_uint_t i; + ngx_md5_t md5; + ngx_http_cache_t *c; + + c = r->cache; + + len = 0; + + ngx_crc32_init(c->crc32); + ngx_md5_init(&md5); + + key = c->keys.elts; + for (i = 0; i < c->keys.nelts; i++) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http cache key: \"%V\"", &key[i]); + + len += key[i].len; + + ngx_crc32_update(&c->crc32, key[i].data, key[i].len); + ngx_md5_update(&md5, key[i].data, key[i].len); + } + + c->header_start = sizeof(ngx_http_file_cache_header_t) + + sizeof(ngx_http_file_cache_key) + len + 1; + + ngx_crc32_final(c->crc32); + ngx_md5_final(c->key, &md5); +} + + +ngx_int_t +ngx_http_file_cache_open(ngx_http_request_t *r) +{ + u_char *p; + time_t now; + ssize_t n; + ngx_int_t rc, rv; + ngx_uint_t cold, test; + ngx_path_t *path; + ngx_http_cache_t *c; + ngx_pool_cleanup_t *cln; + ngx_open_file_info_t of; + ngx_http_file_cache_t *cache; + ngx_http_core_loc_conf_t *clcf; + ngx_http_file_cache_header_t *h; + + c = r->cache; + cache = c->file_cache; + + cln = ngx_pool_cleanup_add(r->pool, 0); + if (cln == NULL) { + return NGX_ERROR; + } + + rc = ngx_http_file_cache_exists(cache, c); + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http file cache exists: %i u:%ui e:%d", + rc, c->uses, c->exists); + + if (rc == NGX_ERROR) { + return rc; + } + + cln->handler = ngx_http_file_cache_cleanup; + cln->data = c; + + if (rc == NGX_AGAIN) { + return rc; + } + + cold = *cache->cold; + + if (rc == NGX_OK) { + + if (c->error) { + return c->error; + } + + c->temp_file = 1; + test = c->exists ? 1 : 0; + rv = NGX_DECLINED; + + } else { /* rc == NGX_DECLINED */ + + if (c->min_uses > 1) { + + if (!cold) { + return NGX_AGAIN; } - return NGX_HTTP_CACHE_THE_SAME; + test = 1; + rv = NGX_AGAIN; + + } else { + c->temp_file = 1; + test = cold ? 1 : 0; + rv = NGX_DECLINED; } } - n = ngx_read_file(&c->file, c->buf->pos, c->buf->end - c->buf->last, 0); + path = cache->path; + + c->file.name.len = path->name.len + 1 + path->len + + 2 * NGX_HTTP_CACHE_KEY_LEN; + + c->file.name.data = ngx_pnalloc(r->pool, c->file.name.len + 1); + if (c->file.name.data == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(c->file.name.data, path->name.data, path->name.len); + + p = c->file.name.data + path->name.len + 1 + path->len; + p = ngx_hex_dump(p, c->key, NGX_HTTP_CACHE_KEY_LEN); + *p = '\0'; + + ngx_create_hashed_filename(path, c->file.name.data, c->file.name.len); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "cache file: \"%s\"", c->file.name.data); + + if (!test) { + return NGX_DECLINED; + } + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + ngx_memzero(&of, sizeof(ngx_open_file_info_t)); - if (n == NGX_ERROR || n == NGX_AGAIN) { + of.uniq = c->uniq; + of.valid = clcf->open_file_cache_valid; + of.min_uses = clcf->open_file_cache_min_uses; + of.events = clcf->open_file_cache_events; + of.directio = NGX_OPEN_FILE_DIRECTIO_OFF; + + if (ngx_open_cached_file(clcf->open_file_cache, &c->file.name, &of, r->pool) + != NGX_OK) + { + switch (of.err) { + + case 0: + return NGX_ERROR; + + case NGX_ENOENT: + case NGX_ENOTDIR: + return rv; + + default: + ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, + ngx_open_file_n " \"%s\" failed", c->file.name.data); + return NGX_ERROR; + } + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http file cache fd: %d", of.fd); + + c->file.fd = of.fd; + c->file.log = r->connection->log; + + c->buf = ngx_create_temp_buf(r->pool, c->body_start); + if (c->buf == NULL) { + return NGX_ERROR; + } + + n = ngx_read_file(&c->file, c->buf->pos, c->body_start, 0); + + if (n == NGX_ERROR) { return n; } - if (n <= c->header_size) { - ngx_log_error(NGX_LOG_CRIT, c->log, 0, + if ((size_t) n <= c->header_start) { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, "cache file \"%s\" is too small", c->file.name.data); return NGX_ERROR; } - h = (ngx_http_cache_header_t *) c->buf->pos; - c->expires = h->expires; - c->last_modified= h->last_modified; - c->date = h->date; - c->length = h->length; + h = (ngx_http_file_cache_header_t *) c->buf->pos; - if (h->key_len > (size_t) (c->buf->end - c->buf->pos)) { - ngx_log_error(NGX_LOG_ALERT, c->log, 0, - "cache file \"%s\" is probably invalid", - c->file.name.data); + if (h->crc32 != c->crc32 || (size_t) h->header_start != c->header_start) { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, + "cache file \"%s\" has md5 collision", c->file.name.data); return NGX_DECLINED; } -#if 0 + c->buf->last += n; - /* TODO */ + c->valid_sec = h->valid_sec; + c->last_modified = h->last_modified; + c->date = h->date; + c->valid_msec = h->valid_msec; + c->length = of.size; + c->body_start = h->body_start; - if (c->key_len && h->key_len != c->key_len) { + r->cached = 1; - ngx_strncmp(h->key, c->key_data, h->key_len) != 0)) + if (cold) { + + ngx_shmtx_lock(&cache->shpool->mutex); - h->key[h->key_len] = '\0'; - ngx_log_error(NGX_LOG_ALERT, c->log, 0, - "md5 collision: \"%s\" and \"%s\"", - h->key, c->key.data); - return NGX_DECLINED; + if (!c->node->exists) { + c->node->uses = 1; + c->node->body_start = c->body_start; + c->node->exists = 1; + + *cache->size += (c->length + cache->bsize - 1) / cache->bsize; + } + + ngx_shmtx_unlock(&cache->shpool->mutex); } -#endif + now = ngx_time(); - c->buf->last += n; + if (c->valid_sec < now) { - if (c->expires < ngx_time()) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http file cache expired"); + c->uses = c->min_uses; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http file cache expired: %T %T", c->valid_sec, now); + return NGX_HTTP_CACHE_STALE; } /* TODO: NGX_HTTP_CACHE_AGED */ - /* STUB */ return NGX_DECLINED; + return NGX_OK; +} + + +static ngx_int_t +ngx_http_file_cache_exists(ngx_http_file_cache_t *cache, ngx_http_cache_t *c) +{ + ngx_int_t rc; + ngx_http_file_cache_node_t *fcn; + + ngx_shmtx_lock(&cache->shpool->mutex); + + fcn = ngx_http_file_cache_lookup(cache, c->key); + + if (fcn) { + ngx_queue_remove(&fcn->queue); + + if (fcn->error) { + + if (fcn->valid_sec < ngx_time()) { + goto renew; + } + + rc = NGX_OK; + + goto done; + } + + fcn->uses++; + fcn->count++; + + if (fcn->exists) { + + c->exists = fcn->exists; + c->body_start = fcn->body_start; + + rc = NGX_OK; + + goto done; + } + + if (fcn->uses >= c->min_uses) { + + c->exists = fcn->exists; + c->body_start = fcn->body_start; + + rc = NGX_OK; + + } else { + rc = NGX_AGAIN; + } + + goto done; + } + + fcn = ngx_slab_alloc_locked(cache->shpool, + sizeof(ngx_http_file_cache_node_t)); + if (fcn == NULL) { + ngx_shmtx_unlock(&cache->shpool->mutex); + + ngx_http_file_cache_forced_expire(cache); + + ngx_shmtx_lock(&cache->shpool->mutex); + + fcn = ngx_slab_alloc_locked(cache->shpool, + sizeof(ngx_http_file_cache_node_t)); + if (fcn == NULL) { + rc = NGX_ERROR; + goto failed; + } + } + + ngx_memcpy((u_char *) &fcn->node.key, c->key, sizeof(ngx_rbtree_key_t)); + + ngx_memcpy(fcn->key, &c->key[sizeof(ngx_rbtree_key_t)], + NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t)); + + ngx_rbtree_insert(cache->rbtree, &fcn->node); + +renew: + + rc = NGX_DECLINED; + + fcn->uses = 1; + fcn->count = 1; + fcn->valid_msec = 0; + fcn->error = 0; + fcn->exists = 0; + fcn->valid_sec = 0; + fcn->uniq = 0; + fcn->body_start = 0; + fcn->length = 0; + +done: + + fcn->expire = ngx_time() + cache->inactive; + + ngx_queue_insert_head(cache->queue, &fcn->queue); + + c->uniq = fcn->uniq; + c->uses = fcn->uses; + c->error = fcn->error; + c->node = fcn; + +failed: + + ngx_shmtx_unlock(&cache->shpool->mutex); + + return rc; +} + + +static ngx_http_file_cache_node_t * +ngx_http_file_cache_lookup(ngx_http_file_cache_t *cache, u_char *key) +{ + ngx_int_t rc; + ngx_rbtree_key_t node_key; + ngx_rbtree_node_t *node, *sentinel; + ngx_http_file_cache_node_t *fcn; + + ngx_memcpy((u_char *) &node_key, key, sizeof(ngx_rbtree_key_t)); + + node = cache->rbtree->root; + sentinel = cache->rbtree->sentinel; + + while (node != sentinel) { + + if (node_key < node->key) { + node = node->left; + continue; + } + + if (node_key > node->key) { + node = node->right; + continue; + } + + /* node_key == node->key */ + + do { + fcn = (ngx_http_file_cache_node_t *) node; + + rc = ngx_memcmp(&key[sizeof(ngx_rbtree_key_t)], fcn->key, + NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t)); + + if (rc == 0) { + return fcn; + } + + node = (rc < 0) ? node->left : node->right; + + } while (node != sentinel && node_key == node->key); + + break; + } + + /* not found */ + + return NULL; +} + + +static void +ngx_http_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp, + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) +{ + ngx_rbtree_node_t **p; + ngx_http_file_cache_node_t *cn, *cnt; + + for ( ;; ) { + + if (node->key < temp->key) { + + p = &temp->left; + + } else if (node->key > temp->key) { + + p = &temp->right; + + } else { /* node->key == temp->key */ + + cn = (ngx_http_file_cache_node_t *) node; + cnt = (ngx_http_file_cache_node_t *) temp; + + p = (ngx_memcmp(cn->key, cnt->key, + NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t)) + < 0) + ? &temp->left : &temp->right; + } + + if (*p == sentinel) { + break; + } + + temp = *p; + } + + *p = node; + node->parent = temp; + node->left = sentinel; + node->right = sentinel; + ngx_rbt_red(node); +} + + +void +ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf) +{ + ngx_http_file_cache_header_t *h = (ngx_http_file_cache_header_t *) buf; + + u_char *p; + ngx_str_t *key; + ngx_uint_t i; + ngx_http_cache_t *c; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http file cache set header"); + + c = r->cache; + + h->valid_sec = c->valid_sec; + h->last_modified = c->last_modified; + h->date = c->date; + h->crc32 = c->crc32; + h->valid_msec = (u_short) c->valid_msec; + h->header_start = (u_short) c->header_start; + h->body_start = (u_short) c->body_start; + + p = buf + sizeof(ngx_http_file_cache_header_t); + + p = ngx_cpymem(p, ngx_http_file_cache_key, sizeof(ngx_http_file_cache_key)); + + key = c->keys.elts; + for (i = 0; i < c->keys.nelts; i++) { + p = ngx_copy(p, key[i].data, key[i].len); + } + + *p = LF; +} + + +void +ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf) +{ + off_t size; + ngx_int_t rc; + ngx_file_uniq_t uniq; + ngx_file_info_t fi; + ngx_http_cache_t *c; + ngx_ext_rename_file_t ext; + ngx_http_file_cache_t *cache; + + c = r->cache; + + if (c->updated) { + return; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http file cache update"); + + c->updated = 1; + + cache = c->file_cache; + + uniq = 0; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http file cache rename: \"%s\" to \"%s\"", + tf->file.name.data, c->file.name.data); + + ext.access = NGX_FILE_OWNER_ACCESS; + ext.path_access = NGX_FILE_OWNER_ACCESS; + 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); + + if (rc == NGX_OK) { + + if (ngx_fd_info(tf->file.fd, &fi) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, + ngx_fd_info_n " \"%s\" failed", tf->file.name.data); + + rc = NGX_ERROR; + + } else { + uniq = ngx_file_uniq(&fi); + } + } + + size = (c->length + cache->bsize - 1) / cache->bsize; + + ngx_shmtx_lock(&cache->shpool->mutex); + + c->node->count--; + c->node->uniq = uniq; + c->node->body_start = c->body_start; + + size = size - (c->node->length + cache->bsize - 1) / cache->bsize; + + c->node->length = c->length; + + *cache->size += size; + + if (rc == NGX_OK) { + c->node->exists = 1; + } + + ngx_shmtx_unlock(&cache->shpool->mutex); +} + + +ngx_int_t +ngx_http_cache_send(ngx_http_request_t *r) +{ + ngx_int_t rc; + ngx_buf_t *b; + ngx_chain_t out; + ngx_http_cache_t *c; + + c = r->cache; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http file cache send: %s", c->file.name.data); + + /* we need to allocate all before the header would be sent */ + + b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); + if (b == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); + if (b->file == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + rc = ngx_http_send_header(r); + + if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { + return rc; + } + + b->file_pos = c->body_start; + b->file_last = c->length; + + b->in_file = (c->length - c->body_start) ? 1: 0; + b->last_buf = (r == r->main) ? 1: 0; + b->last_in_chain = 1; + + b->file->fd = c->file.fd; + b->file->name = c->file.name; + b->file->log = r->connection->log; + + out.buf = b; + out.next = NULL; + + return ngx_http_output_filter(r, &out); +} + + +void +ngx_http_file_cache_free(ngx_http_request_t *r, ngx_temp_file_t *tf) +{ + ngx_http_cache_t *c; + ngx_http_file_cache_t *cache; + + c = r->cache; + + if (c->updated) { + return; + } + + c->updated = 1; + + cache = c->file_cache; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http file cache free"); + + ngx_shmtx_lock(&cache->shpool->mutex); + + c->node->count--; + + if (c->error) { + c->node->valid_sec = c->valid_sec; + c->node->valid_msec = c->valid_msec; + c->node->error = c->error; + } + + ngx_shmtx_unlock(&cache->shpool->mutex); + + if (c->temp_file) { + if (tf && tf->file.fd != NGX_INVALID_FILE) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http file cache incomplete: \"%s\"", + tf->file.name.data); + + if (ngx_delete_file(tf->file.name.data) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, + ngx_delete_file_n " \"%s\" failed", + tf->file.name.data); + } + } + } +} + + +static void +ngx_http_file_cache_cleanup(void *data) +{ + ngx_http_cache_t *c = data; + + ngx_http_file_cache_t *cache; + + if (c->updated) { + return; + } + + c->updated = 1; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->file.log, 0, + "http file cache cleanup"); + + if (c->error) { + return; + } + + cache = c->file_cache; + + ngx_shmtx_lock(&cache->shpool->mutex); + + c->node->count--; + + ngx_shmtx_unlock(&cache->shpool->mutex); +} + + +static time_t +ngx_http_file_cache_forced_expire(ngx_http_file_cache_t *cache) +{ + u_char *name; + size_t len; + time_t wait; + ngx_uint_t tries; + ngx_path_t *path; + ngx_queue_t *q; + ngx_http_file_cache_node_t *fcn; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "http file cache forced expire"); + + path = cache->path; + len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN; + + name = ngx_alloc(len + 1, ngx_cycle->log); + if (name == NULL) { + return 60; + } + + ngx_memcpy(name, path->name.data, path->name.len); + + wait = 60; + tries = 0; + + ngx_shmtx_lock(&cache->shpool->mutex); + + for (q = ngx_queue_last(cache->queue); + q != ngx_queue_sentinel(cache->queue); + q = ngx_queue_prev(q)) + { + fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue); + + ngx_log_debug6(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "http file cache forced expire: #%d %d %02xd%02xd%02xd%02xd", + fcn->count, fcn->exists, + fcn->key[0], fcn->key[1], fcn->key[2], fcn->key[3]); + + if (fcn->count) { + + if (tries++ < 20) { + continue; + } + + wait = 1; + + break; + } + + if (!fcn->exists) { + + ngx_queue_remove(q); + ngx_rbtree_delete(cache->rbtree, &fcn->node); + ngx_slab_free_locked(cache->shpool, fcn); + + break; + } + + ngx_http_file_cache_delete(cache, q, name); + + break; + } + + ngx_shmtx_unlock(&cache->shpool->mutex); + + ngx_free(name); + + return wait; +} + + +static time_t +ngx_http_file_cache_expire(ngx_http_file_cache_t *cache) +{ + u_char *name, *p; + size_t len; + time_t now, wait; + ngx_path_t *path; + ngx_queue_t *q; + ngx_http_file_cache_node_t *fcn; + u_char key[2 * NGX_HTTP_CACHE_KEY_LEN]; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "http file cache expire"); + + path = cache->path; + len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN; + + name = ngx_alloc(len + 1, ngx_cycle->log); + if (name == NULL) { + return 60; + } + + ngx_memcpy(name, path->name.data, path->name.len); + + now = ngx_time(); + + ngx_shmtx_lock(&cache->shpool->mutex); + + for ( ;; ) { + + if (ngx_queue_empty(cache->queue)) { + wait = 60; + break; + } + + q = ngx_queue_last(cache->queue); + + fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue); + + wait = fcn->expire - now; + + if (wait > 0) { + wait = wait > 60 ? 60 : wait; + break; + } + + ngx_log_debug6(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "http file cache expire: #%d %d %02xd%02xd%02xd%02xd", + fcn->count, fcn->exists, + fcn->key[0], fcn->key[1], fcn->key[2], fcn->key[3]); + + if (fcn->count) { + + p = ngx_hex_dump(key, (u_char *) &fcn->node.key, + sizeof(ngx_rbtree_key_t)); + + len = NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t); + (void) ngx_hex_dump(p, fcn->key, len); + + /* + * abnormally exited workers may leave locked cache entries, + * and although it may be safe to remove them completely, + * we prefer to remove them from inactive queue and rbtree + * only, and to allow other leaks + */ + + ngx_queue_remove(q); + ngx_rbtree_delete(cache->rbtree, &fcn->node); + + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, + "ignore long locked inactive cache entry %*s, count:%d", + 2 * NGX_HTTP_CACHE_KEY_LEN, key, fcn->count); + + continue; + } + + if (!fcn->exists) { + + ngx_queue_remove(q); + ngx_rbtree_delete(cache->rbtree, &fcn->node); + ngx_slab_free_locked(cache->shpool, fcn); + + continue; + } + + ngx_http_file_cache_delete(cache, q, name); + } + + ngx_shmtx_unlock(&cache->shpool->mutex); + + ngx_free(name); + + return wait; +} + + +static void +ngx_http_file_cache_delete(ngx_http_file_cache_t *cache, ngx_queue_t *q, + u_char *name) +{ + u_char *p; + size_t len; + ngx_path_t *path; + ngx_http_file_cache_node_t *fcn; + + fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue); + + *cache->size -= (fcn->length + cache->bsize - 1) / cache->bsize; + + path = cache->path; + + p = name + path->name.len + 1 + path->len; + + p = ngx_hex_dump(p, (u_char *) &fcn->node.key, sizeof(ngx_rbtree_key_t)); + + len = NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t); + p = ngx_hex_dump(p, fcn->key, len); + *p = '\0'; + + ngx_queue_remove(q); + + ngx_rbtree_delete(cache->rbtree, &fcn->node); + + ngx_slab_free_locked(cache->shpool, fcn); + + ngx_shmtx_unlock(&cache->shpool->mutex); + + len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN; + + ngx_create_hashed_filename(path, name, len); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "http file cache expire: \"%s\"", name); + + if (ngx_delete_file(name) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, ngx_errno, + ngx_delete_file_n " \"%s\" failed", name); + } + + ngx_shmtx_lock(&cache->shpool->mutex); +} + + +static time_t +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->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 60; + } + + *cache->cold = 0; + + ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, + "http file cache: %V %.3fM, bsize: %uz", + &cache->path->name, + ((double) *cache->size * cache->bsize) / (1024 * 1024), + cache->bsize); + } + + next = ngx_http_file_cache_expire(cache); + + cache->last = ngx_current_msec; + cache->files = 0; + + for ( ;; ) { + ngx_shmtx_lock(&cache->shpool->mutex); + + size = *cache->size; + + ngx_shmtx_unlock(&cache->shpool->mutex); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "http file cache size: %O", size); + + if (size < cache->max_size) { + return next; + } + + next = ngx_http_file_cache_forced_expire(cache); + + if (ngx_http_file_cache_manager_sleep(cache) != NGX_OK) { + return next; + } + } +} + + +static ngx_int_t +ngx_http_file_cache_manager_sleep(ngx_http_file_cache_t *cache) +{ + ngx_msec_t elapsed; + + if (cache->files++ > 100) { + + ngx_time_update(0, 0); + + elapsed = ngx_abs((ngx_msec_int_t) (ngx_current_msec - cache->last)); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0, + "http file cache manager time: %M", elapsed); + + if (elapsed > 200) { + + /* + * if processing 100 files takes more than 200ms, + * it seems that many operations require disk i/o, + * therefore sleep 200ms + */ + + ngx_msleep(200); + + ngx_time_update(0, 0); + } + + cache->last = ngx_current_msec; + cache->files = 0; + } + + return (ngx_quit || ngx_terminate) ? NGX_ABORT : NGX_OK; +} + + +static ngx_int_t +ngx_http_file_cache_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path) +{ + return NGX_OK; +} + + +static ngx_int_t +ngx_http_file_cache_manage_file(ngx_tree_ctx_t *ctx, ngx_str_t *path) +{ + ngx_http_file_cache_t *cache; + + cache = ctx->data; + + if (ngx_http_file_cache_add_file(ctx, path) != NGX_OK) { + (void) ngx_http_file_cache_delete_file(ctx, path); + } + + return ngx_http_file_cache_manager_sleep(cache); +} + + +static ngx_int_t +ngx_http_file_cache_add_file(ngx_tree_ctx_t *ctx, ngx_str_t *name) +{ + u_char *p; + ngx_fd_t fd; + ngx_int_t n; + ngx_uint_t i; + ngx_file_info_t fi; + ngx_http_cache_t c; + ngx_http_file_cache_t *cache; + ngx_http_file_cache_header_t h; + + if (name->len < 2 * NGX_HTTP_CACHE_KEY_LEN) { + return NGX_ERROR; + } + + ngx_memzero(&c, sizeof(ngx_http_cache_t)); + + fd = ngx_open_file(name->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); + + if (fd == NGX_INVALID_FILE) { + ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, + ngx_open_file_n " \"%s\" failed", name->data); + return NGX_ERROR; + } + + c.file.fd = fd; + c.file.name = *name; + c.file.log = ctx->log; + + n = ngx_read_file(&c.file, (u_char *) &h, + sizeof(ngx_http_file_cache_header_t), 0); + if (n == NGX_ERROR) { + return NGX_ERROR; + } + + if ((size_t) n < sizeof(ngx_http_file_cache_header_t)) { + ngx_log_error(NGX_LOG_CRIT, ctx->log, 0, + "cache file \"%s\" is too small", name->data); + return NGX_ERROR; + } + + if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, + ngx_fd_info_n " \"%s\" failed", name->data); + + } else { + c.uniq = ngx_file_uniq(&fi); + c.valid_sec = h.valid_sec; + c.valid_msec = h.valid_msec; + c.body_start = h.body_start; + c.length = ngx_file_size(&fi); + } + + if (ngx_close_file(fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, ctx->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", name->data); + } + + if (c.body_start == 0) { + return NGX_ERROR; + } + + p = &name->data[name->len - 2 * NGX_HTTP_CACHE_KEY_LEN]; + + for (i = 0; i < NGX_HTTP_CACHE_KEY_LEN; i++) { + n = ngx_hextoi(p, 2); + + if (n == NGX_ERROR) { + return NGX_ERROR; + } + + p += 2; + + c.key[i] = (u_char) n; + } + + cache = ctx->data; + + return ngx_http_file_cache_add(cache, &c); +} + + +static ngx_int_t +ngx_http_file_cache_add(ngx_http_file_cache_t *cache, ngx_http_cache_t *c) +{ + ngx_http_file_cache_node_t *fcn; + + ngx_shmtx_lock(&cache->shpool->mutex); + + fcn = ngx_http_file_cache_lookup(cache, c->key); + + if (fcn == NULL) { + + fcn = ngx_slab_alloc_locked(cache->shpool, + sizeof(ngx_http_file_cache_node_t)); + if (fcn == NULL) { + ngx_shmtx_unlock(&cache->shpool->mutex); + return NGX_ERROR; + } + + ngx_memcpy((u_char *) &fcn->node.key, c->key, sizeof(ngx_rbtree_key_t)); + + ngx_memcpy(fcn->key, &c->key[sizeof(ngx_rbtree_key_t)], + NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t)); + + ngx_rbtree_insert(cache->rbtree, &fcn->node); + + fcn->uses = 1; + fcn->count = 0; + fcn->valid_msec = c->valid_msec; + fcn->error = 0; + fcn->exists = 1; + fcn->uniq = c->uniq; + fcn->valid_sec = c->valid_sec; + fcn->body_start = c->body_start; + fcn->length = c->length; + + *cache->size += (c->length + cache->bsize - 1) / cache->bsize; + + } else { + ngx_queue_remove(&fcn->queue); + } + + fcn->expire = ngx_time() + cache->inactive; + + ngx_queue_insert_head(cache->queue, &fcn->queue); + + ngx_shmtx_unlock(&cache->shpool->mutex); return NGX_OK; } -#if 0 +static ngx_int_t +ngx_http_file_cache_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path) +{ + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0, + "http file cache delete: \"%s\"", path->data); + + if (ngx_delete_file(path->data) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno, + ngx_delete_file_n " \"%s\" failed", path->data); + } + + return NGX_OK; +} -int ngx_http_cache_update_file(ngx_http_request_t *r, ngx_http_cache_ctx_t *ctx, - ngx_str_t *temp_file) +time_t +ngx_http_file_cache_valid(ngx_array_t *cache_valid, ngx_uint_t status) { - int retry; - ngx_err_t err; + ngx_uint_t i; + ngx_http_cache_valid_t *valid; - retry = 0; + if (cache_valid == NULL) { + return 0; + } - for ( ;; ) { - if (ngx_rename_file(temp_file->data, ctx->file.name.data) == NGX_OK) { - return NGX_OK; + valid = cache_valid->elts; + for (i = 0; i < cache_valid->nelts; i++) { + + if (valid[i].status == 0) { + return valid[i].valid; } - err = ngx_errno; - -#if (NGX_WIN32) - if (err == NGX_EEXIST) { - if (ngx_win32_rename_file(temp_file, &ctx->file.name, r->pool) - == NGX_ERROR) - { - return NGX_ERROR; - } + if (valid[i].status == status) { + return valid[i].valid; } -#endif + } - if (retry || (err != NGX_ENOENT && err != NGX_ENOTDIR)) { - ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, - ngx_rename_file_n "(\"%s\", \"%s\") failed", - temp_file->data, ctx->file.name.data); - - return NGX_ERROR; - } - - if (ngx_create_path(&ctx->file, ctx->path) == NGX_ERROR) { - return NGX_ERROR; - } - - retry = 1; - } + return 0; } -#endif +char * +ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + off_t max_size; + u_char *last, *p; + time_t inactive; + ssize_t size; + ngx_str_t s, name, *value; + ngx_uint_t i, n; + ngx_http_file_cache_t *cache; + + cache = ngx_pcalloc(cf->pool, sizeof(ngx_http_file_cache_t)); + if (cache == NULL) { + return NGX_CONF_ERROR; + } + + cache->path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t)); + if (cache->path == NULL) { + return NGX_CONF_ERROR; + } + + inactive = 600; + + name.len = 0; + size = 0; + max_size = NGX_MAX_OFF_T_VALUE; + + value = cf->args->elts; + + cache->path->name = value[1]; + + if (cache->path->name.data[cache->path->name.len - 1] == '/') { + cache->path->name.len--; + } + + if (ngx_conf_full_name(cf->cycle, &cache->path->name, 0) != NGX_OK) { + return NGX_CONF_ERROR; + } + + for (i = 2; i < cf->args->nelts; i++) { + + if (ngx_strncmp(value[i].data, "levels=", 7) == 0) { + + n = 0; + p = value[i].data + 7; + last = value[i].data + value[i].len; + + while (p < last) { + + if (*p > '0' && *p < '6') { + + cache->path->level[n] = *p++ - '0'; + cache->path->len += cache->path->level[n] + 1; + + if (p == last) { + break; + } + + if (*p++ == ':') { + + if (n > 2) { + goto invalid_levels; + } + + if (cache->path->level[n] == 0) { + goto invalid_levels; + } + + n++; + + continue; + } + } + + goto invalid_levels; + } + + if (cache->path->len < 10 + 3) { + continue; + } + + invalid_levels: + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid \"levels\" \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + if (ngx_strncmp(value[i].data, "keys_zone=", 10) == 0) { + + name.data = value[i].data + 10; + + p = (u_char *) ngx_strchr(name.data, ':'); + + if (p) { + name.len = p - name.data; + + p++; + + s.len = value[i].data + value[i].len - p; + s.data = p; + + size = ngx_parse_size(&s); + if (size > 8191) { + continue; + } + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid keys zone size \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) { + + s.len = value[i].len - 9; + s.data = value[i].data + 9; + + inactive = ngx_parse_time(&s, 1); + if (inactive < 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid inactive value \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "max_size=", 9) == 0) { + + s.len = value[i].len - 9; + s.data = value[i].data + 9; + + max_size = ngx_parse_offset(&s); + if (max_size < 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid max_size value \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + continue; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + if (name.len == 0 || size == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"%V\" must have \"keys_zone\" parameter", + &cmd->name); + return NGX_CONF_ERROR; + } + + cache->path->manager = ngx_http_file_cache_manager; + cache->path->data = cache; + + if (ngx_add_path(cf, &cache->path) != NGX_OK) { + return NGX_CONF_ERROR; + } + + cache->shm_zone = ngx_shared_memory_add(cf, &name, size, cmd->post); + if (cache->shm_zone == NULL) { + return NGX_CONF_ERROR; + } + + if (cache->shm_zone->data) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "duplicate zone \"%V\"", &name); + return NGX_CONF_ERROR; + } -ngx_int_t ngx_http_cache_cleaner_handler(ngx_gc_t *gc, ngx_str_t *name, - ngx_dir_t *dir) + cache->shm_zone->init = ngx_http_file_cache_init; + cache->shm_zone->data = cache; + + cache->inactive = inactive; + cache->max_size = max_size; + + return NGX_CONF_OK; +} + + +char * +ngx_http_file_cache_valid_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) { - int rc; - ngx_buf_t buf; - ngx_http_cache_t c; - u_char data[sizeof(ngx_http_cache_header_t)]; - - ngx_memzero(&c, sizeof(ngx_http_cache_t)); - - c.file.fd = NGX_INVALID_FILE; - c.file.name = *name; - c.file.log = gc->log; + char *p = conf; - c.header_size = sizeof(ngx_http_cache_header_t); - c.buf = &buf; - c.log = gc->log; - c.key_len = 0; + time_t valid; + ngx_str_t *value; + ngx_uint_t i, n, status; + ngx_array_t **a; + ngx_http_cache_valid_t *v; + static ngx_uint_t statuses[] = { 200, 301, 302 }; + + a = (ngx_array_t **) (p + cmd->offset); - buf.memory = 1; - buf.temporary = 1; - buf.pos = data; - buf.last = data; - buf.start = data; - buf.end = data + sizeof(ngx_http_cache_header_t); + if (*a == NGX_CONF_UNSET_PTR) { + *a = ngx_array_create(cf->pool, 1, sizeof(ngx_http_cache_valid_t)); + if (*a == NULL) { + return NGX_CONF_ERROR; + } + } - rc = ngx_http_file_cache_open(&c); + value = cf->args->elts; + n = cf->args->nelts - 1; - /* TODO: NGX_AGAIN */ - - if (rc != NGX_ERROR&& rc != NGX_DECLINED && rc != NGX_HTTP_CACHE_STALE) { - return NGX_OK; + valid = ngx_parse_time(&value[n], 1); + if (valid < 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid time value \"%V\"", &value[n]); + return NGX_CONF_ERROR; } - if (ngx_delete_file(name->data) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_CRIT, c.log, ngx_errno, - ngx_delete_file_n " \"%s\" failed", name->data); - return NGX_ERROR; + if (n == 1) { + + for (i = 0; i < 3; i++) { + v = ngx_array_push(*a); + if (v == NULL) { + return NGX_CONF_ERROR; + } + + v->status = statuses[i]; + v->valid = valid; + } + + return NGX_CONF_OK; } - gc->deleted++; - gc->freed += ngx_de_size(dir); + for (i = 1; i < n; i++) { + + if (ngx_strcmp(value[i].data, "any") == 0) { + + status = 0; + + } else { - return NGX_OK; + status = ngx_atoi(value[i].data, value[i].len); + if (status < 100) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid status \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + } + + v = ngx_array_push(*a); + if (v == NULL) { + return NGX_CONF_ERROR; + } + + v->status = status; + v->valid = valid; + } + + return NGX_CONF_OK; } diff --git a/src/http/ngx_http_header_filter_module.c b/src/http/ngx_http_header_filter_module.c --- a/src/http/ngx_http_header_filter_module.c +++ b/src/http/ngx_http_header_filter_module.c @@ -155,14 +155,17 @@ ngx_http_header_filter(ngx_http_request_ size_t len; ngx_str_t host; ngx_buf_t *b; - ngx_uint_t status, i; + ngx_uint_t status, i, port; ngx_chain_t out; ngx_list_part_t *part; ngx_table_elt_t *header; ngx_http_core_loc_conf_t *clcf; ngx_http_core_srv_conf_t *cscf; - /* AF_INET only */ - u_char addr[NGX_INET_ADDRSTRLEN]; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + u_char addr[NGX_SOCKADDR_STRLEN]; r->header_sent = 1; @@ -290,6 +293,7 @@ ngx_http_header_filter(ngx_http_request_ host = r->headers_in.server; } else { + host.len = NGX_SOCKADDR_STRLEN; host.data = addr; if (ngx_http_server_addr(r, &host) != NGX_OK) { @@ -297,31 +301,42 @@ ngx_http_header_filter(ngx_http_request_ } } -#if (NGX_HTTP_SSL) - if (r->connection->ssl) { - len += sizeof("Location: https://") - 1 - + host.len - + r->headers_out.location->value.len + 2; + switch (r->connection->local_sockaddr->sa_family) { - if (clcf->port_in_redirect && r->port != 443) { - len += r->port_text->len; - } +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) r->connection->local_sockaddr; + port = ntohs(sin6->sin6_port); + break; +#endif + default: /* AF_INET */ + sin = (struct sockaddr_in *) r->connection->local_sockaddr; + port = ntohs(sin->sin_port); + break; + } - } else + len += sizeof("Location: https://") - 1 + + host.len + + r->headers_out.location->value.len + 2; + + if (clcf->port_in_redirect) { + +#if (NGX_HTTP_SSL) + if (r->connection->ssl) + port = (port == 443) ? 0 : port; + else #endif - { - len += sizeof("Location: http://") - 1 - + host.len - + r->headers_out.location->value.len + 2; + port = (port == 80) ? 0 : port; + } - if (clcf->port_in_redirect && r->port != 80) { - len += r->port_text->len; - } + if (port) { + len += sizeof(":65535") - 1; } } else { host.len = 0; host.data = NULL; + port = 0; } if (r->chunked) { @@ -473,21 +488,8 @@ ngx_http_header_filter(ngx_http_request_ *b->last++ = ':'; *b->last++ = '/'; *b->last++ = '/'; b->last = ngx_copy(b->last, host.data, host.len); - if (clcf->port_in_redirect) { -#if (NGX_HTTP_SSL) - if (r->connection->ssl) { - if (r->port != 443) { - b->last = ngx_copy(b->last, r->port_text->data, - r->port_text->len); - } - } else -#endif - { - if (r->port != 80) { - b->last = ngx_copy(b->last, r->port_text->data, - r->port_text->len); - } - } + if (port) { + b->last = ngx_sprintf(b->last, ":%ui", port); } b->last = ngx_copy(b->last, r->headers_out.location->value.data, 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 @@ -1523,3 +1523,39 @@ ngx_http_arg(ngx_http_request_t *r, u_ch return NGX_DECLINED; } + + +void +ngx_http_split_args(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args) +{ + u_char ch, *p, *last; + + p = uri->data; + + last = p + uri->len; + + args->len = 0; + + while (p < last) { + + ch = *p++; + + if (ch == '?') { + args->len = last - p; + args->data = p; + + uri->len = p - 1 - uri->data; + + if (ngx_strlchr(p, last, '\0') != NULL) { + r->zero_in_uri = 1; + } + + return; + } + + if (ch == '\0') { + r->zero_in_uri = 1; + continue; + } + } +} 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 @@ -232,13 +232,19 @@ ngx_http_init_request(ngx_event_t *rev) ngx_uint_t i; ngx_connection_t *c; ngx_http_request_t *r; - ngx_http_in_port_t *hip; - ngx_http_in_addr_t *hia; + struct sockaddr_in *sin; + ngx_http_port_t *port; + ngx_http_in_addr_t *addr; ngx_http_log_ctx_t *ctx; + ngx_http_addr_conf_t *addr_conf; ngx_http_connection_t *hc; ngx_http_core_srv_conf_t *cscf; ngx_http_core_loc_conf_t *clcf; ngx_http_core_main_conf_t *cmcf; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; + ngx_http_in6_addr_t *addr6; +#endif #if (NGX_STAT_STUB) ngx_atomic_fetch_add(ngx_stat_reading, -1); @@ -292,58 +298,82 @@ ngx_http_init_request(ngx_event_t *rev) /* find the server configuration for the address:port */ - /* AF_INET only */ - - hip = c->listening->servers; - hia = hip->addrs; - - r->port = hip->port; - r->port_text = &hip->port_text; - - i = 0; + port = c->listening->servers; r->connection = c; - if (hip->naddrs > 1) { + if (port->naddrs > 1) { /* - * There are several addresses on this port and one of them - * is the "*:port" wildcard so getsockname() is needed to determine - * the server address. - * - * AcceptEx() already has given this address. + * there are several addresses on this port and one of them + * is an "*:port" wildcard so getsockname() in ngx_http_server_addr() + * is required to determine a server address */ -#if (NGX_WIN32) - if (c->local_sockaddr) { - r->in_addr = - ((struct sockaddr_in *) c->local_sockaddr)->sin_addr.s_addr; - - } else + if (ngx_http_server_addr(r, NULL) != NGX_OK) { + ngx_http_close_connection(c); + return; + } + + switch (c->local_sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) c->local_sockaddr; + + addr6 = (ngx_http_in6_addr_t *) port->addrs; + + /* the last address is "*" */ + + for (i = 0; i < port->naddrs - 1; i++) { + if (ngx_memcmp(&addr6[i].addr6, &sin6->sin6_addr, 16) == 0) { + break; + } + } + + addr_conf = &addr6[i].conf; + + break; #endif - { - if (ngx_http_server_addr(r, NULL) != NGX_OK) { - ngx_http_close_connection(c); - return; + + default: /* AF_INET */ + sin = (struct sockaddr_in *) c->local_sockaddr; + + addr = port->addrs; + + /* the last address is "*" */ + + for (i = 0; i < port->naddrs - 1; i++) { + if (addr[i].addr == sin->sin_addr.s_addr) { + break; + } } - } - - /* the last address is "*" */ - - for ( /* void */ ; i < hip->naddrs - 1; i++) { - if (hia[i].addr == r->in_addr) { - break; - } + + addr_conf = &addr[i].conf; + + break; } } else { - r->in_addr = hia[0].addr; + + switch (c->local_sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + addr6 = (ngx_http_in6_addr_t *) port->addrs; + addr_conf = &addr6[0].conf; + break; +#endif + + default: /* AF_INET */ + addr = port->addrs; + addr_conf = &addr[0].conf; + break; + } } - r->virtual_names = hia[i].virtual_names; - /* the default server configuration for the address:port */ - cscf = hia[i].core_srv_conf; + cscf = addr_conf->core_srv_conf; r->main_conf = cscf->ctx->main_conf; r->srv_conf = cscf->ctx->srv_conf; @@ -357,13 +387,13 @@ ngx_http_init_request(ngx_event_t *rev) ngx_http_ssl_srv_conf_t *sscf; sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); - if (sscf->enable || hia[i].ssl) { + if (sscf->enable || addr_conf->ssl) { if (c->ssl == NULL) { c->log->action = "SSL handshaking"; - if (hia[i].ssl && sscf->ssl.ctx == NULL) { + if (addr_conf->ssl && sscf->ssl.ctx == NULL) { ngx_log_error(NGX_LOG_ERR, c->log, 0, "no \"ssl_certificate\" is defined " "in server listening on SSL port"); @@ -372,7 +402,7 @@ ngx_http_init_request(ngx_event_t *rev) } if (ngx_ssl_create_connection(&sscf->ssl, c, NGX_SSL_BUFFER) - == NGX_ERROR) + != NGX_OK) { ngx_http_close_connection(c); return; @@ -415,7 +445,7 @@ ngx_http_init_request(ngx_event_t *rev) if (ngx_list_init(&r->headers_out.headers, r->pool, 20, sizeof(ngx_table_elt_t)) - == NGX_ERROR) + != NGX_OK) { ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; @@ -775,7 +805,7 @@ ngx_http_process_request_line(ngx_event_ if (ngx_list_init(&r->headers_in.headers, r->pool, 20, sizeof(ngx_table_elt_t)) - == NGX_ERROR) + != NGX_OK) { ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; @@ -784,7 +814,7 @@ ngx_http_process_request_line(ngx_event_ if (ngx_array_init(&r->headers_in.cookies, r->pool, 2, sizeof(ngx_table_elt_t *)) - == NGX_ERROR) + != NGX_OK) { ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; @@ -1580,11 +1610,15 @@ ngx_http_find_virtual_server(ngx_http_re { u_char *server; ngx_uint_t hash; + ngx_http_virtual_names_t *vn; ngx_http_core_loc_conf_t *clcf; ngx_http_core_srv_conf_t *cscf; u_char buf[32]; - if (r->virtual_names == NULL) { + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + vn = cscf->virtual_names; + + if (vn == NULL) { return NGX_DECLINED; } @@ -1600,7 +1634,7 @@ ngx_http_find_virtual_server(ngx_http_re hash = ngx_hash_strlow(server, host, len); - cscf = ngx_hash_find_combined(&r->virtual_names->names, hash, server, len); + cscf = ngx_hash_find_combined(&vn->names, hash, server, len); if (cscf) { goto found; @@ -1608,7 +1642,8 @@ ngx_http_find_virtual_server(ngx_http_re #if (NGX_PCRE) - if (r->virtual_names->nregex) { + if (vn->nregex) { + size_t ncaptures; ngx_int_t n; ngx_uint_t i; ngx_str_t name; @@ -1617,11 +1652,33 @@ ngx_http_find_virtual_server(ngx_http_re name.len = len; name.data = server; - sn = r->virtual_names->regex; - - for (i = 0; i < r->virtual_names->nregex; i++) { - - n = ngx_regex_exec(sn[i].regex, &name, NULL, 0); + ncaptures = 0; + + sn = vn->regex; + + for (i = 0; i < vn->nregex; i++) { + + if (sn[i].captures && r->captures == NULL) { + + ncaptures = (NGX_HTTP_MAX_CAPTURES + 1) * 3; + + r->captures = ngx_palloc(r->pool, ncaptures * sizeof(int)); + if (r->captures == NULL) { + return NGX_ERROR; + } + + if (server == buf) { + server = ngx_pnalloc(r->pool, len); + if (server == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(server, buf, len); + name.data = server; + } + } + + n = ngx_regex_exec(sn[i].regex, &name, r->captures, ncaptures); if (n == NGX_REGEX_NO_MATCHED) { continue; @@ -1639,6 +1696,9 @@ ngx_http_find_virtual_server(ngx_http_re cscf = sn[i].core_srv_conf; + r->ncaptures = ncaptures; + r->captures_data = server; + goto found; } } @@ -2359,8 +2419,15 @@ ngx_http_set_keepalive(ngx_http_request_ (const void *) &tcp_nodelay, sizeof(int)) == -1) { +#if (NGX_SOLARIS) + /* Solaris returns EINVAL if a socket has been shut down */ + c->log_error = NGX_ERROR_IGNORE_EINVAL; +#endif + ngx_connection_error(c, ngx_socket_errno, "setsockopt(TCP_NODELAY) failed"); + + c->log_error = NGX_ERROR_INFO; ngx_http_close_connection(c); return; } 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 @@ -10,6 +10,7 @@ #define NGX_HTTP_MAX_URI_CHANGES 10 #define NGX_HTTP_MAX_SUBREQUESTS 50 +#define NGX_HTTP_MAX_CAPTURES 9 /* must be 2^n */ #define NGX_HTTP_LC_HEADER_LEN 32 @@ -347,7 +348,9 @@ struct ngx_http_request_s { ngx_http_event_handler_pt read_event_handler; ngx_http_event_handler_pt write_event_handler; +#if (NGX_HTTP_CACHE) ngx_http_cache_t *cache; +#endif ngx_http_upstream_t *upstream; ngx_array_t *upstream_states; @@ -384,17 +387,18 @@ struct ngx_http_request_s { ngx_http_post_subrequest_t *post_subrequest; ngx_http_posted_request_t *posted_requests; - uint32_t in_addr; - ngx_uint_t port; - ngx_str_t *port_text; /* ":80" */ - ngx_http_virtual_names_t *virtual_names; - ngx_int_t phase_handler; ngx_http_handler_pt content_handler; ngx_uint_t access_code; ngx_http_variable_value_t *variables; +#if (NGX_PCRE) + ngx_uint_t ncaptures; + int *captures; + u_char *captures_data; +#endif + size_t limit_rate; /* used to learn the Apache compatible response length without a header */ @@ -441,6 +445,9 @@ struct ngx_http_request_s { unsigned subrequest_in_memory:1; unsigned waited:1; +#if (NGX_HTTP_CACHE) + unsigned cached:1; +#endif unsigned gzip:2; unsigned proxy:1; 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 @@ -9,11 +9,208 @@ #include +static ngx_int_t ngx_http_script_init_arrays(ngx_http_script_compile_t *sc); +static ngx_int_t ngx_http_script_done(ngx_http_script_compile_t *sc); +static ngx_int_t ngx_http_script_add_copy_code(ngx_http_script_compile_t *sc, + ngx_str_t *value, ngx_uint_t last); +static ngx_int_t ngx_http_script_add_var_code(ngx_http_script_compile_t *sc, + ngx_str_t *name); +static ngx_int_t ngx_http_script_add_args_code(ngx_http_script_compile_t *sc); +#if (NGX_PCRE) +static ngx_int_t ngx_http_script_add_capture_code(ngx_http_script_compile_t *sc, + ngx_uint_t n); +#endif +static ngx_int_t + ngx_http_script_add_full_name_code(ngx_http_script_compile_t *sc); +static size_t ngx_http_script_full_name_len_code(ngx_http_script_engine_t *e); +static void ngx_http_script_full_name_code(ngx_http_script_engine_t *e); + + #define ngx_http_script_exit (u_char *) &ngx_http_script_exit_code static uintptr_t ngx_http_script_exit_code = (uintptr_t) NULL; +void +ngx_http_script_flush_complex_value(ngx_http_request_t *r, + ngx_http_complex_value_t *val) +{ + ngx_uint_t *index; + + index = val->flushes; + + if (index) { + while (*index != (ngx_uint_t) -1) { + + if (r->variables[*index].no_cacheable) { + r->variables[*index].valid = 0; + r->variables[*index].not_found = 0; + } + + index++; + } + } +} + + +ngx_int_t +ngx_http_complex_value(ngx_http_request_t *r, ngx_http_complex_value_t *val, + ngx_str_t *value) +{ + size_t len; + ngx_http_script_code_pt code; + ngx_http_script_len_code_pt lcode; + ngx_http_script_engine_t e; + + if (val->lengths == NULL) { + *value = val->value; + return NGX_OK; + } + + ngx_http_script_flush_complex_value(r, val); + + ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); + + e.ip = val->lengths; + e.request = r; + e.flushed = 1; + + len = 0; + + while (*(uintptr_t *) e.ip) { + lcode = *(ngx_http_script_len_code_pt *) e.ip; + len += lcode(&e); + } + + value->len = len; + value->data = ngx_pnalloc(r->pool, len); + if (value->data == NULL) { + return NGX_ERROR; + } + + e.ip = val->values; + e.pos = value->data; + e.buf = *value; + + while (*(uintptr_t *) e.ip) { + code = *(ngx_http_script_code_pt *) e.ip; + code((ngx_http_script_engine_t *) &e); + } + + *value = e.buf; + + return NGX_OK; +} + + +ngx_int_t +ngx_http_compile_complex_value(ngx_http_compile_complex_value_t *ccv) +{ + ngx_str_t *v; + ngx_uint_t i, n, nv, nc; + ngx_array_t flushes, lengths, values, *pf, *pl, *pv; + ngx_http_script_compile_t sc; + + v = ccv->value; + + if (v->len == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, ccv->cf, 0, "empty parameter"); + return NGX_ERROR; + } + + nv = 0; + nc = 0; + + for (i = 0; i < v->len; i++) { + if (v->data[i] == '$') { + if (v->data[i + 1] >= '1' && v->data[i + 1] <= '9') { + nc++; + + } else { + nv++; + } + } + } + + if (v->data[0] != '$' && (ccv->conf_prefix || ccv->root_prefix)) { + + if (ngx_conf_full_name(ccv->cf->cycle, v, ccv->conf_prefix) != NGX_OK) { + return NGX_ERROR; + } + + ccv->conf_prefix = 0; + ccv->root_prefix = 0; + } + + ccv->complex_value->value = *v; + ccv->complex_value->flushes = NULL; + ccv->complex_value->lengths = NULL; + ccv->complex_value->values = NULL; + + if (nv == 0 && nc == 0) { + return NGX_OK; + } + + n = nv + 1; + + if (ngx_array_init(&flushes, ccv->cf->pool, n, sizeof(ngx_uint_t)) + != NGX_OK) + { + return NGX_ERROR; + } + + n = nv * (2 * sizeof(ngx_http_script_copy_code_t) + + sizeof(ngx_http_script_var_code_t)) + + sizeof(uintptr_t); + + if (ngx_array_init(&lengths, ccv->cf->pool, n, 1) != NGX_OK) { + return NGX_ERROR; + } + + n = (nv * (2 * sizeof(ngx_http_script_copy_code_t) + + sizeof(ngx_http_script_var_code_t)) + + sizeof(uintptr_t) + + v->len + + sizeof(uintptr_t) - 1) + & ~(sizeof(uintptr_t) - 1); + + if (ngx_array_init(&values, ccv->cf->pool, n, 1) != NGX_OK) { + return NGX_ERROR; + } + + pf = &flushes; + pl = &lengths; + pv = &values; + + ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); + + sc.cf = ccv->cf; + sc.source = v; + sc.flushes = &pf; + sc.lengths = &pl; + sc.values = &pv; + sc.complete_lengths = 1; + sc.complete_values = 1; + sc.zero = ccv->zero; + sc.conf_prefix = ccv->conf_prefix; + sc.root_prefix = ccv->root_prefix; + + if (ngx_http_script_compile(&sc) != NGX_OK) { + return NGX_ERROR; + } + + if (flushes.nelts) { + ccv->complex_value->flushes = flushes.elts; + ccv->complex_value->flushes[flushes.nelts] = (ngx_uint_t) -1; + } + + ccv->complex_value->lengths = lengths.elts; + ccv->complex_value->values = values.elts; + + return NGX_OK; +} + + ngx_uint_t ngx_http_script_variables_count(ngx_str_t *value) { @@ -32,53 +229,14 @@ ngx_http_script_variables_count(ngx_str_ ngx_int_t ngx_http_script_compile(ngx_http_script_compile_t *sc) { - u_char ch; - size_t size; - ngx_int_t index, *p; - ngx_str_t name; - uintptr_t *code; - ngx_uint_t i, n, bracket; - ngx_http_script_var_code_t *var_code; - ngx_http_script_copy_code_t *copy; - ngx_http_script_copy_capture_code_t *copy_capture; - - if (sc->flushes && *sc->flushes == NULL) { - n = sc->variables ? sc->variables : 1; - *sc->flushes = ngx_array_create(sc->cf->pool, n, sizeof(ngx_uint_t)); - if (*sc->flushes == NULL) { - return NGX_ERROR; - } - } - + u_char ch; + ngx_str_t name; + ngx_uint_t i, bracket; - if (*sc->lengths == NULL) { - n = sc->variables * (2 * sizeof(ngx_http_script_copy_code_t) - + sizeof(ngx_http_script_var_code_t)) - + sizeof(uintptr_t); - - *sc->lengths = ngx_array_create(sc->cf->pool, n, 1); - if (*sc->lengths == NULL) { - return NGX_ERROR; - } + if (ngx_http_script_init_arrays(sc) != NGX_OK) { + return NGX_ERROR; } - - if (*sc->values == NULL) { - n = (sc->variables * (2 * sizeof(ngx_http_script_copy_code_t) - + sizeof(ngx_http_script_var_code_t)) - + sizeof(uintptr_t) - + sc->source->len - + sizeof(uintptr_t) - 1) - & ~(sizeof(uintptr_t) - 1); - - *sc->values = ngx_array_create(sc->cf->pool, n, 1); - if (*sc->values == NULL) { - return NGX_ERROR; - } - } - - sc->variables = 0; - for (i = 0; i < sc->source->len; /* void */ ) { name.len = 0; @@ -89,6 +247,12 @@ ngx_http_script_compile(ngx_http_script_ goto invalid_variable; } +#if (NGX_PCRE) + { + ngx_uint_t n; + + /* NGX_HTTP_MAX_CAPTURES is 9 */ + if (sc->source->data[i] >= '1' && sc->source->data[i] <= '9') { n = sc->source->data[i] - '0'; @@ -99,36 +263,16 @@ ngx_http_script_compile(ngx_http_script_ sc->captures_mask |= 1 << n; - copy_capture = ngx_http_script_add_code(*sc->lengths, - sizeof(ngx_http_script_copy_capture_code_t), - NULL); - if (copy_capture == NULL) { + if (ngx_http_script_add_capture_code(sc, n) != NGX_OK) { return NGX_ERROR; } - copy_capture->code = (ngx_http_script_code_pt) - ngx_http_script_copy_capture_len_code; - copy_capture->n = 2 * n; - - - copy_capture = ngx_http_script_add_code(*sc->values, - sizeof(ngx_http_script_copy_capture_code_t), - &sc->main); - if (copy_capture == NULL) { - return NGX_ERROR; - } - - copy_capture->code = ngx_http_script_copy_capture_code; - copy_capture->n = 2 * n; - - if (sc->ncaptures < n) { - sc->ncaptures = n; - } - i++; continue; } + } +#endif if (sc->source->data[i] == '{') { bracket = 1; @@ -177,43 +321,10 @@ ngx_http_script_compile(ngx_http_script_ sc->variables++; - index = ngx_http_get_variable_index(sc->cf, &name); - - if (index == NGX_ERROR) { + if (ngx_http_script_add_var_code(sc, &name) != NGX_OK) { return NGX_ERROR; } - if (sc->flushes) { - p = ngx_array_push(*sc->flushes); - if (p == NULL) { - return NGX_ERROR; - } - - *p = index; - } - - var_code = ngx_http_script_add_code(*sc->lengths, - sizeof(ngx_http_script_var_code_t), - NULL); - if (var_code == NULL) { - return NGX_ERROR; - } - - var_code->code = (ngx_http_script_code_pt) - ngx_http_script_copy_var_len_code; - var_code->index = (uintptr_t) index; - - - var_code = ngx_http_script_add_code(*sc->values, - sizeof(ngx_http_script_var_code_t), - &sc->main); - if (var_code == NULL) { - return NGX_ERROR; - } - - var_code->code = ngx_http_script_copy_var_code; - var_code->index = (uintptr_t) index; - continue; } @@ -221,22 +332,10 @@ ngx_http_script_compile(ngx_http_script_ sc->args = 1; sc->compile_args = 0; - code = ngx_http_script_add_code(*sc->lengths, sizeof(uintptr_t), - NULL); - if (code == NULL) { + if (ngx_http_script_add_args_code(sc) != NGX_OK) { return NGX_ERROR; } - *code = (uintptr_t) ngx_http_script_mark_args_code; - - code = ngx_http_script_add_code(*sc->values, sizeof(uintptr_t), - &sc->main); - if (code == NULL) { - return NGX_ERROR; - } - - *code = (uintptr_t) ngx_http_script_start_args_code; - i++; continue; @@ -265,52 +364,14 @@ ngx_http_script_compile(ngx_http_script_ sc->size += name.len; - copy = ngx_http_script_add_code(*sc->lengths, - sizeof(ngx_http_script_copy_code_t), - NULL); - if (copy == NULL) { - return NGX_ERROR; - } - - copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code; - copy->len = name.len; - - size = (sizeof(ngx_http_script_copy_code_t) + name.len - + sizeof(uintptr_t) - 1) - & ~(sizeof(uintptr_t) - 1); - - copy = ngx_http_script_add_code(*sc->values, size, &sc->main); - if (copy == NULL) { + if (ngx_http_script_add_copy_code(sc, &name, (i == sc->source->len)) + != NGX_OK) + { return NGX_ERROR; } - - copy->code = ngx_http_script_copy_code; - copy->len = name.len; - - ngx_memcpy((u_char *) copy + sizeof(ngx_http_script_copy_code_t), - name.data, name.len); } - if (sc->complete_lengths) { - code = ngx_http_script_add_code(*sc->lengths, sizeof(uintptr_t), NULL); - if (code == NULL) { - return NGX_ERROR; - } - - *code = (uintptr_t) NULL; - } - - if (sc->complete_values) { - code = ngx_http_script_add_code(*sc->values, sizeof(uintptr_t), - &sc->main); - if (code == NULL) { - return NGX_ERROR; - } - - *code = (uintptr_t) NULL; - } - - return NGX_OK; + return ngx_http_script_done(sc); invalid_variable: @@ -387,6 +448,95 @@ ngx_http_script_flush_no_cacheable_varia } +static ngx_int_t +ngx_http_script_init_arrays(ngx_http_script_compile_t *sc) +{ + ngx_uint_t n; + + if (sc->flushes && *sc->flushes == NULL) { + n = sc->variables ? sc->variables : 1; + *sc->flushes = ngx_array_create(sc->cf->pool, n, sizeof(ngx_uint_t)); + if (*sc->flushes == NULL) { + return NGX_ERROR; + } + } + + if (*sc->lengths == NULL) { + n = sc->variables * (2 * sizeof(ngx_http_script_copy_code_t) + + sizeof(ngx_http_script_var_code_t)) + + sizeof(uintptr_t); + + *sc->lengths = ngx_array_create(sc->cf->pool, n, 1); + if (*sc->lengths == NULL) { + return NGX_ERROR; + } + } + + if (*sc->values == NULL) { + n = (sc->variables * (2 * sizeof(ngx_http_script_copy_code_t) + + sizeof(ngx_http_script_var_code_t)) + + sizeof(uintptr_t) + + sc->source->len + + sizeof(uintptr_t) - 1) + & ~(sizeof(uintptr_t) - 1); + + *sc->values = ngx_array_create(sc->cf->pool, n, 1); + if (*sc->values == NULL) { + return NGX_ERROR; + } + } + + sc->variables = 0; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_script_done(ngx_http_script_compile_t *sc) +{ + ngx_str_t zero; + uintptr_t *code; + + if (sc->zero) { + + zero.len = 1; + zero.data = (u_char *) "\0"; + + if (ngx_http_script_add_copy_code(sc, &zero, 0) != NGX_OK) { + return NGX_ERROR; + } + } + + if (sc->conf_prefix || sc->root_prefix) { + if (ngx_http_script_add_full_name_code(sc) != NGX_OK) { + return NGX_ERROR; + } + } + + if (sc->complete_lengths) { + code = ngx_http_script_add_code(*sc->lengths, sizeof(uintptr_t), NULL); + if (code == NULL) { + return NGX_ERROR; + } + + *code = (uintptr_t) NULL; + } + + if (sc->complete_values) { + code = ngx_http_script_add_code(*sc->values, sizeof(uintptr_t), + &sc->main); + if (code == NULL) { + return NGX_ERROR; + } + + *code = (uintptr_t) NULL; + } + + return NGX_OK; +} + + void * ngx_http_script_start_code(ngx_pool_t *pool, ngx_array_t **codes, size_t size) { @@ -425,6 +575,49 @@ ngx_http_script_add_code(ngx_array_t *co } +static ngx_int_t +ngx_http_script_add_copy_code(ngx_http_script_compile_t *sc, ngx_str_t *value, + ngx_uint_t last) +{ + u_char *p; + size_t size, len, zero; + ngx_http_script_copy_code_t *code; + + zero = (sc->zero && last); + len = value->len + zero; + + code = ngx_http_script_add_code(*sc->lengths, + sizeof(ngx_http_script_copy_code_t), NULL); + if (code == NULL) { + return NGX_ERROR; + } + + code->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code; + code->len = len; + + size = (sizeof(ngx_http_script_copy_code_t) + len + sizeof(uintptr_t) - 1) + & ~(sizeof(uintptr_t) - 1); + + code = ngx_http_script_add_code(*sc->values, size, &sc->main); + if (code == NULL) { + return NGX_ERROR; + } + + code->code = ngx_http_script_copy_code; + code->len = len; + + p = ngx_cpymem((u_char *) code + sizeof(ngx_http_script_copy_code_t), + value->data, value->len); + + if (zero) { + *p = '\0'; + sc->zero = 0; + } + + return NGX_OK; +} + + size_t ngx_http_script_copy_len_code(ngx_http_script_engine_t *e) { @@ -461,6 +654,50 @@ ngx_http_script_copy_code(ngx_http_scrip } +static ngx_int_t +ngx_http_script_add_var_code(ngx_http_script_compile_t *sc, ngx_str_t *name) +{ + ngx_int_t index, *p; + ngx_http_script_var_code_t *code; + + index = ngx_http_get_variable_index(sc->cf, name); + + if (index == NGX_ERROR) { + return NGX_ERROR; + } + + if (sc->flushes) { + p = ngx_array_push(*sc->flushes); + if (p == NULL) { + return NGX_ERROR; + } + + *p = index; + } + + code = ngx_http_script_add_code(*sc->lengths, + sizeof(ngx_http_script_var_code_t), NULL); + if (code == NULL) { + return NGX_ERROR; + } + + code->code = (ngx_http_script_code_pt) ngx_http_script_copy_var_len_code; + code->index = (uintptr_t) index; + + code = ngx_http_script_add_code(*sc->values, + sizeof(ngx_http_script_var_code_t), + &sc->main); + if (code == NULL) { + return NGX_ERROR; + } + + code->code = ngx_http_script_copy_var_code; + code->index = (uintptr_t) index; + + return NGX_OK; +} + + size_t ngx_http_script_copy_var_len_code(ngx_http_script_engine_t *e) { @@ -518,62 +755,26 @@ ngx_http_script_copy_var_code(ngx_http_s } -size_t -ngx_http_script_copy_capture_len_code(ngx_http_script_engine_t *e) +static ngx_int_t +ngx_http_script_add_args_code(ngx_http_script_compile_t *sc) { - ngx_http_script_copy_capture_code_t *code; - - code = (ngx_http_script_copy_capture_code_t *) e->ip; - - e->ip += sizeof(ngx_http_script_copy_capture_code_t); + uintptr_t *code; - if (code->n < e->ncaptures) { - if ((e->is_args || e->quote) - && (e->request->quoted_uri || e->request->plus_in_uri)) - { - return e->captures[code->n + 1] - e->captures[code->n] - + 2 * ngx_escape_uri(NULL, - &e->line.data[e->captures[code->n]], - e->captures[code->n + 1] - e->captures[code->n], - NGX_ESCAPE_ARGS); - } else { - return e->captures[code->n + 1] - e->captures[code->n]; - } + code = ngx_http_script_add_code(*sc->lengths, sizeof(uintptr_t), NULL); + if (code == NULL) { + return NGX_ERROR; } - return 0; -} - - -void -ngx_http_script_copy_capture_code(ngx_http_script_engine_t *e) -{ - u_char *p; - ngx_http_script_copy_capture_code_t *code; - - code = (ngx_http_script_copy_capture_code_t *) e->ip; - - e->ip += sizeof(ngx_http_script_copy_capture_code_t); + *code = (uintptr_t) ngx_http_script_mark_args_code; - p = e->pos; - - if (code->n < e->ncaptures) { - if ((e->is_args || e->quote) - && (e->request->quoted_uri || e->request->plus_in_uri)) - { - e->pos = (u_char *) ngx_escape_uri(p, - &e->line.data[e->captures[code->n]], - e->captures[code->n + 1] - e->captures[code->n], - NGX_ESCAPE_ARGS); - } else { - e->pos = ngx_copy(p, - &e->line.data[e->captures[code->n]], - e->captures[code->n + 1] - e->captures[code->n]); - } + code = ngx_http_script_add_code(*sc->values, sizeof(uintptr_t), &sc->main); + if (code == NULL) { + return NGX_ERROR; } - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, - "http script capture: \"%*s\"", e->pos - p, p); + *code = (uintptr_t) ngx_http_script_start_args_code; + + return NGX_OK; } @@ -599,7 +800,6 @@ ngx_http_script_start_args_code(ngx_http } - #if (NGX_PCRE) void @@ -628,7 +828,18 @@ ngx_http_script_regex_start_code(ngx_htt e->line.data = e->sp->data; } - rc = ngx_regex_exec(code->regex, &e->line, e->captures, code->ncaptures); + if (code->ncaptures && r->captures == NULL) { + + r->captures = ngx_palloc(r->pool, + (NGX_HTTP_MAX_CAPTURES + 1) * 3 * sizeof(int)); + if (r->captures == NULL) { + e->ip = ngx_http_script_exit; + e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; + return; + } + } + + rc = ngx_regex_exec(code->regex, &e->line, r->captures, code->ncaptures); if (rc == NGX_REGEX_NO_MATCHED) { if (e->log || (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP)) { @@ -637,7 +848,7 @@ ngx_http_script_regex_start_code(ngx_htt &code->name, &e->line); } - e->ncaptures = 0; + r->ncaptures = 0; if (code->test) { if (code->negative_test) { @@ -674,7 +885,8 @@ ngx_http_script_regex_start_code(ngx_htt "\"%V\" matches \"%V\"", &code->name, &e->line); } - e->ncaptures = code->ncaptures; + r->ncaptures = code->ncaptures; + r->captures_data = e->line.data; if (code->test) { if (code->negative_test) { @@ -725,7 +937,7 @@ ngx_http_script_regex_start_code(ngx_htt } for (n = 1; n < (ngx_uint_t) rc; n++) { - e->buf.len += e->captures[2 * n + 1] - e->captures[2 * n]; + e->buf.len += r->captures[2 * n + 1] - r->captures[2 * n]; } } else { @@ -734,8 +946,6 @@ ngx_http_script_regex_start_code(ngx_htt le.ip = code->lengths->elts; le.line = e->line; le.request = r; - le.captures = e->captures; - le.ncaptures = e->ncaptures; le.quote = code->redirect; len = 0; @@ -874,9 +1084,193 @@ ngx_http_script_regex_end_code(ngx_http_ e->ip += sizeof(ngx_http_script_regex_end_code_t); } + +static ngx_int_t +ngx_http_script_add_capture_code(ngx_http_script_compile_t *sc, ngx_uint_t n) +{ + ngx_http_script_copy_capture_code_t *code; + + code = ngx_http_script_add_code(*sc->lengths, + sizeof(ngx_http_script_copy_capture_code_t), + NULL); + if (code == NULL) { + return NGX_ERROR; + } + + code->code = (ngx_http_script_code_pt) + ngx_http_script_copy_capture_len_code; + code->n = 2 * n; + + + code = ngx_http_script_add_code(*sc->values, + sizeof(ngx_http_script_copy_capture_code_t), + &sc->main); + if (code == NULL) { + return NGX_ERROR; + } + + code->code = ngx_http_script_copy_capture_code; + code->n = 2 * n; + + if (sc->ncaptures < n) { + sc->ncaptures = n; + } + + return NGX_OK; +} + + +size_t +ngx_http_script_copy_capture_len_code(ngx_http_script_engine_t *e) +{ + int *cap; + u_char *p; + ngx_uint_t n; + ngx_http_request_t *r; + ngx_http_script_copy_capture_code_t *code; + + r = e->request; + + code = (ngx_http_script_copy_capture_code_t *) e->ip; + + e->ip += sizeof(ngx_http_script_copy_capture_code_t); + + n = code->n; + + if (n < r->ncaptures) { + + cap = r->captures; + + if ((e->is_args || e->quote) + && (e->request->quoted_uri || e->request->plus_in_uri)) + { + p = r->captures_data; + + return cap[n + 1] - cap[n] + + 2 * ngx_escape_uri(NULL, &p[cap[n]], cap[n + 1] - cap[n], + NGX_ESCAPE_ARGS); + } else { + return cap[n + 1] - cap[n]; + } + } + + return 0; +} + + +void +ngx_http_script_copy_capture_code(ngx_http_script_engine_t *e) +{ + int *cap; + u_char *p, *pos; + ngx_uint_t n; + ngx_http_request_t *r; + ngx_http_script_copy_capture_code_t *code; + + r = e->request; + + code = (ngx_http_script_copy_capture_code_t *) e->ip; + + e->ip += sizeof(ngx_http_script_copy_capture_code_t); + + n = code->n; + + pos = e->pos; + + if (n < r->ncaptures) { + + cap = r->captures; + p = r->captures_data; + + if ((e->is_args || e->quote) + && (e->request->quoted_uri || e->request->plus_in_uri)) + { + e->pos = (u_char *) ngx_escape_uri(pos, &p[cap[n]], + cap[n + 1] - cap[n], + NGX_ESCAPE_ARGS); + } else { + e->pos = ngx_copy(pos, &p[cap[n]], cap[n + 1] - cap[n]); + } + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + "http script capture: \"%*s\"", e->pos - pos, pos); +} + #endif +static ngx_int_t +ngx_http_script_add_full_name_code(ngx_http_script_compile_t *sc) +{ + ngx_http_script_full_name_code_t *code; + + code = ngx_http_script_add_code(*sc->lengths, + sizeof(ngx_http_script_full_name_code_t), + NULL); + if (code == NULL) { + return NGX_ERROR; + } + + code->code = (ngx_http_script_code_pt) ngx_http_script_full_name_len_code; + code->prefix = sc->conf_prefix; + + code = ngx_http_script_add_code(*sc->values, + sizeof(ngx_http_script_full_name_code_t), + &sc->main); + if (code == NULL) { + return NGX_ERROR; + } + + code->code = ngx_http_script_full_name_code; + code->prefix = sc->conf_prefix; + + return NGX_OK; +} + + +static size_t +ngx_http_script_full_name_len_code(ngx_http_script_engine_t *e) +{ + ngx_http_script_full_name_code_t *code; + + code = (ngx_http_script_full_name_code_t *) e->ip; + + e->ip += sizeof(ngx_http_script_full_name_code_t); + + return code->prefix ? sizeof(NGX_CONF_PREFIX) : ngx_cycle->root.len; +} + + +static void +ngx_http_script_full_name_code(ngx_http_script_engine_t *e) +{ + ngx_http_script_full_name_code_t *code; + + ngx_str_t value; + + code = (ngx_http_script_full_name_code_t *) e->ip; + + value.data = e->buf.data; + value.len = e->pos - e->buf.data; + + if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, &value, code->prefix) + != NGX_OK) + { + e->ip = ngx_http_script_exit; + e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; + return; + } + + e->buf = value; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + "http script fullname: \"%V\"", &value); + + e->ip += sizeof(ngx_http_script_full_name_code_t); +} + + void ngx_http_script_return_code(ngx_http_script_engine_t *e) { @@ -1133,8 +1527,6 @@ ngx_http_script_complex_value_code(ngx_h le.ip = code->lengths->elts; le.line = e->line; le.request = e->request; - le.captures = e->captures; - le.ncaptures = e->ncaptures; le.quote = e->quote; for (len = 0; *(uintptr_t *) le.ip; len += lcode(&le)) { diff --git a/src/http/ngx_http_script.h b/src/http/ngx_http_script.h --- a/src/http/ngx_http_script.h +++ b/src/http/ngx_http_script.h @@ -30,9 +30,6 @@ typedef struct { unsigned is_args:1; unsigned log:1; - int *captures; - ngx_uint_t ncaptures; - ngx_int_t status; ngx_http_request_t *request; } ngx_http_script_engine_t; @@ -56,86 +53,114 @@ typedef struct { unsigned compile_args:1; unsigned complete_lengths:1; unsigned complete_values:1; + unsigned zero:1; + unsigned conf_prefix:1; + unsigned root_prefix:1; + unsigned dup_capture:1; - unsigned args:1; } ngx_http_script_compile_t; +typedef struct { + ngx_str_t value; + ngx_uint_t *flushes; + void *lengths; + void *values; +} ngx_http_complex_value_t; + + +typedef struct { + ngx_conf_t *cf; + ngx_str_t *value; + ngx_http_complex_value_t *complex_value; + + unsigned zero:1; + unsigned conf_prefix:1; + unsigned root_prefix:1; +} ngx_http_compile_complex_value_t; + + typedef void (*ngx_http_script_code_pt) (ngx_http_script_engine_t *e); typedef size_t (*ngx_http_script_len_code_pt) (ngx_http_script_engine_t *e); typedef struct { - ngx_http_script_code_pt code; - uintptr_t len; + ngx_http_script_code_pt code; + uintptr_t len; } ngx_http_script_copy_code_t; typedef struct { - ngx_http_script_code_pt code; - uintptr_t index; + ngx_http_script_code_pt code; + uintptr_t index; } ngx_http_script_var_code_t; typedef struct { - ngx_http_script_code_pt code; - ngx_http_set_variable_pt handler; - uintptr_t data; + ngx_http_script_code_pt code; + ngx_http_set_variable_pt handler; + uintptr_t data; } ngx_http_script_var_handler_code_t; typedef struct { - ngx_http_script_code_pt code; - uintptr_t n; + ngx_http_script_code_pt code; + uintptr_t n; } ngx_http_script_copy_capture_code_t; #if (NGX_PCRE) typedef struct { - ngx_http_script_code_pt code; - ngx_regex_t *regex; - ngx_array_t *lengths; - uintptr_t size; - uintptr_t ncaptures; - uintptr_t status; - uintptr_t next; + ngx_http_script_code_pt code; + ngx_regex_t *regex; + ngx_array_t *lengths; + uintptr_t size; + uintptr_t ncaptures; + uintptr_t status; + uintptr_t next; - uintptr_t test:1; - uintptr_t negative_test:1; - uintptr_t uri:1; - uintptr_t args:1; + uintptr_t test:1; + uintptr_t negative_test:1; + uintptr_t uri:1; + uintptr_t args:1; /* add the r->args to the new arguments */ - uintptr_t add_args:1; + uintptr_t add_args:1; - uintptr_t redirect:1; - uintptr_t break_cycle:1; + uintptr_t redirect:1; + uintptr_t break_cycle:1; - ngx_str_t name; + ngx_str_t name; } ngx_http_script_regex_code_t; typedef struct { - ngx_http_script_code_pt code; + ngx_http_script_code_pt code; - uintptr_t uri:1; - uintptr_t args:1; + uintptr_t uri:1; + uintptr_t args:1; /* add the r->args to the new arguments */ - uintptr_t add_args:1; + uintptr_t add_args:1; - uintptr_t redirect:1; + uintptr_t redirect:1; } ngx_http_script_regex_end_code_t; #endif typedef struct { - ngx_http_script_code_pt code; - uintptr_t status; - uintptr_t null; + ngx_http_script_code_pt code; + uintptr_t prefix; +} ngx_http_script_full_name_code_t; + + +typedef struct { + ngx_http_script_code_pt code; + uintptr_t status; + uintptr_t null; } ngx_http_script_return_code_t; @@ -152,32 +177,38 @@ typedef enum { typedef struct { - ngx_http_script_code_pt code; - uintptr_t op; + ngx_http_script_code_pt code; + uintptr_t op; } ngx_http_script_file_code_t; typedef struct { - ngx_http_script_code_pt code; - uintptr_t next; - void **loc_conf; + ngx_http_script_code_pt code; + uintptr_t next; + void **loc_conf; } ngx_http_script_if_code_t; typedef struct { - ngx_http_script_code_pt code; - ngx_array_t *lengths; + ngx_http_script_code_pt code; + ngx_array_t *lengths; } ngx_http_script_complex_value_code_t; typedef struct { - ngx_http_script_code_pt code; - uintptr_t value; - uintptr_t text_len; - uintptr_t text_data; + ngx_http_script_code_pt code; + uintptr_t value; + uintptr_t text_len; + uintptr_t text_data; } ngx_http_script_value_code_t; +void ngx_http_script_flush_complex_value(ngx_http_request_t *r, + ngx_http_complex_value_t *val); +ngx_int_t ngx_http_complex_value(ngx_http_request_t *r, + ngx_http_complex_value_t *val, ngx_str_t *value); +ngx_int_t ngx_http_compile_complex_value(ngx_http_compile_complex_value_t *ccv); + ngx_uint_t ngx_http_script_variables_count(ngx_str_t *value); ngx_int_t ngx_http_script_compile(ngx_http_script_compile_t *sc); u_char *ngx_http_script_run(ngx_http_request_t *r, ngx_str_t *value, diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c --- a/src/http/ngx_http_special_response.c +++ b/src/http/ngx_http_special_response.c @@ -432,9 +432,8 @@ ngx_http_special_response_handler(ngx_ht static ngx_int_t ngx_http_send_error_page(ngx_http_request_t *r, ngx_http_err_page_t *err_page) { - u_char ch, *p, *last; ngx_int_t overwrite; - ngx_str_t *uri, *args, u, a; + ngx_str_t uri, args; ngx_table_elt_t *location; ngx_http_core_loc_conf_t *clcf; @@ -448,67 +447,29 @@ ngx_http_send_error_page(ngx_http_reques r->zero_in_uri = 0; - if (err_page->uri_lengths) { - if (ngx_http_script_run(r, &u, err_page->uri_lengths->elts, 0, - err_page->uri_values->elts) - == NULL) - { - return NGX_ERROR; - } - - p = u.data; - uri = &u; - args = NULL; - - if (*p == '/') { - - last = p + uri->len; - - while (p < last) { - - ch = *p++; + if (ngx_http_complex_value(r, &err_page->value, &uri) != NGX_OK) { + return NGX_ERROR; + } - if (ch == '?') { - a.len = last - p; - a.data = p; - args = &a; - - u.len = p - 1 - u.data; - - while (p < last) { - if (*p++ == '\0') { - r->zero_in_uri = 1; - break; - } - } - - break; - } - - if (ch == '\0') { - r->zero_in_uri = 1; - continue; - } - } - } + if (err_page->value.lengths) { + ngx_http_split_args(r, &uri, &args); } else { - uri = &err_page->uri; - args = &err_page->args; + args = err_page->args; } - if (uri->data[0] == '/') { + if (uri.data[0] == '/') { if (r->method != NGX_HTTP_HEAD) { r->method = NGX_HTTP_GET; r->method_name = ngx_http_get_name; } - return ngx_http_internal_redirect(r, uri, args); + return ngx_http_internal_redirect(r, &uri, &args); } - if (uri->data[0] == '@') { - return ngx_http_named_location(r, uri); + if (uri.data[0] == '@') { + return ngx_http_named_location(r, &uri); } location = ngx_list_push(&r->headers_out.headers); @@ -522,7 +483,7 @@ ngx_http_send_error_page(ngx_http_reques location->hash = 1; location->key.len = sizeof("Location") - 1; location->key.data = (u_char *) "Location"; - location->value = *uri; + location->value = uri; r->headers_out.location = location; 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 @@ -9,6 +9,13 @@ #include +#if (NGX_HTTP_CACHE) +static ngx_int_t ngx_http_upstream_cache(ngx_http_request_t *r, + ngx_http_upstream_t *u); +static ngx_int_t ngx_http_upstream_cache_send(ngx_http_request_t *r, + ngx_http_upstream_t *u); +#endif + static void ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx); static void ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t *r); static void ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r); @@ -29,6 +36,8 @@ static ngx_int_t ngx_http_upstream_test_ static ngx_int_t ngx_http_upstream_intercept_errors(ngx_http_request_t *r, ngx_http_upstream_t *u); static ngx_int_t ngx_http_upstream_test_connect(ngx_connection_t *c); +static ngx_int_t ngx_http_upstream_process_headers(ngx_http_request_t *r, + ngx_http_upstream_t *u); static void ngx_http_upstream_process_body_in_memory(ngx_http_request_t *r, ngx_http_upstream_t *u); static void ngx_http_upstream_send_response(ngx_http_request_t *r, @@ -80,10 +89,15 @@ static ngx_int_t ngx_http_upstream_copy_ ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_upstream_copy_content_length(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t ngx_http_upstream_copy_last_modified(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_upstream_rewrite_location(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_upstream_rewrite_refresh(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); + #if (NGX_HTTP_GZIP) static ngx_int_t ngx_http_upstream_copy_content_encoding(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); @@ -139,8 +153,7 @@ ngx_http_upstream_header_t ngx_http_ups { ngx_string("Last-Modified"), ngx_http_upstream_process_header_line, offsetof(ngx_http_upstream_headers_in_t, last_modified), - ngx_http_upstream_copy_header_line, - offsetof(ngx_http_headers_out_t, last_modified), 0 }, + ngx_http_upstream_copy_last_modified, 0, 0 }, { ngx_string("Server"), ngx_http_upstream_process_header_line, @@ -185,7 +198,7 @@ ngx_http_upstream_header_t ngx_http_ups { ngx_string("Accept-Ranges"), ngx_http_upstream_process_header_line, offsetof(ngx_http_upstream_headers_in_t, accept_ranges), - ngx_http_upstream_copy_header_line, + ngx_http_upstream_copy_allow_ranges, offsetof(ngx_http_headers_out_t, accept_ranges), 1 }, { ngx_string("Connection"), @@ -360,6 +373,25 @@ ngx_http_upstream_init(ngx_http_request_ u->request_bufs = r->request_body->bufs; } +#if (NGX_HTTP_CACHE) + + if (u->conf->cache) { + ngx_int_t rc; + + rc = ngx_http_upstream_cache(r, u); + + if (rc == NGX_DONE) { + return; + } + + if (rc != NGX_DECLINED) { + ngx_http_finalize_request(r, rc); + return; + } + } + +#endif + if (u->create_request(r) != NGX_OK) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; @@ -491,6 +523,136 @@ found: } +#if (NGX_HTTP_CACHE) + +static ngx_int_t +ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u) +{ + ngx_int_t rc; + ngx_http_cache_t *c; + + c = ngx_pcalloc(r->pool, sizeof(ngx_http_cache_t)); + if (c == NULL) { + return NGX_ERROR; + } + + if (ngx_array_init(&c->keys, r->pool, 4, sizeof(ngx_str_t)) != NGX_OK) { + return NGX_ERROR; + } + + r->cache = c; + c->file.log = r->connection->log; + + if (u->create_key(r) != NGX_OK) { + return NGX_ERROR; + } + + /* TODO: add keys */ + + ngx_http_file_cache_create_key(r); + + u->cacheable = 1; + + c->min_uses = r->upstream->conf->cache_min_uses; + c->body_start = r->upstream->conf->buffer_size; + c->file_cache = u->conf->cache->data; + + rc = ngx_http_file_cache_open(r); + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http upstream cache: %i u:%ui", rc, c->uses); + + if (rc == NGX_OK) { + + rc = ngx_http_upstream_cache_send(r, u); + + if (rc != NGX_HTTP_UPSTREAM_INVALID_HEADER) { + return rc; + } + + } else if (rc == NGX_ERROR) { + + return NGX_ERROR; + + } else if (rc == NGX_HTTP_CACHE_STALE) { + + u->stale_cache = 1; + u->buffer.start = NULL; + + } else if (rc == NGX_DECLINED) { + + if ((size_t) (u->buffer.end - u->buffer.start) < u->conf->buffer_size) { + u->buffer.start = NULL; + + } else { + u->buffer.pos = u->buffer.start + c->header_start; + u->buffer.last = u->buffer.pos; + } + + } else if (rc == NGX_AGAIN) { + + u->cacheable = 0; + + } else { + + /* cached NGX_HTTP_BAD_GATEWAY, NGX_HTTP_GATEWAY_TIME_OUT, etc. */ + + return rc; + } + + r->cached = 0; + + return NGX_DECLINED; +} + + +static ngx_int_t +ngx_http_upstream_cache_send(ngx_http_request_t *r, ngx_http_upstream_t *u) +{ + ngx_int_t rc; + ngx_http_cache_t *c; + + c = r->cache; + + /* TODO: cache stack */ + + u->buffer = *c->buf; + u->buffer.pos += c->header_start; + + ngx_memzero(&u->headers_in, sizeof(ngx_http_upstream_headers_in_t)); + + if (ngx_list_init(&u->headers_in.headers, r->pool, 8, + sizeof(ngx_table_elt_t)) + != NGX_OK) + { + return NGX_ERROR; + } + + rc = u->process_header(r); + + if (rc == NGX_OK) { + + if (ngx_http_upstream_process_headers(r, u) != NGX_OK) { + return NGX_DONE; + } + + return ngx_http_cache_send(r); + } + + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + /* rc == NGX_HTTP_UPSTREAM_INVALID_HEADER */ + + /* TODO: delete file */ + + return rc; +} + +#endif + + static void ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx) { @@ -860,7 +1022,7 @@ ngx_http_upstream_ssl_init_connection(ng if (ngx_ssl_create_connection(u->conf->ssl, c, NGX_SSL_BUFFER|NGX_SSL_CLIENT) - == NGX_ERROR) + != NGX_OK) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_INTERNAL_SERVER_ERROR); @@ -969,22 +1131,18 @@ ngx_http_upstream_reinit(ngx_http_reques /* reinit u->buffer */ -#if 0 - if (u->cache) { - u->buffer.pos = u->buffer.start + u->cache->ctx.header_size; - u->buffer.last = u->buffer.pos; - - } else { - u->buffer.pos = u->buffer.start; - u->buffer.last = u->buffer.start; + u->buffer.pos = u->buffer.start; + +#if (NGX_HTTP_CACHE) + + if (r->cache) { + u->buffer.pos += r->cache->header_start; } -#else - - u->buffer.pos = u->buffer.start; - u->buffer.last = u->buffer.start; #endif + u->buffer.last = u->buffer.pos; + return NGX_OK; } @@ -1115,15 +1273,9 @@ ngx_http_upstream_send_request_handler(n static void ngx_http_upstream_process_header(ngx_http_request_t *r, ngx_http_upstream_t *u) { - ssize_t n; - ngx_int_t rc; - ngx_str_t *uri, args; - ngx_uint_t i, flags; - ngx_list_part_t *part; - ngx_table_elt_t *h; - ngx_connection_t *c; - ngx_http_upstream_header_t *hh; - ngx_http_upstream_main_conf_t *umcf; + ssize_t n; + ngx_int_t rc; + ngx_connection_t *c; c = u->peer.connection; @@ -1166,9 +1318,10 @@ ngx_http_upstream_process_header(ngx_htt return; } -#if 0 - if (u->cache) { - u->buffer.pos += u->cache->ctx.header_size; +#if (NGX_HTTP_CACHE) + + if (r->cache) { + u->buffer.pos += r->cache->header_start; u->buffer.last = u->buffer.pos; } #endif @@ -1257,124 +1410,10 @@ ngx_http_upstream_process_header(ngx_htt } } - umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module); - - if (u->headers_in.x_accel_redirect) { - - ngx_http_upstream_finalize_request(r, u, NGX_DECLINED); - - part = &u->headers_in.headers.part; - h = part->elts; - - for (i = 0; /* void */; i++) { - - if (i >= part->nelts) { - if (part->next == NULL) { - break; - } - - part = part->next; - h = part->elts; - i = 0; - } - - hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash, - h[i].lowcase_key, h[i].key.len); - - if (hh && hh->redirect) { - if (hh->copy_handler(r, &h[i], hh->conf) != NGX_OK) { - ngx_http_finalize_request(r, - NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - } - } - - uri = &u->headers_in.x_accel_redirect->value; - args.len = 0; - args.data = NULL; - flags = 0; - - if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) { - ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND); - return; - } - - if (flags & NGX_HTTP_ZERO_IN_URI) { - r->zero_in_uri = 1; - } - - if (r->method != NGX_HTTP_HEAD) { - r->method = NGX_HTTP_GET; - } - - r->valid_unparsed_uri = 0; - - ngx_http_internal_redirect(r, uri, &args); + if (ngx_http_upstream_process_headers(r, u) != NGX_OK) { return; } - part = &u->headers_in.headers.part; - h = part->elts; - - for (i = 0; /* void */; i++) { - - if (i >= part->nelts) { - if (part->next == NULL) { - break; - } - - part = part->next; - h = part->elts; - i = 0; - } - - if (ngx_hash_find(&u->conf->hide_headers_hash, h[i].hash, - h[i].lowcase_key, h[i].key.len)) - { - continue; - } - - hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash, - h[i].lowcase_key, h[i].key.len); - - if (hh) { - if (hh->copy_handler(r, &h[i], hh->conf) != NGX_OK) { - ngx_http_upstream_finalize_request(r, u, - NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - - continue; - } - - if (ngx_http_upstream_copy_header_line(r, &h[i], 0) != NGX_OK) { - ngx_http_upstream_finalize_request(r, u, - NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - } - - if (r->headers_out.server && r->headers_out.server->value.data == NULL) { - r->headers_out.server->hash = 0; - } - - if (r->headers_out.date && r->headers_out.date->value.data == NULL) { - r->headers_out.date->hash = 0; - } - - r->headers_out.status = u->headers_in.status_n; - r->headers_out.status_line = u->headers_in.status_line; - - u->headers_in.content_length_n = r->headers_out.content_length_n; - - if (r->headers_out.content_length_n != -1) { - u->length = (size_t) r->headers_out.content_length_n; - - } else { - u->length = NGX_MAX_SIZE_T_VALUE; - } - if (!r->subrequest_in_memory) { ngx_http_upstream_send_response(r, u); return; @@ -1443,9 +1482,12 @@ ngx_http_upstream_test_next(ngx_http_req #if (NGX_HTTP_CACHE) - if (u->peer.tries == 0 && u->stale && (u->conf->use_stale & un->mask)) { + if (u->peer.tries == 0 + && u->stale_cache + && (u->conf->cache_use_stale & un->mask)) + { ngx_http_upstream_finalize_request(r, u, - ngx_http_send_cached_response(r)); + ngx_http_upstream_cache_send(r, u)); return NGX_OK; } @@ -1557,6 +1599,138 @@ ngx_http_upstream_test_connect(ngx_conne } +static ngx_int_t +ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u) +{ + ngx_str_t *uri, args; + ngx_uint_t i, flags; + ngx_list_part_t *part; + ngx_table_elt_t *h; + ngx_http_upstream_header_t *hh; + ngx_http_upstream_main_conf_t *umcf; + + umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module); + + if (u->headers_in.x_accel_redirect) { + + ngx_http_upstream_finalize_request(r, u, NGX_DECLINED); + + part = &u->headers_in.headers.part; + h = part->elts; + + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + h = part->elts; + i = 0; + } + + hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash, + h[i].lowcase_key, h[i].key.len); + + if (hh && hh->redirect) { + if (hh->copy_handler(r, &h[i], hh->conf) != NGX_OK) { + ngx_http_finalize_request(r, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return NGX_DONE; + } + } + } + + uri = &u->headers_in.x_accel_redirect->value; + args.len = 0; + args.data = NULL; + flags = 0; + + if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) { + ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND); + return NGX_DONE; + } + + if (flags & NGX_HTTP_ZERO_IN_URI) { + r->zero_in_uri = 1; + } + + if (r->method != NGX_HTTP_HEAD) { + r->method = NGX_HTTP_GET; + } + + r->valid_unparsed_uri = 0; + + ngx_http_internal_redirect(r, uri, &args); + return NGX_DONE; + } + + part = &u->headers_in.headers.part; + h = part->elts; + + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + h = part->elts; + i = 0; + } + + if (ngx_hash_find(&u->conf->hide_headers_hash, h[i].hash, + h[i].lowcase_key, h[i].key.len)) + { + continue; + } + + hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash, + h[i].lowcase_key, h[i].key.len); + + if (hh) { + if (hh->copy_handler(r, &h[i], hh->conf) != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return NGX_DONE; + } + + continue; + } + + if (ngx_http_upstream_copy_header_line(r, &h[i], 0) != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return NGX_DONE; + } + } + + if (r->headers_out.server && r->headers_out.server->value.data == NULL) { + r->headers_out.server->hash = 0; + } + + if (r->headers_out.date && r->headers_out.date->value.data == NULL) { + r->headers_out.date->hash = 0; + } + + r->headers_out.status = u->headers_in.status_n; + r->headers_out.status_line = u->headers_in.status_line; + + u->headers_in.content_length_n = r->headers_out.content_length_n; + + if (r->headers_out.content_length_n != -1) { + u->length = (size_t) r->headers_out.content_length_n; + + } else { + u->length = NGX_MAX_SIZE_T_VALUE; + } + + return NGX_OK; +} + + static void ngx_http_upstream_process_body_in_memory(ngx_http_request_t *r, ngx_http_upstream_t *u) @@ -1637,8 +1811,6 @@ ngx_http_upstream_send_response(ngx_http ngx_int_t rc; ngx_event_pipe_t *p; ngx_connection_t *c; - ngx_pool_cleanup_t *cl; - ngx_pool_cleanup_file_t *clf; ngx_http_core_loc_conf_t *clcf; rc = ngx_http_send_header(r); @@ -1651,18 +1823,8 @@ ngx_http_upstream_send_response(ngx_http u->header_sent = 1; if (r->request_body && r->request_body->temp_file) { - for (cl = r->pool->cleanup; cl; cl = cl->next) { - if (cl->handler == ngx_pool_cleanup_file) { - clf = cl->data; - - if (clf->fd == r->request_body->temp_file->file.fd) { - cl->handler(clf); - cl->handler = NULL; - r->request_body->temp_file->file.fd = NGX_INVALID_FILE; - break; - } - } - } + ngx_pool_run_cleanup_file(r->pool, r->request_body->temp_file->file.fd); + r->request_body->temp_file->file.fd = NGX_INVALID_FILE; } c = r->connection; @@ -1738,28 +1900,38 @@ ngx_http_upstream_send_response(ngx_http /* TODO: preallocate event_pipe bufs, look "Content-Length" */ -#if 0 - - if (u->cache && u->cache->ctx.file.fd != NGX_INVALID_FILE) { - if (ngx_close_file(u->cache->ctx.file.fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, - ngx_close_file_n " \"%s\" failed", - u->cache->ctx.file.name.data); - } +#if (NGX_HTTP_CACHE) + + if (r->cache && r->cache->file.fd != NGX_INVALID_FILE) { + ngx_pool_run_cleanup_file(r->pool, r->cache->file.fd); + r->cache->file.fd = NGX_INVALID_FILE; } if (u->cacheable) { - header = (ngx_http_cache_header_t *) u->buffer->start; - - header->expires = u->cache->ctx.expires; - header->last_modified = u->cache->ctx.last_modified; - header->date = u->cache->ctx.date; - header->length = r->headers_out.content_length_n; - u->cache->ctx.length = r->headers_out.content_length_n; - - header->key_len = u->cache->ctx.key0.len; - ngx_memcpy(&header->key, u->cache->ctx.key0.data, header->key_len); - header->key[header->key_len] = LF; + time_t now, valid; + + valid = ngx_http_file_cache_valid(u->conf->cache_valid, + u->headers_in.status_n); + if (valid) { + + now = ngx_time(); + + r->cache->valid_sec = now + valid; + + r->cache->last_modified = r->headers_out.last_modified_time; + 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 { + u->cacheable = 0; + } } #endif @@ -1789,7 +1961,7 @@ ngx_http_upstream_send_response(ngx_http p->temp_file->path = u->conf->temp_path; p->temp_file->pool = r->pool; - if (u->cacheable || u->store) { + if (p->cacheable) { p->temp_file->persistent = 1; } else { @@ -2241,23 +2413,21 @@ ngx_http_upstream_process_request(ngx_ht } } -#if (NGX_HTTP_FILE_CACHE) - - if (p->upstream_done && u->cacheable) { - if (ngx_http_cache_update(r) == NGX_ERROR) { - ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock); - ngx_http_upstream_finalize_request(r, u, 0); - return; - } - - } else if (p->upstream_eof && u->cacheable) { - - /* TODO: check length & update cache */ - - if (ngx_http_cache_update(r) == NGX_ERROR) { - ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock); - ngx_http_upstream_finalize_request(r, u, 0); - return; +#if (NGX_HTTP_CACHE) + + if (u->cacheable) { + + if (p->upstream_done) { + ngx_http_file_cache_update(r, u->pipe->temp_file); + + } else if (p->upstream_eof) { + + /* TODO: check length & update cache */ + + ngx_http_file_cache_update(r, u->pipe->temp_file); + + } else if (p->upstream_error) { + ngx_http_file_cache_free(r, u->pipe->temp_file); } } @@ -2438,12 +2608,12 @@ ngx_http_upstream_next(ngx_http_request_ #if (NGX_HTTP_CACHE) - if (u->stale && (u->conf->use_stale & ft_type)) { + if (u->stale_cache && (u->conf->cache_use_stale & ft_type)) { + ngx_http_upstream_finalize_request(r, u, - ngx_http_send_cached_response(r)); + ngx_http_upstream_cache_send(r, u)); return; } - #endif ngx_http_upstream_finalize_request(r, u, status); @@ -2557,25 +2727,41 @@ ngx_http_upstream_finalize_request(ngx_h u->peer.connection = NULL; - if (u->header_sent && (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE)) - { - rc = 0; - } - if (u->pipe && u->pipe->temp_file) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http upstream temp fd: %d", u->pipe->temp_file->file.fd); } -#if 0 - if (u->cache) { +#if (NGX_HTTP_CACHE) + + if (r->cache) { + time_t valid; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http upstream cache fd: %d", - u->cache->ctx.file.fd); + r->cache->file.fd); + + if (rc == NGX_HTTP_BAD_GATEWAY || rc == NGX_HTTP_GATEWAY_TIME_OUT) { + + valid = ngx_http_file_cache_valid(u->conf->cache_valid, rc); + + if (valid) { + r->cache->valid_sec = ngx_time() + valid; + r->cache->error = rc; + } + } + + ngx_http_file_cache_free(r, u->pipe->temp_file); } + #endif + if (u->header_sent && (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE)) + { + rc = 0; + } + if (rc == NGX_DECLINED) { return; } @@ -2827,6 +3013,33 @@ ngx_http_upstream_copy_content_length(ng static ngx_int_t +ngx_http_upstream_copy_last_modified(ngx_http_request_t *r, ngx_table_elt_t *h, + ngx_uint_t offset) +{ + ngx_table_elt_t *ho; + + ho = ngx_list_push(&r->headers_out.headers); + if (ho == NULL) { + return NGX_ERROR; + } + + *ho = *h; + +#if (NGX_HTTP_CACHE) + + if (r->cached) { + r->headers_out.last_modified = ho; + r->headers_out.last_modified_time = ngx_http_parse_time(h->value.data, + h->value.len); + } + +#endif + + return NGX_OK; +} + + +static ngx_int_t ngx_http_upstream_rewrite_location(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset) { @@ -2916,6 +3129,33 @@ ngx_http_upstream_rewrite_refresh(ngx_ht } +static ngx_int_t +ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset) +{ + ngx_table_elt_t *ho; + +#if (NGX_HTTP_CACHE) + + if (r->cached) { + r->allow_ranges = 1; + return NGX_OK; + + } + +#endif + + ho = ngx_list_push(&r->headers_out.headers); + if (ho == NULL) { + return NGX_ERROR; + } + + *ho = *h; + + return NGX_OK; +} + + #if (NGX_HTTP_GZIP) static ngx_int_t 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 @@ -39,21 +39,21 @@ typedef struct { - ngx_msec_t bl_time; - ngx_uint_t bl_state; + ngx_msec_t bl_time; + ngx_uint_t bl_state; - ngx_uint_t status; - time_t response_sec; - ngx_uint_t response_msec; + ngx_uint_t status; + time_t response_sec; + ngx_uint_t response_msec; off_t response_length; - ngx_str_t *peer; + ngx_str_t *peer; } ngx_http_upstream_state_t; typedef struct { - ngx_hash_t headers_in_hash; - ngx_array_t upstreams; + ngx_hash_t headers_in_hash; + ngx_array_t upstreams; /* ngx_http_upstream_srv_conf_t */ } ngx_http_upstream_main_conf_t; @@ -66,21 +66,21 @@ typedef ngx_int_t (*ngx_http_upstream_in typedef struct { - ngx_http_upstream_init_pt init_upstream; - ngx_http_upstream_init_peer_pt init; - void *data; + ngx_http_upstream_init_pt init_upstream; + ngx_http_upstream_init_peer_pt init; + void *data; } ngx_http_upstream_peer_t; typedef struct { - ngx_peer_addr_t *addrs; - ngx_uint_t naddrs; - ngx_uint_t weight; - ngx_uint_t max_fails; - time_t fail_timeout; + ngx_peer_addr_t *addrs; + ngx_uint_t naddrs; + ngx_uint_t weight; + ngx_uint_t max_fails; + time_t fail_timeout; - unsigned down:1; - unsigned backup:1; + unsigned down:1; + unsigned backup:1; } ngx_http_upstream_server_t; @@ -93,67 +93,75 @@ typedef struct { struct ngx_http_upstream_srv_conf_s { - ngx_http_upstream_peer_t peer; - void **srv_conf; + ngx_http_upstream_peer_t peer; + void **srv_conf; - ngx_array_t *servers; /* ngx_http_upstream_server_t */ + ngx_array_t *servers; /* ngx_http_upstream_server_t */ - ngx_uint_t flags; - ngx_str_t host; - u_char *file_name; - ngx_uint_t line; - in_port_t port; - in_port_t default_port; + ngx_uint_t flags; + ngx_str_t host; + u_char *file_name; + ngx_uint_t line; + in_port_t port; + in_port_t default_port; }; typedef struct { - ngx_http_upstream_srv_conf_t *upstream; + ngx_http_upstream_srv_conf_t *upstream; - ngx_msec_t connect_timeout; - ngx_msec_t send_timeout; - ngx_msec_t read_timeout; - ngx_msec_t timeout; + ngx_msec_t connect_timeout; + ngx_msec_t send_timeout; + ngx_msec_t read_timeout; + ngx_msec_t timeout; - size_t send_lowat; - size_t buffer_size; + size_t send_lowat; + size_t buffer_size; - size_t busy_buffers_size; - size_t max_temp_file_size; - size_t temp_file_write_size; + size_t busy_buffers_size; + size_t max_temp_file_size; + size_t temp_file_write_size; + + size_t busy_buffers_size_conf; + size_t max_temp_file_size_conf; + size_t temp_file_write_size_conf; - size_t busy_buffers_size_conf; - size_t max_temp_file_size_conf; - size_t temp_file_write_size_conf; + ngx_bufs_t bufs; - ngx_uint_t next_upstream; - ngx_uint_t store_access; + ngx_uint_t next_upstream; + ngx_uint_t store_access; + ngx_flag_t buffering; + ngx_flag_t pass_request_headers; + ngx_flag_t pass_request_body; - ngx_bufs_t bufs; + ngx_flag_t ignore_client_abort; + ngx_flag_t intercept_errors; + ngx_flag_t cyclic_temp_file; + + ngx_path_t *temp_path; - ngx_flag_t buffering; - ngx_flag_t pass_request_headers; - ngx_flag_t pass_request_body; + ngx_hash_t hide_headers_hash; + ngx_array_t *hide_headers; + ngx_array_t *pass_headers; - ngx_flag_t ignore_client_abort; - ngx_flag_t intercept_errors; - ngx_flag_t cyclic_temp_file; +#if (NGX_HTTP_CACHE) + ngx_shm_zone_t *cache; - ngx_path_t *temp_path; + ngx_uint_t cache_min_uses; + ngx_uint_t cache_use_stale; - ngx_hash_t hide_headers_hash; - ngx_array_t *hide_headers; - ngx_array_t *pass_headers; + ngx_array_t *cache_valid; +#endif - ngx_array_t *store_lengths; - ngx_array_t *store_values; + ngx_array_t *store_lengths; + ngx_array_t *store_values; - signed store:2; - unsigned intercept_404:1; - unsigned change_buffering:1; + signed store:2; + unsigned intercept_404:1; + unsigned change_buffering:1; #if (NGX_HTTP_SSL) - ngx_ssl_t *ssl; + ngx_ssl_t *ssl; ngx_flag_t ssl_session_reuse; #endif @@ -161,62 +169,62 @@ typedef struct { typedef struct { - ngx_str_t name; - ngx_http_header_handler_pt handler; - ngx_uint_t offset; - ngx_http_header_handler_pt copy_handler; - ngx_uint_t conf; - ngx_uint_t redirect; /* unsigned redirect:1; */ + ngx_str_t name; + ngx_http_header_handler_pt handler; + ngx_uint_t offset; + ngx_http_header_handler_pt copy_handler; + ngx_uint_t conf; + ngx_uint_t redirect; /* unsigned redirect:1; */ } ngx_http_upstream_header_t; typedef struct { - ngx_list_t headers; + ngx_list_t headers; - ngx_uint_t status_n; - ngx_str_t status_line; + ngx_uint_t status_n; + ngx_str_t status_line; - ngx_table_elt_t *status; - ngx_table_elt_t *date; - ngx_table_elt_t *server; - ngx_table_elt_t *connection; + ngx_table_elt_t *status; + ngx_table_elt_t *date; + ngx_table_elt_t *server; + ngx_table_elt_t *connection; - ngx_table_elt_t *expires; - ngx_table_elt_t *etag; - ngx_table_elt_t *x_accel_expires; - ngx_table_elt_t *x_accel_redirect; - ngx_table_elt_t *x_accel_limit_rate; + ngx_table_elt_t *expires; + ngx_table_elt_t *etag; + ngx_table_elt_t *x_accel_expires; + ngx_table_elt_t *x_accel_redirect; + ngx_table_elt_t *x_accel_limit_rate; - ngx_table_elt_t *content_type; - ngx_table_elt_t *content_length; + ngx_table_elt_t *content_type; + ngx_table_elt_t *content_length; - ngx_table_elt_t *last_modified; - ngx_table_elt_t *location; - ngx_table_elt_t *accept_ranges; - ngx_table_elt_t *www_authenticate; + ngx_table_elt_t *last_modified; + ngx_table_elt_t *location; + ngx_table_elt_t *accept_ranges; + ngx_table_elt_t *www_authenticate; #if (NGX_HTTP_GZIP) - ngx_table_elt_t *content_encoding; + ngx_table_elt_t *content_encoding; #endif - off_t content_length_n; + off_t content_length_n; - ngx_array_t cache_control; + ngx_array_t cache_control; } ngx_http_upstream_headers_in_t; typedef struct { - ngx_str_t host; - in_port_t port; - ngx_uint_t no_port; /* unsigned no_port:1 */ + ngx_str_t host; + in_port_t port; + ngx_uint_t no_port; /* unsigned no_port:1 */ - ngx_uint_t naddrs; - in_addr_t *addrs; + ngx_uint_t naddrs; + in_addr_t *addrs; - struct sockaddr *sockaddr; - socklen_t socklen; + struct sockaddr *sockaddr; + socklen_t socklen; - ngx_resolver_ctx_t *ctx; + ngx_resolver_ctx_t *ctx; } ngx_http_upstream_resolved_t; @@ -225,63 +233,69 @@ typedef void (*ngx_http_upstream_handler struct ngx_http_upstream_s { - ngx_http_upstream_handler_pt read_event_handler; - ngx_http_upstream_handler_pt write_event_handler; + ngx_http_upstream_handler_pt read_event_handler; + ngx_http_upstream_handler_pt write_event_handler; - ngx_peer_connection_t peer; + ngx_peer_connection_t peer; - ngx_event_pipe_t *pipe; + ngx_event_pipe_t *pipe; - ngx_chain_t *request_bufs; + ngx_chain_t *request_bufs; - ngx_output_chain_ctx_t output; - ngx_chain_writer_ctx_t writer; + ngx_output_chain_ctx_t output; + ngx_chain_writer_ctx_t writer; - ngx_http_upstream_conf_t *conf; + ngx_http_upstream_conf_t *conf; - ngx_http_upstream_headers_in_t headers_in; + ngx_http_upstream_headers_in_t headers_in; - ngx_http_upstream_resolved_t *resolved; + ngx_http_upstream_resolved_t *resolved; - ngx_buf_t buffer; - size_t length; + ngx_buf_t buffer; + size_t length; - ngx_chain_t *out_bufs; - ngx_chain_t *busy_bufs; - ngx_chain_t *free_bufs; + ngx_chain_t *out_bufs; + ngx_chain_t *busy_bufs; + ngx_chain_t *free_bufs; - ngx_int_t (*input_filter_init)(void *data); - ngx_int_t (*input_filter)(void *data, ssize_t bytes); - void *input_filter_ctx; + ngx_int_t (*input_filter_init)(void *data); + ngx_int_t (*input_filter)(void *data, ssize_t bytes); + void *input_filter_ctx; - ngx_int_t (*create_request)(ngx_http_request_t *r); - ngx_int_t (*reinit_request)(ngx_http_request_t *r); - ngx_int_t (*process_header)(ngx_http_request_t *r); - void (*abort_request)(ngx_http_request_t *r); - void (*finalize_request)(ngx_http_request_t *r, - ngx_int_t rc); - ngx_int_t (*rewrite_redirect)(ngx_http_request_t *r, - ngx_table_elt_t *h, size_t prefix); +#if (NGX_HTTP_CACHE) + ngx_int_t (*create_key)(ngx_http_request_t *r); +#endif + ngx_int_t (*create_request)(ngx_http_request_t *r); + ngx_int_t (*reinit_request)(ngx_http_request_t *r); + ngx_int_t (*process_header)(ngx_http_request_t *r); + void (*abort_request)(ngx_http_request_t *r); + void (*finalize_request)(ngx_http_request_t *r, + ngx_int_t rc); + ngx_int_t (*rewrite_redirect)(ngx_http_request_t *r, + ngx_table_elt_t *h, size_t prefix); - ngx_msec_t timeout; + ngx_msec_t timeout; - ngx_http_upstream_state_t *state; + ngx_http_upstream_state_t *state; - ngx_str_t method; - ngx_str_t schema; - ngx_str_t uri; + ngx_str_t method; + ngx_str_t schema; + ngx_str_t uri; - ngx_http_cleanup_pt *cleanup; + ngx_http_cleanup_pt *cleanup; - unsigned store:1; - unsigned cacheable:1; - unsigned accel:1; - unsigned ssl:1; + unsigned store:1; + unsigned cacheable:1; + unsigned accel:1; + unsigned ssl:1; +#if (NGX_HTTP_CACHE) + unsigned stale_cache:1; +#endif - unsigned buffering:1; + unsigned buffering:1; - unsigned request_sent:1; - unsigned header_sent:1; + unsigned request_sent:1; + unsigned header_sent:1; }; diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -332,7 +332,8 @@ ngx_http_get_variable_index(ngx_conf_t * if (v == NULL) { if (ngx_array_init(&cmcf->variables, cf->pool, 4, - sizeof(ngx_http_variable_t)) == NGX_ERROR) + sizeof(ngx_http_variable_t)) + != NGX_OK) { return NGX_ERROR; } @@ -828,17 +829,37 @@ static ngx_int_t ngx_http_variable_binary_remote_addr(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { - struct sockaddr_in *sin; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif - /* AF_INET only */ + switch (r->connection->sockaddr->sa_family) { - sin = (struct sockaddr_in *) r->connection->sockaddr; +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) r->connection->sockaddr; - v->len = sizeof(in_addr_t); - v->valid = 1; - v->no_cacheable = 0; - v->not_found = 0; - v->data = (u_char *) &sin->sin_addr.s_addr; + v->len = sizeof(struct in6_addr); + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = (u_char *) &sin6->sin6_addr; + + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) r->connection->sockaddr; + + v->len = sizeof(in_addr_t); + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = (u_char *) &sin->sin_addr; + + break; + } return NGX_OK; } @@ -862,8 +883,11 @@ static ngx_int_t ngx_http_variable_remote_port(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { - ngx_uint_t port; - struct sockaddr_in *sin; + ngx_uint_t port; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif v->len = 0; v->valid = 1; @@ -875,16 +899,23 @@ ngx_http_variable_remote_port(ngx_http_r return NGX_ERROR; } - /* AF_INET only */ + switch (r->connection->sockaddr->sa_family) { - if (r->connection->sockaddr->sa_family == AF_INET) { - sin = (struct sockaddr_in *) r->connection->sockaddr; +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) r->connection->sockaddr; + port = ntohs(sin6->sin6_port); + break; +#endif + default: /* AF_INET */ + sin = (struct sockaddr_in *) r->connection->sockaddr; port = ntohs(sin->sin_port); + break; + } - if (port > 0 && port < 65536) { - v->len = ngx_sprintf(v->data, "%ui", port) - v->data; - } + if (port > 0 && port < 65536) { + v->len = ngx_sprintf(v->data, "%ui", port) - v->data; } return NGX_OK; @@ -896,15 +927,21 @@ ngx_http_variable_server_addr(ngx_http_r ngx_http_variable_value_t *v, uintptr_t data) { ngx_str_t s; + u_char addr[NGX_SOCKADDR_STRLEN]; - s.data = ngx_pnalloc(r->pool, NGX_INET_ADDRSTRLEN); + s.len = NGX_SOCKADDR_STRLEN; + s.data = addr; + + if (ngx_http_server_addr(r, &s) != NGX_OK) { + return NGX_ERROR; + } + + s.data = ngx_pnalloc(r->pool, s.len); if (s.data == NULL) { return NGX_ERROR; } - if (ngx_http_server_addr(r, &s) != NGX_OK) { - return NGX_ERROR; - } + ngx_memcpy(s.data, addr, s.len); v->len = s.len; v->valid = 1; @@ -920,11 +957,44 @@ static ngx_int_t ngx_http_variable_server_port(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { - v->len = r->port_text->len - 1; + ngx_uint_t port; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + + v->len = 0; v->valid = 1; v->no_cacheable = 0; v->not_found = 0; - v->data = r->port_text->data + 1; + + if (ngx_http_server_addr(r, NULL) != NGX_OK) { + return NGX_ERROR; + } + + v->data = ngx_pnalloc(r->pool, sizeof("65535") - 1); + if (v->data == NULL) { + return NGX_ERROR; + } + + switch (r->connection->local_sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) r->connection->local_sockaddr; + port = ntohs(sin6->sin6_port); + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) r->connection->local_sockaddr; + port = ntohs(sin->sin_port); + break; + } + + if (port > 0 && port < 65536) { + v->len = ngx_sprintf(v->data, "%ui", port) - v->data; + } return NGX_OK; } @@ -1003,9 +1073,7 @@ ngx_http_variable_document_root(ngx_http return NGX_ERROR; } - if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, &path, 0) - == NGX_ERROR) - { + if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, &path, 0) != NGX_OK) { return NGX_ERROR; } @@ -1044,9 +1112,7 @@ ngx_http_variable_realpath_root(ngx_http path.data[path.len - 1] = '\0'; - if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, &path, 0) - == NGX_ERROR) - { + if (ngx_conf_full_name((ngx_cycle_t *) ngx_cycle, &path, 0) != NGX_OK) { return NGX_ERROR; } } @@ -1250,6 +1316,8 @@ static ngx_int_t ngx_http_variable_sent_location(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { + ngx_str_t name; + if (r->headers_out.location) { v->len = r->headers_out.location->value.len; v->valid = 1; @@ -1260,7 +1328,10 @@ ngx_http_variable_sent_location(ngx_http return NGX_OK; } - return ngx_http_variable_unknown_header(v, (ngx_str_t *) data, + name.len = sizeof("sent_http_location") - 1; + name.data = (u_char *) "sent_http_location"; + + return ngx_http_variable_unknown_header(v, &name, &r->headers_out.headers.part, sizeof("sent_http_") - 1); } 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 @@ -305,6 +305,11 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx return NGX_CONF_ERROR; } + if (u.family != AF_INET) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "listen supports IPv4 only"); + return NGX_CONF_ERROR; + } + cmcf = ngx_mail_conf_get_module_main_conf(cf, ngx_mail_core_module); imls = cmcf->listen.elts; diff --git a/src/os/unix/ngx_darwin_config.h b/src/os/unix/ngx_darwin_config.h --- a/src/os/unix/ngx_darwin_config.h +++ b/src/os/unix/ngx_darwin_config.h @@ -24,6 +24,7 @@ #include #include #include +#include /* statfs() */ #include /* FIONBIO */ #include 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 @@ -44,6 +44,7 @@ typedef int ngx_err_t; #define NGX_EHOSTUNREACH EHOSTUNREACH #define NGX_ENOSYS ENOSYS #define NGX_ECANCELED ECANCELED +#define NGX_EILSEQ EILSEQ #define NGX_ENOMOREFILES 0 diff --git a/src/os/unix/ngx_files.c b/src/os/unix/ngx_files.c --- a/src/os/unix/ngx_files.c +++ b/src/os/unix/ngx_files.c @@ -249,11 +249,6 @@ ngx_open_dir(ngx_str_t *name, ngx_dir_t } dir->valid_info = 0; -#if (NGX_HAVE_D_TYPE) - dir->valid_type = 1; -#else - dir->valid_type = 0; -#endif return NGX_OK; } @@ -267,6 +262,9 @@ ngx_read_dir(ngx_dir_t *dir) if (dir->de) { #if (NGX_HAVE_D_TYPE) dir->type = dir->de->d_type; + dir->valid_type = dir->type ? 1 : 0; +#else + dir->valid_type = 0; #endif return NGX_OK; } @@ -418,3 +416,50 @@ ngx_directio_off(ngx_fd_t fd) } #endif + + +#if (NGX_HAVE_STATFS) + +size_t +ngx_fs_bsize(u_char *name) +{ + struct statfs fs; + + if (statfs((char *) name, &fs) == -1) { + return 512; + } + + if ((fs.f_bsize % 512) != 0) { + return 512; + } + + return (size_t) fs.f_bsize; +} + +#elif (NGX_HAVE_STATVFS) + +size_t +ngx_fs_bsize(u_char *name) +{ + struct statvfs fs; + + if (statvfs((char *) name, &fs) == -1) { + return 512; + } + + if ((fs.f_frsize % 512) != 0) { + return 512; + } + + return (size_t) fs.f_frsize; +} + +#else + +size_t +ngx_fs_bsize(u_char *name) +{ + return 512; +} + +#endif 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 @@ -64,9 +64,10 @@ typedef struct { #define NGX_FILE_CREATE_OR_OPEN O_CREAT #define NGX_FILE_OPEN 0 #define NGX_FILE_TRUNCATE O_TRUNC -#define NGX_FILE_APPEND O_APPEND +#define NGX_FILE_APPEND O_WRONLY|O_APPEND #define NGX_FILE_DEFAULT_ACCESS 0644 +#define NGX_FILE_OWNER_ACCESS 0600 #define ngx_close_file close @@ -200,10 +201,25 @@ ngx_int_t ngx_read_dir(ngx_dir_t *dir); #if (NGX_HAVE_D_TYPE) +#if (NGX_LINUX) + +/* XFS on Linux does not set dirent.d_type */ + +#define ngx_de_is_dir(dir) \ + (((dir)->type) ? ((dir)->type == DT_DIR) : (S_ISDIR((dir)->info.st_mode))) +#define ngx_de_is_file(dir) \ + (((dir)->type) ? ((dir)->type == DT_REG) : (S_ISREG((dir)->info.st_mode))) +#define ngx_de_is_link(dir) \ + (((dir)->type) ? ((dir)->type == DT_LINK) : (S_ISLNK((dir)->info.st_mode))) + +#else + #define ngx_de_is_dir(dir) ((dir)->type == DT_DIR) #define ngx_de_is_file(dir) ((dir)->type == DT_REG) #define ngx_de_is_link(dir) ((dir)->type == DT_LINK) +#endif /* NGX_LINUX */ + #else #define ngx_de_is_dir(dir) (S_ISDIR((dir)->info.st_mode)) @@ -258,4 +274,7 @@ ngx_int_t ngx_directio_off(ngx_fd_t fd); #endif +size_t ngx_fs_bsize(u_char *name); + + #endif /* _NGX_FILES_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_freebsd_config.h b/src/os/unix/ngx_freebsd_config.h --- a/src/os/unix/ngx_freebsd_config.h +++ b/src/os/unix/ngx_freebsd_config.h @@ -22,6 +22,8 @@ #include #include #include +#include /* ALIGN() */ +#include /* statfs() */ #include /* FIONBIO */ #include @@ -43,7 +45,6 @@ #include /* setproctitle() before 4.1 */ #include #include -#include /* ALIGN() */ #if __FreeBSD_version < 400017 diff --git a/src/os/unix/ngx_linux_config.h b/src/os/unix/ngx_linux_config.h --- a/src/os/unix/ngx_linux_config.h +++ b/src/os/unix/ngx_linux_config.h @@ -28,6 +28,7 @@ #include #include #include +#include /* statfs() */ #include #include diff --git a/src/os/unix/ngx_posix_config.h b/src/os/unix/ngx_posix_config.h --- a/src/os/unix/ngx_posix_config.h +++ b/src/os/unix/ngx_posix_config.h @@ -44,6 +44,12 @@ #include #include #include +#if (NGX_HAVE_SYS_MOUNT_H) +#include /* statfs() */ +#endif +#if (NGX_HAVE_SYS_STATVFS_H) +#include /* statvfs() */ +#endif #if (NGX_HAVE_SYS_FILIO_H) #include /* FIONBIO */ 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,7 @@ static void ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type); -static void ngx_start_garbage_collector(ngx_cycle_t *cycle, ngx_int_t type); +static void ngx_start_cache_manager_process(ngx_cycle_t *cycle, ngx_int_t type); 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); @@ -24,9 +24,8 @@ static void ngx_channel_handler(ngx_even static void ngx_wakeup_worker_threads(ngx_cycle_t *cycle); static ngx_thread_value_t ngx_worker_thread_cycle(void *data); #endif -#if 0 -static void ngx_garbage_collector_cycle(ngx_cycle_t *cycle, void *data); -#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); ngx_uint_t ngx_process; @@ -123,7 +122,7 @@ ngx_master_process_cycle(ngx_cycle_t *cy ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_RESPAWN); - ngx_start_garbage_collector(cycle, NGX_PROCESS_RESPAWN); + ngx_start_cache_manager_process(cycle, NGX_PROCESS_RESPAWN); ngx_new_binary = 0; delay = 0; @@ -204,7 +203,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_garbage_collector(cycle, NGX_PROCESS_RESPAWN); + ngx_start_cache_manager_process(cycle, NGX_PROCESS_RESPAWN); ngx_noaccepting = 0; continue; @@ -223,7 +222,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_garbage_collector(cycle, NGX_PROCESS_JUST_RESPAWN); + ngx_start_cache_manager_process(cycle, NGX_PROCESS_JUST_RESPAWN); live = 1; ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); @@ -233,7 +232,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_garbage_collector(cycle, NGX_PROCESS_RESPAWN); + ngx_start_cache_manager_process(cycle, NGX_PROCESS_RESPAWN); live = 1; } @@ -361,18 +360,28 @@ ngx_start_worker_processes(ngx_cycle_t * static void -ngx_start_garbage_collector(ngx_cycle_t *cycle, ngx_int_t type) +ngx_start_cache_manager_process(ngx_cycle_t *cycle, ngx_int_t type) { -#if 0 - ngx_int_t i; - ngx_channel_t ch; + ngx_int_t i; + ngx_uint_t n; + ngx_path_t **path; + ngx_channel_t ch; - ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start garbage collector"); + path = ngx_cycle->pathes.elts; + for (n = 0; n < ngx_cycle->pathes.nelts; n++) { + if (path[n]->manager) { + goto start; + } + } + + return; + +start: ch.command = NGX_CMD_OPEN_CHANNEL; - ngx_spawn_process(cycle, ngx_garbage_collector_cycle, NULL, - "garbage collector", type); + 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; @@ -398,7 +407,6 @@ ngx_start_garbage_collector(ngx_cycle_t ngx_write_channel(ngx_processes[i].channel[0], &ch, sizeof(ngx_channel_t), cycle->log); } -#endif } @@ -1004,7 +1012,7 @@ ngx_worker_process_exit(ngx_cycle_t *cyc && !c[i].read->resolver) { ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, - "open socket #%d left in %ui connection %s", + "open socket #%d left in connection %ui%s", c[i].fd, i, ngx_debug_quit ? ", aborting" : ""); ngx_debug_point(); } @@ -1254,27 +1262,29 @@ ngx_worker_thread_cycle(void *data) #endif -#if 0 - static void -ngx_garbage_collector_cycle(ngx_cycle_t *cycle, void *data) +ngx_cache_manager_process_cycle(ngx_cycle_t *cycle, void *data) { - ngx_uint_t i; - ngx_gc_t ctx; - ngx_path_t **path; - ngx_event_t *ev; + void *ident[4]; + ngx_event_t ev; + + cycle->connection_n = 512; ngx_worker_process_init(cycle, 0); - ev = &cycle->read_events0[ngx_channel]; - - ngx_accept_mutex = NULL; + ngx_close_listening_sockets(cycle); - ngx_setproctitle("garbage collector"); + ngx_memzero(&ev, sizeof(ngx_event_t)); + ev.handler = ngx_cache_manager_process_handler; + ev.data = ident; + ev.log = cycle->log; + ident[3] = (void *) -1; -#if 0 - ngx_add_timer(ev, 60 * 1000); -#endif + ngx_use_accept_mutex = 0; + + ngx_setproctitle("cache manager process"); + + ngx_add_timer(&ev, 0); for ( ;; ) { @@ -1289,19 +1299,35 @@ ngx_garbage_collector_cycle(ngx_cycle_t ngx_reopen_files(cycle, -1); } - path = cycle->pathes.elts; - for (i = 0; i < cycle->pathes.nelts; i++) { - ctx.path = path[i]; - ctx.log = cycle->log; - ctx.handler = path[i]->cleaner; - - ngx_collect_garbage(&ctx, &path[i]->name, 0); - } - - ngx_add_timer(ev, 60 * 60 * 1000); - ngx_process_events_and_timers(cycle); } } -#endif + +static void +ngx_cache_manager_process_handler(ngx_event_t *ev) +{ + time_t next, n; + ngx_uint_t i; + ngx_path_t **path; + + next = 60 * 60; + + path = ngx_cycle->pathes.elts; + for (i = 0; i < ngx_cycle->pathes.nelts; i++) { + + if (path[i]->manager) { + n = path[i]->manager(path[i]->data); + + next = (n <= next) ? n : next; + + ngx_time_update(0, 0); + } + } + + if (next == 0) { + next = 1; + } + + ngx_add_timer(ev, next * 1000); +} diff --git a/src/os/unix/ngx_solaris_config.h b/src/os/unix/ngx_solaris_config.h --- a/src/os/unix/ngx_solaris_config.h +++ b/src/os/unix/ngx_solaris_config.h @@ -28,6 +28,7 @@ #include #include #include +#include /* statvfs() */ #include /* FIONBIO */ #include