# HG changeset patch # User Igor Sysoev # Date 1111179600 -10800 # Node ID 72eb30262aac58f69b80911fbd4dee3ea829f148 # Parent 93dabbc9efb90cc7f92bf1c136d9c44366fa3d5a nginx 0.1.25 *) Bugfix: nginx did run on Linux parisc. *) Feature: nginx now does not start under FreeBSD if the sysctl kern.ipc.somaxconn value is too big. *) Bugfix: if a request was internally redirected by the ngx_http_index_module module to the ngx_http_proxy_module or ngx_http_fastcgi_module modules, then the index file was not closed after request completion. *) Feature: the "proxy_pass" can be used in location with regular expression. *) Feature: the ngx_http_rewrite_filter_module module supports the condition like "if ($HTTP_USER_AGENT ~ MSIE)". *) Bugfix: nginx started too slow if the large number of addresses and text values were used in the "geo" directive. *) Change: a variable name must be declared as "$name" in the "geo" directive. The previous variant without "$" is still supported, but will be removed soon. *) Feature: the "%{VARIABLE}v" logging parameter. *) Feature: the "set $name value" directive. *) Bugfix: gcc 4.0 compatibility. *) Feature: the --with-openssl-opt=OPTIONS autoconfiguration directive. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,37 @@ + +Changes with nginx 0.1.25 19 Mar 2005 + + *) Bugfix: nginx did run on Linux parisc. + + *) Feature: nginx now does not start under FreeBSD if the sysctl + kern.ipc.somaxconn value is too big. + + *) Bugfix: if a request was internally redirected by the + ngx_http_index_module module to the ngx_http_proxy_module or + ngx_http_fastcgi_module modules, then the index file was not closed + after request completion. + + *) Feature: the "proxy_pass" can be used in location with regular + expression. + + *) Feature: the ngx_http_rewrite_filter_module module supports the + condition like "if ($HTTP_USER_AGENT ~ MSIE)". + + *) Bugfix: nginx started too slow if the large number of addresses and + text values were used in the "geo" directive. + + *) Change: a variable name must be declared as "$name" in the "geo" + directive. The previous variant without "$" is still supported, but + will be removed soon. + + *) Feature: the "%{VARIABLE}v" logging parameter. + + *) Feature: the "set $name value" directive. + + *) Bugfix: gcc 4.0 compatibility. + + *) Feature: the --with-openssl-opt=OPTIONS autoconfiguration directive. + Changes with nginx 0.1.24 04 Mar 2005 diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,3 +1,36 @@ + +Изменения в nginx 0.1.25 19.03.2005 + + *) Исправление: nginx не работал на Linux parisc. + + *) Добавление: nginx теперь не запускается под FreeBSD, если значение + sysctl kern.ipc.somaxconn слишком большое. + + *) Исправление: если модуль ngx_http_index_module делал внутреннее + перенаправление запроса в модули ngx_http_proxy_module или + ngx_http_fastcgi_module, то файл индекса не закрывался после + обслуживания запроса. + + *) Добавление: директива proxy_pass может использоваться в location, + заданных регулярным выражением. + + *) Добавление: модуль ngx_http_rewrite_filter_module поддерживает + условия вида "if ($HTTP_USER_AGENT ~ MSIE)". + + *) Исправление: nginx очень медленно запускался при большом количестве + адресов и использовании текстовых значений в директиве geo. + + *) Изменение: имя переменной в директиве geo нужно указывать, как + $name. Прежний вариант без "$" пока работает, но вскоре будет убран. + + *) Добавление: параметр лога "%{VARIABLE}v". + + *) Добавление: директива "set $name value". + + *) Исправление: совместимость с gcc 4.0. + + *) Добавление: параметр автоконфигурации --with-openssl-opt=OPTIONS. + Изменения в nginx 0.1.24 04.03.2005 diff --git a/auto/cc/gcc b/auto/cc/gcc --- a/auto/cc/gcc +++ b/auto/cc/gcc @@ -2,8 +2,15 @@ # Copyright (C) Igor Sysoev -# gcc 2.7.2.3, 2.8.1, 2.95.4, +# gcc 2.7.2.3, 2.8.1, 2.95.4, egcs-1.1.2 # 3.0.4, 3.1.1, 3.2.3, 3.3.2, 3.3.3, 3.3.4, 3.4.0, 3.4.2 +# 4.0.0 + + +NGX_GCC_VER=`$CC -v 2>&1 | grep 'gcc version' 2>&1 \ + | sed -e 's/^.* version \(.*\)/\1/'` + +echo " + gcc version: $NGX_GCC_VER" # Solaris 7's /usr/ccs/bin/as does not support "-pipe" @@ -24,7 +31,6 @@ if [ $ngx_found = yes ]; then PIPE="-pipe" fi - # optimizations #NGX_GCC_OPT="-O2" @@ -61,8 +67,12 @@ case $CPU in esac -# STUB for batch builds -if [ $CC = gcc27 ]; then CPU_OPT=; fi +case "$NGX_GCC_VER" in + 2.7*) + # batch build + CPU_OPT= + ;; +esac CFLAGS="$CFLAGS $PIPE $CPU_OPT" @@ -95,8 +105,21 @@ CFLAGS="$CFLAGS -Wall -Wpointer-arith" #CFLAGS="$CFLAGS -Wconversion" #CFLAGS="$CFLAGS -Winline" -# we have a lot of the unused function arguments -CFLAGS="$CFLAGS -Wno-unused" + +case "$NGX_GCC_VER" in + 3.* | 4.* ) + # we have a lot of the unused function arguments + CFLAGS="$CFLAGS -Wno-unused-parameter" + CFLAGS="$CFLAGS -Wno-unused-function" + #CFLAGS="$CFLAGS -Wunreachable-code" + ;; + + *) + # we have a lot of the unused function arguments + CFLAGS="$CFLAGS -Wno-unused" + ;; +esac + # stop on warning CFLAGS="$CFLAGS -Werror" diff --git a/auto/cc/icc b/auto/cc/icc --- a/auto/cc/icc +++ b/auto/cc/icc @@ -7,7 +7,7 @@ # optimizations CFLAGS="$CFLAGS -O" -# inline functions declared with __inline +# inline the functions declared with __inline #CFLAGS="$CFLAGS -Ob1" # inline any function, at the compiler's discretion CFLAGS="$CFLAGS -Ob2" @@ -54,14 +54,34 @@ fi # warnings -CFLAGS="$CFLAGS -w1" -#CFLAGS="$CFLAGS -w2" +CFLAGS="$CFLAGS -w2" + +# disable some warnings -# disable the ICC 8.1 errors: -# error #181: argument is incompatible with corresponding format -# string conversion -# error #269: invalid format string conversion -CFLAGS="$CFLAGS -wd181 -wd269" +# invalid type conversion: "int" to "char *" +CFLAGS="$CFLAGS -wd171" +# argument is incompatible with corresponding format string conversion +CFLAGS="$CFLAGS -wd181" +# zero used for undefined preprocessing identifier +CFLAGS="$CFLAGS -wd193" +# invalid format string conversion +CFLAGS="$CFLAGS -wd269" +# conversion from "long long" to "size_t" may lose significant bits +CFLAGS="$CFLAGS -wd810" +# parameter was never referenced +CFLAGS="$CFLAGS -wd869" + +# STUB +# enumerated type mixed with another type +CFLAGS="$CFLAGS -wd188" +# controlling expression is constant +CFLAGS="$CFLAGS -wd279" +# operands are evaluated in unspecified order +CFLAGS="$CFLAGS -wd981" +# external definition with no prior declaration +CFLAGS="$CFLAGS -wd1418" +# external declaration in primary source file +CFLAGS="$CFLAGS -wd1419" # stop on warning CFLAGS="$CFLAGS -Werror" diff --git a/auto/lib/openssl/make b/auto/lib/openssl/make --- a/auto/lib/openssl/make +++ b/auto/lib/openssl/make @@ -1,17 +1,28 @@ # Copyright (C) Igor Sysoev +if test -n "$OPENSSL_OPT"; then + NGX_OPENSSL_CONFIG="./Configure \"$OPENSSL_OPT\"" +else + NGX_OPENSSL_CONFIG="./config" +fi + +if test -n "$USE_THREADS"; then + NGX_OPENSSL_CONFIG="$NGX_OPENSSL_CONFIG threads" +fi case "$NGX_PLATFORM" in *) - echo "$OPENSSL/libssl.a:" >> $MAKEFILE - echo " cd $OPENSSL \\" >> $MAKEFILE - echo " && \$(MAKE) clean \\" >> $MAKEFILE - echo " && CC=\"\$(CC)\" \\" >> $MAKEFILE - echo " ./config threads no-shared \\" >> $MAKEFILE - echo " && \$(MAKE)" >> $MAKEFILE + cat << END >> $NGX_MAKEFILE + +$OPENSSL/libssl.a: + cd $OPENSSL \\ + && \$(MAKE) clean \\ + && $NGX_OPENSSL_CONFIG no-shared \\ + && \$(MAKE) + +END + ;; esac - -echo >> $MAKEFILE diff --git a/auto/options b/auto/options --- a/auto/options +++ b/auto/options @@ -153,6 +153,7 @@ do --with-pcre-opt=*) PCRE_OPT="$value" ;; --with-openssl=*) OPENSSL="$value" ;; + --with-openssl-opt=*) OPENSSL_OPT="$value" ;; --with-md5=*) MD5="$value" ;; --with-md5-opt=*) MD5_OPT="$value" ;; @@ -203,6 +204,7 @@ cat << END --with-http_ssl_module enable ngx_http_ssl_module --without-http_charset_module disable ngx_http_charset_module --without-http_gzip_module disable ngx_http_gzip_module + --without-http_ssi_module disable ngx_http_ssi_module --without-http_userid_module disable ngx_http_userid_module --without-http_access_module disable ngx_http_access_module --without-http_autoindex_module disable ngx_http_autoindex_module @@ -241,6 +243,7 @@ cat << END pentium, pentiumpro --with-openssl=DIR set path to OpenSSL library sources + --with-openssl-opt=OPTIONS set additional options for OpenSSL building --with-debug enable the debugging logging diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -241,27 +241,27 @@ HTTP_DEPS="src/http/ngx_http.h \ src/http/ngx_http_variables.h \ src/http/ngx_http_upstream.h \ src/http/ngx_http_busy_lock.h \ - src/http/ngx_http_log_handler.h" + src/http/ngx_http_log_module.h" HTTP_SRCS="src/http/ngx_http.c \ src/http/ngx_http_core_module.c \ src/http/ngx_http_special_response.c \ src/http/ngx_http_request.c \ src/http/ngx_http_parse.c \ - src/http/ngx_http_header_filter.c \ - src/http/ngx_http_write_filter.c \ - src/http/ngx_http_copy_filter.c \ - src/http/ngx_http_log_handler.c \ + src/http/ngx_http_header_filter_module.c \ + src/http/ngx_http_write_filter_module.c \ + src/http/ngx_http_copy_filter_module.c \ + src/http/ngx_http_log_module.c \ src/http/ngx_http_request_body.c \ src/http/ngx_http_variables.c \ src/http/ngx_http_upstream.c \ src/http/ngx_http_parse_time.c \ - src/http/modules/ngx_http_static_handler.c \ - src/http/modules/ngx_http_index_handler.c \ - src/http/modules/ngx_http_chunked_filter.c \ - src/http/modules/ngx_http_range_filter.c \ - src/http/modules/ngx_http_headers_filter.c \ - src/http/modules/ngx_http_not_modified_filter.c" + src/http/modules/ngx_http_static_module.c \ + src/http/modules/ngx_http_index_module.c \ + src/http/modules/ngx_http_chunked_filter_module.c \ + src/http/modules/ngx_http_range_filter_module.c \ + src/http/modules/ngx_http_headers_filter_module.c \ + src/http/modules/ngx_http_not_modified_filter_module.c" # STUB HTTP_SRCS="$HTTP_SRCS src/http/ngx_http_busy_lock.c" @@ -271,31 +271,31 @@ HTPP_FILE_CACHE_SRCS=src/http/ngx_http_f HTTP_CHARSET_FILTER_MODULE=ngx_http_charset_filter_module -HTTP_CHARSET_SRCS=src/http/modules/ngx_http_charset_filter.c +HTTP_CHARSET_SRCS=src/http/modules/ngx_http_charset_filter_module.c HTTP_GZIP_FILTER_MODULE=ngx_http_gzip_filter_module -HTTP_GZIP_SRCS=src/http/modules/ngx_http_gzip_filter.c +HTTP_GZIP_SRCS=src/http/modules/ngx_http_gzip_filter_module.c HTTP_SSI_FILTER_MODULE=ngx_http_ssi_filter_module -HTTP_SSI_SRCS=src/http/modules/ngx_http_ssi_filter.c +HTTP_SSI_SRCS=src/http/modules/ngx_http_ssi_filter_module.c HTTP_USERID_FILTER_MODULE=ngx_http_userid_filter_module -HTTP_USERID_SRCS=src/http/modules/ngx_http_userid_filter.c +HTTP_USERID_SRCS=src/http/modules/ngx_http_userid_filter_module.c HTTP_ACCESS_MODULE=ngx_http_access_module -HTTP_ACCESS_SRCS=src/http/modules/ngx_http_access_handler.c +HTTP_ACCESS_SRCS=src/http/modules/ngx_http_access_module.c HTTP_AUTOINDEX_MODULE=ngx_http_autoindex_module -HTTP_AUTOINDEX_SRCS=src/http/modules/ngx_http_autoindex_handler.c +HTTP_AUTOINDEX_SRCS=src/http/modules/ngx_http_autoindex_module.c HTTP_STATUS_MODULE=ngx_http_status_module -HTTP_STATUS_SRCS=src/http/modules/ngx_http_status_handler.c +HTTP_STATUS_SRCS=src/http/modules/ngx_http_status_module.c HTTP_GEO_MODULE=ngx_http_geo_module @@ -303,7 +303,7 @@ HTTP_GEO_SRCS=src/http/modules/ngx_http_ HTTP_REWRITE_MODULE=ngx_http_rewrite_module -HTTP_REWRITE_SRCS=src/http/modules/ngx_http_rewrite_handler.c +HTTP_REWRITE_SRCS=src/http/modules/ngx_http_rewrite_module.c HTTP_SSL_MODULE=ngx_http_ssl_module @@ -324,7 +324,7 @@ HTTP_PROXY_SRCS="src/http/modules/proxy/ HTTP_FASTCGI_MODULE=ngx_http_fastcgi_module -HTTP_FASTCGI_SRCS=src/http/modules/ngx_http_fastcgi_handler.c +HTTP_FASTCGI_SRCS=src/http/modules/ngx_http_fastcgi_module.c IMAP_INCS="src/imap" diff --git a/auto/summary b/auto/summary --- a/auto/summary +++ b/auto/summary @@ -17,7 +17,7 @@ case $USE_THREADS in esac if [ $USE_PCRE = DISABLED ]; then - echo " + PCRE library is disabled" + echo " + PCRE library is disabled" else case $PCRE in diff --git a/src/core/nginx.c b/src/core/nginx.c --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -141,7 +141,8 @@ main(int argc, char *const *argv) ngx_pid = ngx_getpid(); - if (!(log = ngx_log_init())) { + log = ngx_log_init(); + if (log == NULL) { return 1; } @@ -155,7 +156,8 @@ main(int argc, char *const *argv) init_cycle.log = log; ngx_cycle = &init_cycle; - if (!(init_cycle.pool = ngx_create_pool(1024, log))) { + init_cycle.pool = ngx_create_pool(1024, log); + if (init_cycle.pool == NULL) { return 1; } @@ -255,9 +257,9 @@ main(int argc, char *const *argv) static ngx_int_t ngx_add_inherited_sockets(ngx_cycle_t *cycle) { - u_char *p, *v, *inherited; - ngx_socket_t s; - ngx_listening_t *ls; + u_char *p, *v, *inherited; + ngx_int_t s; + ngx_listening_t *ls; inherited = (u_char *) getenv(NGINX_VAR); @@ -287,11 +289,12 @@ ngx_add_inherited_sockets(ngx_cycle_t *c v = p + 1; - if (!(ls = ngx_array_push(&cycle->listening))) { + ls = ngx_array_push(&cycle->listening); + if (ls == NULL) { return NGX_ERROR; } - ls->fd = s; + ls->fd = (ngx_socket_t) s; } } @@ -315,7 +318,7 @@ ngx_pid_t ngx_exec_new_binary(ngx_cycle_ ctx.argv = argv; var = ngx_alloc(sizeof(NGINX_VAR) - + cycle->listening.nelts * (NGX_INT32_LEN + 1) + 2, + + cycle->listening.nelts * (NGX_INT32_LEN + 1) + 2, cycle->log); p = ngx_cpymem(var, NGINX_VAR "=", sizeof(NGINX_VAR)); @@ -411,27 +414,29 @@ static ngx_int_t ngx_getopt(ngx_cycle_t static ngx_int_t ngx_save_argv(ngx_cycle_t *cycle, int argc, char *const *argv) { +#if (NGX_FREEBSD) + + ngx_os_argv = (char **) argv; + ngx_argc = argc; + ngx_argv = (char **) argv; + +#else size_t len; ngx_int_t i; ngx_os_argv = (char **) argv; - ngx_argc = argc; -#if (NGX_FREEBSD) - - ngx_argv = (char **) argv; - -#else - - if (!(ngx_argv = ngx_alloc((argc + 1) * sizeof(char *), cycle->log))) { + ngx_argv = ngx_alloc((argc + 1) * sizeof(char *), cycle->log); + if (ngx_argv == NULL) { return NGX_ERROR; } for (i = 0; i < argc; i++) { len = ngx_strlen(argv[i]) + 1; - if (!(ngx_argv[i] = ngx_alloc(len, cycle->log))) { + ngx_argv[i] = ngx_alloc(len, cycle->log); + if (ngx_argv[i] == NULL) { return NGX_ERROR; } @@ -451,7 +456,8 @@ ngx_core_module_create_conf(ngx_cycle_t { ngx_core_conf_t *ccf; - if (!(ccf = ngx_pcalloc(cycle->pool, sizeof(ngx_core_conf_t)))) { + ccf = ngx_pcalloc(cycle->pool, sizeof(ngx_core_conf_t)); + if (ccf == NULL) { return NULL; } @@ -534,7 +540,8 @@ ngx_core_module_init_conf(ngx_cycle_t *c ccf->newpid.len = ccf->pid.len + sizeof(NGX_NEWPID_EXT); - if (!(ccf->newpid.data = ngx_palloc(cycle->pool, ccf->newpid.len))) { + ccf->newpid.data = ngx_palloc(cycle->pool, ccf->newpid.len); + if (ccf->newpid.data == NULL) { 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,7 @@ #define _NGINX_H_INCLUDED_ -#define NGINX_VER "nginx/0.1.24" +#define NGINX_VER "nginx/0.1.25" #define NGINX_VAR "NGINX" #define NGX_NEWPID_EXT ".newbin" diff --git a/src/core/ngx_array.c b/src/core/ngx_array.c --- a/src/core/ngx_array.c +++ b/src/core/ngx_array.c @@ -12,11 +12,13 @@ ngx_array_t *ngx_array_create(ngx_pool_t { ngx_array_t *a; - if (!(a = ngx_palloc(p, sizeof(ngx_array_t)))) { + a = ngx_palloc(p, sizeof(ngx_array_t)); + if (a == NULL) { return NULL; } - if (!(a->elts = ngx_palloc(p, n * size))) { + a->elts = ngx_palloc(p, n * size); + if (a->elts == NULL) { return NULL; } @@ -72,7 +74,8 @@ void *ngx_array_push(ngx_array_t *a) } else { /* allocate a new array */ - if (!(new = ngx_palloc(p, 2 * size))) { + new = ngx_palloc(p, 2 * size); + if (new == NULL) { return NULL; } @@ -120,7 +123,8 @@ void *ngx_array_push_n(ngx_array_t *a, n nalloc = 2 * ((n >= a->nalloc) ? n : a->nalloc); - if (!(new = ngx_palloc(p, nalloc * a->size))) { + new = ngx_palloc(p, nalloc * a->size); + if (new == NULL) { return NULL; } diff --git a/src/core/ngx_array.h b/src/core/ngx_array.h --- a/src/core/ngx_array.h +++ b/src/core/ngx_array.h @@ -27,10 +27,11 @@ void *ngx_array_push(ngx_array_t *a); void *ngx_array_push_n(ngx_array_t *a, ngx_uint_t n); -static ngx_inline ngx_int_t ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, - ngx_uint_t n, size_t size) +static ngx_inline ngx_int_t +ngx_array_init(ngx_array_t *array, ngx_pool_t *pool, ngx_uint_t n, size_t size) { - if (!(array->elts = ngx_palloc(pool, n * size))) { + array->elts = ngx_palloc(pool, n * size); + if (array->elts == NULL) { return NGX_ERROR; } @@ -43,14 +44,4 @@ static ngx_inline ngx_int_t ngx_array_in } -/* STUB */ -#define ngx_init_array(a, p, n, s, rc) \ - ngx_test_null(a.elts, ngx_palloc(p, n * s), rc); \ - a.nelts = 0; a.size = s; a.nalloc = n; a.pool = p; - -#define ngx_create_array ngx_array_create -#define ngx_push_array ngx_array_push -/**/ - - #endif /* _NGX_ARRAY_H_INCLUDED_ */ diff --git a/src/core/ngx_buf.c b/src/core/ngx_buf.c --- a/src/core/ngx_buf.c +++ b/src/core/ngx_buf.c @@ -13,11 +13,13 @@ ngx_create_temp_buf(ngx_pool_t *pool, si { ngx_buf_t *b; - if (!(b = ngx_calloc_buf(pool))) { + b = ngx_calloc_buf(pool); + if (b == NULL) { return NULL; } - if (!(b->start = ngx_palloc(pool, size))) { + b->start = ngx_palloc(pool, size); + if (b->start == NULL) { return NULL; } @@ -49,14 +51,17 @@ ngx_create_chain_of_bufs(ngx_pool_t *poo ngx_buf_t *b; ngx_chain_t *chain, *cl, **ll; - if (!(p = ngx_palloc(pool, bufs->num * bufs->size))) { + p = ngx_palloc(pool, bufs->num * bufs->size); + if (p == NULL) { return NULL; } ll = &chain; for (i = 0; i < bufs->num; i++) { - if (!(b = ngx_calloc_buf(pool))) { + + b = ngx_calloc_buf(pool); + if (b == NULL) { return NULL; } @@ -79,7 +84,8 @@ ngx_create_chain_of_bufs(ngx_pool_t *poo p += bufs->size; b->end = p; - if (!(cl = ngx_alloc_chain_link(pool))) { + cl = ngx_alloc_chain_link(pool); + if (cl == NULL) { return NULL; } @@ -106,7 +112,10 @@ ngx_chain_add_copy(ngx_pool_t *pool, ngx } while (in) { - ngx_test_null(cl, ngx_alloc_chain_link(pool), NGX_ERROR); + cl = ngx_alloc_chain_link(pool); + if (cl == NULL) { + return NGX_ERROR; + } cl->buf = in->buf; *ll = cl; diff --git a/src/core/ngx_buf.h b/src/core/ngx_buf.h --- a/src/core/ngx_buf.h +++ b/src/core/ngx_buf.h @@ -119,27 +119,9 @@ ngx_chain_t *ngx_create_chain_of_bufs(ng #define ngx_alloc_buf(pool) ngx_palloc(pool, sizeof(ngx_buf_t)) #define ngx_calloc_buf(pool) ngx_pcalloc(pool, sizeof(ngx_buf_t)) - #define ngx_alloc_chain_link(pool) ngx_palloc(pool, sizeof(ngx_chain_t)) -#define ngx_alloc_link_and_set_buf(chain, b, pool, error) \ - do { \ - ngx_test_null(chain, ngx_alloc_chain_link(pool), error); \ - chain->buf = b; \ - chain->next = NULL; \ - } while (0); - - -#define ngx_chain_add_link(chain, last, cl) \ - if (chain) { \ - *last = cl; \ - } else { \ - chain = cl; \ - } \ - last = &cl->next - - ngx_int_t ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in); ngx_int_t ngx_chain_writer(void *ctx, ngx_chain_t *in); 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 @@ -8,6 +8,7 @@ #include +static ngx_int_t ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last); static char *ngx_conf_include(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -53,13 +54,10 @@ static ngx_int_t ngx_conf_read_token(ngx char *ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename) { - int m, rc, found, valid; char *rv; - void *conf, **confp; ngx_fd_t fd; - ngx_str_t *name; + ngx_int_t rc; ngx_conf_file_t *prev; - ngx_command_t *cmd; #if (NGX_SUPPRESS_WARN) fd = NGX_INVALID_FILE; @@ -78,7 +76,9 @@ char *ngx_conf_parse(ngx_conf_t *cf, ngx } prev = cf->conf_file; - if (!(cf->conf_file = ngx_palloc(cf->pool, sizeof(ngx_conf_file_t)))) { + + cf->conf_file = ngx_palloc(cf->pool, sizeof(ngx_conf_file_t)); + if (cf->conf_file == NULL) { return NGX_CONF_ERROR; } @@ -130,194 +130,30 @@ char *ngx_conf_parse(ngx_conf_t *cf, ngx rv = (*cf->handler)(cf, NULL, cf->handler_conf); if (rv == NGX_CONF_OK) { continue; - - } else if (rv == NGX_CONF_ERROR) { - rc = NGX_ERROR; - break; + } - } else { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "%s in %s:%d", - rv, - cf->conf_file->file.name.data, - cf->conf_file->line); + if (rv == NGX_CONF_ERROR) { rc = NGX_ERROR; break; } - } - name = (ngx_str_t *) cf->args->elts; - found = 0; - - for (m = 0; rc != NGX_ERROR && !found && ngx_modules[m]; m++) { - - /* look up the directive in the appropriate modules */ - - if (ngx_modules[m]->type != NGX_CONF_MODULE - && ngx_modules[m]->type != cf->module_type) - { - continue; - } - - cmd = ngx_modules[m]->commands; - if (cmd == NULL) { - continue; - } - - while (cmd->name.len) { - if (name->len == cmd->name.len - && ngx_strcmp(name->data, cmd->name.data) == 0) - { - - found = 1; - - /* is the directive's location right ? */ - - if ((cmd->type & cf->cmd_type) == 0) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "directive \"%s\" in %s:%d " - "is not allowed here", - name->data, - cf->conf_file->file.name.data, - cf->conf_file->line); - rc = NGX_ERROR; - break; - } - - if (!(cmd->type & NGX_CONF_BLOCK) && rc != NGX_OK) - { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "directive \"%s\" in %s:%d " - "is not terminated by \";\"", - name->data, - cf->conf_file->file.name.data, - cf->conf_file->line); - rc = NGX_ERROR; - break; - } - - if ((cmd->type & NGX_CONF_BLOCK) - && rc != NGX_CONF_BLOCK_START) - { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "directive \"%s\" in %s:%d " - "has not the opening \"{\"", - name->data, - cf->conf_file->file.name.data, - cf->conf_file->line); - rc = NGX_ERROR; - break; - } - - /* is the directive's argument count right ? */ - - if (cmd->type & NGX_CONF_ANY) { - valid = 1; - - } else if (cmd->type & NGX_CONF_FLAG) { - - if (cf->args->nelts == 2) { - valid = 1; - } else { - valid = 0; - } - - } else if (cmd->type & NGX_CONF_1MORE) { - - if (cf->args->nelts > 1) { - valid = 1; - } else { - valid = 0; - } - - } else if (cmd->type & NGX_CONF_2MORE) { - - if (cf->args->nelts > 2) { - valid = 1; - } else { - valid = 0; - } - - } else if (cf->args->nelts <= 10 - && (cmd->type - & argument_number[cf->args->nelts - 1])) - { - valid = 1; - - } else { - valid = 0; - } - - if (!valid) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "invalid number arguments in " - "directive \"%s\" in %s:%d", - name->data, - cf->conf_file->file.name.data, - cf->conf_file->line); - rc = NGX_ERROR; - break; - } - - /* set up the directive's configuration context */ - - conf = NULL; - - if (cmd->type & NGX_DIRECT_CONF) { - conf = ((void **) cf->ctx)[ngx_modules[m]->index]; - - } else if (cmd->type & NGX_MAIN_CONF) { - conf = &(((void **) cf->ctx)[ngx_modules[m]->index]); - - } else if (cf->ctx) { - confp = *(void **) ((char *) cf->ctx + cmd->conf); - - if (confp) { - conf = confp[ngx_modules[m]->ctx_index]; - } - } - - rv = cmd->set(cf, cmd, conf); - - if (rv == NGX_CONF_OK) { - break; - - } else if (rv == NGX_CONF_ERROR) { - rc = NGX_ERROR; - break; - - } else { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "the \"%s\" directive %s in %s:%d", - name->data, rv, - cf->conf_file->file.name.data, - cf->conf_file->line); - - rc = NGX_ERROR; - break; - } - } - - cmd++; - } - } - - if (!found) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "unknown directive \"%s\" in %s:%d", - name->data, - cf->conf_file->file.name.data, - cf->conf_file->line); - + "%s in %s:%d", + rv, cf->conf_file->file.name.data, + cf->conf_file->line); rc = NGX_ERROR; break; } + + rc = ngx_conf_handler(cf, rc); + if (rc == NGX_ERROR) { break; } } + if (filename) { cf->conf_file = prev; @@ -337,6 +173,164 @@ char *ngx_conf_parse(ngx_conf_t *cf, ngx } +static ngx_int_t ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last) +{ + char *rv; + void *conf, **confp; + ngx_uint_t i, valid; + ngx_str_t *name; + ngx_command_t *cmd; + + name = cf->args->elts; + + for (i = 0; ngx_modules[i]; i++) { + + /* look up the directive in the appropriate modules */ + + if (ngx_modules[i]->type != NGX_CONF_MODULE + && ngx_modules[i]->type != cf->module_type) + { + continue; + } + + cmd = ngx_modules[i]->commands; + if (cmd == NULL) { + continue; + } + + while (cmd->name.len) { + + if (name->len == cmd->name.len + && ngx_strcmp(name->data, cmd->name.data) == 0) + { + /* is the directive's location right ? */ + + if (!(cmd->type & cf->cmd_type)) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "directive \"%s\" in %s:%d " + "is not allowed here", + name->data, cf->conf_file->file.name.data, + cf->conf_file->line); + return NGX_ERROR; + } + + if (!(cmd->type & NGX_CONF_BLOCK) && last != NGX_OK) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "directive \"%s\" in %s:%d " + "is not terminated by \";\"", + name->data, cf->conf_file->file.name.data, + cf->conf_file->line); + return NGX_ERROR; + } + + if ((cmd->type & NGX_CONF_BLOCK) + && last != NGX_CONF_BLOCK_START) + { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "directive \"%s\" in %s:%d " + "has not the opening \"{\"", + name->data, cf->conf_file->file.name.data, + cf->conf_file->line); + return NGX_ERROR; + } + + /* is the directive's argument count right ? */ + + if (cmd->type & NGX_CONF_ANY) { + valid = 1; + + } else if (cmd->type & NGX_CONF_FLAG) { + + if (cf->args->nelts == 2) { + valid = 1; + } else { + valid = 0; + } + + } else if (cmd->type & NGX_CONF_1MORE) { + + if (cf->args->nelts > 1) { + valid = 1; + } else { + valid = 0; + } + + } else if (cmd->type & NGX_CONF_2MORE) { + + if (cf->args->nelts > 2) { + valid = 1; + } else { + valid = 0; + } + + } else if (cf->args->nelts <= 10 + && (cmd->type + & argument_number[cf->args->nelts - 1])) + { + valid = 1; + + } else { + valid = 0; + } + + if (!valid) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "invalid number arguments in " + "directive \"%s\" in %s:%d", + name->data, cf->conf_file->file.name.data, + cf->conf_file->line); + return NGX_ERROR; + } + + /* set up the directive's configuration context */ + + conf = NULL; + + if (cmd->type & NGX_DIRECT_CONF) { + conf = ((void **) cf->ctx)[ngx_modules[i]->index]; + + } else if (cmd->type & NGX_MAIN_CONF) { + conf = &(((void **) cf->ctx)[ngx_modules[i]->index]); + + } else if (cf->ctx) { + confp = *(void **) ((char *) cf->ctx + cmd->conf); + + if (confp) { + conf = confp[ngx_modules[i]->ctx_index]; + } + } + + rv = cmd->set(cf, cmd, conf); + + if (rv == NGX_CONF_OK) { + return NGX_OK; + } + + if (rv == NGX_CONF_ERROR) { + return NGX_ERROR; + } + + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "the \"%s\" directive %s in %s:%d", + name->data, rv, cf->conf_file->file.name.data, + cf->conf_file->line); + + return NGX_ERROR; + } + + cmd++; + } + } + + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "unknown directive \"%s\" in %s:%d", + name->data, cf->conf_file->file.name.data, + cf->conf_file->line); + + return NGX_ERROR; +} + + static ngx_int_t ngx_conf_read_token(ngx_conf_t *cf) { u_char *start, ch, *src, *dst; @@ -523,11 +517,13 @@ static ngx_int_t ngx_conf_read_token(ngx } if (found) { - if (!(word = ngx_push_array(cf->args))) { + word = ngx_array_push(cf->args); + if (word == NULL) { return NGX_ERROR; } - if (!(word->data = ngx_palloc(cf->pool, b->pos - start + 1))) { + word->data = ngx_palloc(cf->pool, b->pos - start + 1); + if (word->data == NULL) { return NGX_ERROR; } @@ -623,7 +619,8 @@ ngx_int_t ngx_conf_full_name(ngx_cycle_t name->len = cycle->root.len + old.len; if (cycle->connections) { - if (!(name->data = ngx_palloc(cycle->pool, name->len + 1))) { + name->data = ngx_palloc(cycle->pool, name->len + 1); + if (name->data == NULL) { return NGX_ERROR; } @@ -631,7 +628,8 @@ ngx_int_t ngx_conf_full_name(ngx_cycle_t /* the init_cycle */ - if (!(name->data = ngx_alloc(name->len + 1, cycle->log))) { + name->data = ngx_alloc(name->len + 1, cycle->log); + if (name->data == NULL) { return NGX_ERROR; } } @@ -686,7 +684,8 @@ ngx_open_file_t *ngx_conf_open_file(ngx_ } } - if (!(file = ngx_list_push(&cycle->open_files))) { + file = ngx_list_push(&cycle->open_files); + if (file == NULL) { 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 @@ -20,13 +20,15 @@ ngx_listening_t *ngx_listening_inet_stre ngx_listening_t *ls; struct sockaddr_in *sin; - if (!(ls = ngx_array_push(&cf->cycle->listening))) { + ls = ngx_array_push(&cf->cycle->listening); + if (ls == NULL) { return NULL; } ngx_memzero(ls, sizeof(ngx_listening_t)); - if (!(sin = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in)))) { + sin = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in)); + if (sin == NULL) { return NULL; } @@ -46,7 +48,6 @@ ngx_listening_t *ngx_listening_inet_stre ls->addr_text.len = ngx_sprintf(ls->addr_text.data + len, ":%d", port) - ls->addr_text.data; - ls->fd = (ngx_socket_t) -1; ls->family = AF_INET; ls->type = SOCK_STREAM; 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 @@ -54,15 +54,18 @@ ngx_cycle_t *ngx_init_cycle(ngx_cycle_t log = old_cycle->log; - if (!(pool = ngx_create_pool(16 * 1024, log))) { + pool = ngx_create_pool(16 * 1024, log); + if (pool == NULL) { return NULL; } pool->log = log; - if (!(cycle = ngx_pcalloc(pool, sizeof(ngx_cycle_t)))) { + cycle = ngx_pcalloc(pool, sizeof(ngx_cycle_t)); + if (cycle == NULL) { ngx_destroy_pool(pool); return NULL; } + cycle->pool = pool; cycle->log = log; cycle->old_cycle = old_cycle; @@ -72,10 +75,13 @@ ngx_cycle_t *ngx_init_cycle(ngx_cycle_t n = old_cycle->pathes.nelts ? old_cycle->pathes.nelts : 10; - if (!(cycle->pathes.elts = ngx_pcalloc(pool, n * sizeof(ngx_path_t *)))) { + + cycle->pathes.elts = ngx_pcalloc(pool, n * sizeof(ngx_path_t *)); + if (cycle->pathes.elts == NULL) { ngx_destroy_pool(pool); return NULL; } + cycle->pathes.nelts = 0; cycle->pathes.size = sizeof(ngx_path_t *); cycle->pathes.nalloc = n; @@ -100,7 +106,8 @@ ngx_cycle_t *ngx_init_cycle(ngx_cycle_t } - if (!(cycle->new_log = ngx_log_create_errlog(cycle, NULL))) { + cycle->new_log = ngx_log_create_errlog(cycle, NULL); + if (cycle->new_log == NULL) { ngx_destroy_pool(pool); return NULL; } @@ -109,11 +116,13 @@ ngx_cycle_t *ngx_init_cycle(ngx_cycle_t n = old_cycle->listening.nelts ? old_cycle->listening.nelts : 10; + cycle->listening.elts = ngx_pcalloc(pool, n * sizeof(ngx_listening_t)); if (cycle->listening.elts == NULL) { ngx_destroy_pool(pool); return NULL; } + cycle->listening.nelts = 0; cycle->listening.size = sizeof(ngx_listening_t); cycle->listening.nalloc = n; @@ -147,7 +156,7 @@ ngx_cycle_t *ngx_init_cycle(ngx_cycle_t ngx_memzero(&conf, sizeof(ngx_conf_t)); /* STUB: init array ? */ - conf.args = ngx_create_array(pool, 10, sizeof(ngx_str_t)); + conf.args = ngx_array_create(pool, 10, sizeof(ngx_str_t)); if (conf.args == NULL) { ngx_destroy_pool(pool); return NULL; @@ -516,7 +525,7 @@ ngx_cycle_t *ngx_init_cycle(ngx_cycle_t ngx_temp_pool->log = cycle->log; - old = ngx_push_array(&ngx_old_cycles); + old = ngx_array_push(&ngx_old_cycles); if (old == NULL) { exit(1); } @@ -562,7 +571,7 @@ ngx_int_t ngx_create_pidfile(ngx_cycle_t { ngx_uint_t trunc; size_t len; - u_char *name, pid[NGX_INT64_LEN]; + u_char pid[NGX_INT64_LEN]; ngx_file_t file; ngx_core_conf_t *ccf, *old_ccf; 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 @@ -43,7 +43,8 @@ ngx_create_temp_file(ngx_file_t *file, n file->name.len = path->name.len + 1 + path->len + NGX_ATOMIC_T_LEN; - if (!(file->name.data = ngx_palloc(pool, file->name.len + 1))) { + file->name.data = ngx_palloc(pool, file->name.len + 1); + if (file->name.data == NULL) { return NGX_ERROR; } @@ -203,7 +204,8 @@ ngx_conf_set_path_slot(ngx_conf_t *cf, n return "is duplicate"; } - if (!(path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t)))) { + path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t)); + if (path == NULL) { return NGX_CONF_ERROR; } @@ -292,7 +294,8 @@ ngx_add_path(ngx_conf_t *cf, ngx_path_t } } - if (!(p = ngx_array_push(&cf->cycle->pathes))) { + p = ngx_array_push(&cf->cycle->pathes); + if (p == NULL) { return NGX_ERROR; } 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 @@ -70,7 +70,8 @@ char *ngx_conf_set_path_slot(ngx_conf_t #define ngx_conf_merge_path_value(curr, prev, path, l1, l2, l3, clean, cf) \ if (curr == NULL) { \ if (prev == NULL) { \ - if (!(curr = ngx_palloc(cf->pool, sizeof(ngx_path_t)))) { \ + curr = ngx_palloc(cf->pool, sizeof(ngx_path_t)); \ + if (curr == NULL) { \ return NGX_CONF_ERROR; \ } \ \ diff --git a/src/core/ngx_garbage_collector.c b/src/core/ngx_garbage_collector.c --- a/src/core/ngx_garbage_collector.c +++ b/src/core/ngx_garbage_collector.c @@ -77,7 +77,8 @@ ngx_int_t ngx_collect_garbage(ngx_gc_t * buf.len = dname->len + 1 + len + NGX_DIR_MASK_LEN; - if (!(buf.data = ngx_alloc(buf.len + 1, ctx->log))) { + buf.data = ngx_alloc(buf.len + 1, ctx->log); + if (buf.data == NULL) { return NGX_ABORT; } } 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 @@ -244,7 +244,8 @@ ngx_peers_t *ngx_inet_upstream_parse(ngx u->port = u->default_port_value; - if (!(u->port_text.data = ngx_palloc(cf->pool, sizeof("65536") - 1))) { + u->port_text.data = ngx_palloc(cf->pool, sizeof("65536") - 1); + if (u->port_text.data == NULL) { return NULL; } @@ -271,7 +272,8 @@ ngx_peers_t *ngx_inet_upstream_parse(ngx u->port = htons(u->port); - if (!(host = ngx_palloc(cf->pool, u->host.len + 1))) { + host = ngx_palloc(cf->pool, u->host.len + 1); + if (host == NULL) { return NULL; } @@ -297,7 +299,6 @@ ngx_peers_t *ngx_inet_upstream_parse(ngx peers = ngx_pcalloc(cf->pool, sizeof(ngx_peers_t) + sizeof(ngx_peer_t) * (i - 1)); - if (peers == NULL) { return NULL; } @@ -307,7 +308,8 @@ ngx_peers_t *ngx_inet_upstream_parse(ngx for (i = 0; h->h_addr_list[i] != NULL; i++) { - if (!(sin = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in)))) { + sin = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in)); + if (sin == NULL) { return NULL; } @@ -320,7 +322,8 @@ ngx_peers_t *ngx_inet_upstream_parse(ngx len = INET_ADDRSTRLEN - 1 + 1 + u->port_text.len; - if (!(peers->peer[i].name.data = ngx_palloc(cf->pool, len))) { + peers->peer[i].name.data = ngx_palloc(cf->pool, len); + if (peers->peer[i].name.data == NULL) { return NULL; } @@ -345,11 +348,13 @@ ngx_peers_t *ngx_inet_upstream_parse(ngx /* MP: ngx_shared_palloc() */ - if (!(peers = ngx_pcalloc(cf->pool, sizeof(ngx_peers_t)))) { + peers = ngx_pcalloc(cf->pool, sizeof(ngx_peers_t)); + if (peers == NULL) { return NULL; } - if (!(sin = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in)))) { + sin = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in)); + if (sin == NULL) { return NULL; } @@ -366,7 +371,8 @@ ngx_peers_t *ngx_inet_upstream_parse(ngx peers->peer[0].name.len = len; - if (!(peers->peer[0].name.data = ngx_palloc(cf->pool, len))) { + peers->peer[0].name.data = ngx_palloc(cf->pool, len); + if (peers->peer[0].name.data == NULL) { return NULL; } diff --git a/src/core/ngx_list.c b/src/core/ngx_list.c --- a/src/core/ngx_list.c +++ b/src/core/ngx_list.c @@ -19,11 +19,13 @@ void *ngx_list_push(ngx_list_t *l) /* the last part is full, allocate a new list part */ - if (!(last = ngx_palloc(l->pool, sizeof(ngx_list_part_t)))) { + last = ngx_palloc(l->pool, sizeof(ngx_list_part_t)); + if (last == NULL) { return NULL; } - if (!(last->elts = ngx_palloc(l->pool, l->nalloc * l->size))) { + last->elts = ngx_palloc(l->pool, l->nalloc * l->size); + if (last->elts == NULL) { return NULL; } diff --git a/src/core/ngx_list.h b/src/core/ngx_list.h --- a/src/core/ngx_list.h +++ b/src/core/ngx_list.h @@ -30,10 +30,12 @@ typedef struct { } ngx_list_t; -static ngx_inline ngx_int_t ngx_list_init(ngx_list_t *list, ngx_pool_t *pool, - ngx_uint_t n, size_t size) +static ngx_inline +ngx_int_t ngx_list_init(ngx_list_t *list, ngx_pool_t *pool, ngx_uint_t n, + size_t size) { - if (!(list->part.elts = ngx_palloc(pool, n * size))) { + list->part.elts = ngx_palloc(pool, n * size); + if (list->part.elts == NULL) { return NGX_ERROR; } 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 @@ -253,11 +253,13 @@ ngx_log_t *ngx_log_create_errlog(ngx_cyc name = NULL; } - if (!(log = ngx_pcalloc(cycle->pool, sizeof(ngx_log_t)))) { + log = ngx_pcalloc(cycle->pool, sizeof(ngx_log_t)); + if (log == NULL) { return NULL; } - if (!(log->file = ngx_conf_open_file(cycle, name))) { + log->file = ngx_conf_open_file(cycle, name); + if (log->file == NULL) { return NULL; } diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c --- a/src/core/ngx_output_chain.c +++ b/src/core/ngx_output_chain.c @@ -155,7 +155,8 @@ ngx_output_chain(ngx_output_chain_ctx_t } } - if (!(ctx->buf = ngx_create_temp_buf(ctx->pool, size))) { + ctx->buf = ngx_create_temp_buf(ctx->pool, size); + if (ctx->buf == NULL) { return NGX_ERROR; } @@ -186,9 +187,11 @@ ngx_output_chain(ngx_output_chain_ctx_t ctx->in = ctx->in->next; } - if (!(cl = ngx_alloc_chain_link(ctx->pool))) { + cl = ngx_alloc_chain_link(ctx->pool); + if (cl == NULL) { return NGX_ERROR; } + cl->buf = ctx->buf; cl->next = NULL; *last_out = cl; @@ -269,7 +272,8 @@ ngx_output_chain_add_copy(ngx_pool_t *po while (in) { - if (!(cl = ngx_alloc_chain_link(pool))) { + cl = ngx_alloc_chain_link(pool); + if (cl == NULL) { return NGX_ERROR; } @@ -281,7 +285,8 @@ ngx_output_chain_add_copy(ngx_pool_t *po && buf->file_pos < NGX_SENDFILE_LIMIT && buf->file_last > NGX_SENDFILE_LIMIT) { - if (!(b = ngx_calloc_buf(pool))) { + b = ngx_calloc_buf(pool); + if (b == NULL) { return NGX_ERROR; } @@ -431,9 +436,11 @@ ngx_chain_writer(void *data, ngx_chain_t ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->connection->log, 0, "chain writer buf size: %uz", ngx_buf_size(in->buf)); - if (!(cl = ngx_alloc_chain_link(ctx->pool))) { + cl = ngx_alloc_chain_link(ctx->pool); + if (cl == NULL) { return NGX_ERROR; } + cl->buf = in->buf; cl->next = NULL; *ctx->last = cl; 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 @@ -8,11 +8,13 @@ #include -ngx_pool_t *ngx_create_pool(size_t size, ngx_log_t *log) +ngx_pool_t * +ngx_create_pool(size_t size, ngx_log_t *log) { ngx_pool_t *p; - if (!(p = ngx_alloc(size, log))) { + p = ngx_alloc(size, log); + if (p == NULL) { return NULL; } @@ -26,7 +28,8 @@ ngx_pool_t *ngx_create_pool(size_t size, } -void ngx_destroy_pool(ngx_pool_t *pool) +void +ngx_destroy_pool(ngx_pool_t *pool) { ngx_pool_t *p, *n; ngx_pool_large_t *l; @@ -68,7 +71,8 @@ void ngx_destroy_pool(ngx_pool_t *pool) } -void *ngx_palloc(ngx_pool_t *pool, size_t size) +void * +ngx_palloc(ngx_pool_t *pool, size_t size) { u_char *m; ngx_pool_t *p, *n; @@ -94,7 +98,8 @@ void *ngx_palloc(ngx_pool_t *pool, size_ /* allocate a new pool block */ - if (!(n = ngx_create_pool((size_t) (p->end - (u_char *) p), p->log))) { + n = ngx_create_pool((size_t) (p->end - (u_char *) p), p->log); + if (n == NULL) { return NULL; } @@ -125,7 +130,8 @@ void *ngx_palloc(ngx_pool_t *pool, size_ } if (large == NULL) { - if (!(large = ngx_palloc(pool, sizeof(ngx_pool_large_t)))) { + large = ngx_palloc(pool, sizeof(ngx_pool_large_t)); + if (large == NULL) { return NULL; } @@ -133,11 +139,13 @@ void *ngx_palloc(ngx_pool_t *pool, size_ } #if 0 - if (!(p = ngx_memalign(ngx_pagesize, size, pool->log))) { + p = ngx_memalign(ngx_pagesize, size, pool->log); + if (p == NULL) { return NULL; } #else - if (!(p = ngx_alloc(size, pool->log))) { + p = ngx_alloc(size, pool->log); + if (p == NULL) { return NULL; } #endif @@ -155,7 +163,8 @@ void *ngx_palloc(ngx_pool_t *pool, size_ } -ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p) +ngx_int_t +ngx_pfree(ngx_pool_t *pool, void *p) { ngx_pool_large_t *l; @@ -174,7 +183,8 @@ ngx_int_t ngx_pfree(ngx_pool_t *pool, vo } -void *ngx_pcalloc(ngx_pool_t *pool, size_t size) +void * +ngx_pcalloc(ngx_pool_t *pool, size_t size) { void *p; @@ -188,7 +198,8 @@ void *ngx_pcalloc(ngx_pool_t *pool, size #if 0 -static void *ngx_get_cached_block(size_t size) +static void * +ngx_get_cached_block(size_t size) { void *p; ngx_cached_block_slot_t *slot; 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 @@ -21,8 +21,6 @@ #define NGX_DEFAULT_POOL_SIZE (16 * 1024) -#define ngx_test_null(p, alloc, rc) if ((p = alloc) == NULL) { return rc; } - typedef struct ngx_pool_large_s ngx_pool_large_t; diff --git a/src/core/ngx_radix_tree.c b/src/core/ngx_radix_tree.c --- a/src/core/ngx_radix_tree.c +++ b/src/core/ngx_radix_tree.c @@ -17,7 +17,8 @@ ngx_radix_tree_create(ngx_pool_t *pool, uint32_t key, mask, inc; ngx_radix_tree_t *tree; - if (!(tree = ngx_palloc(pool, sizeof(ngx_radix_tree_t)))) { + tree = ngx_palloc(pool, sizeof(ngx_radix_tree_t)); + if (tree == NULL) { return NULL; } @@ -26,7 +27,8 @@ ngx_radix_tree_create(ngx_pool_t *pool, tree->start = NULL; tree->size = 0; - if (!(tree->root = ngx_radix_alloc(tree))) { + tree->root = ngx_radix_alloc(tree); + if (tree->root == NULL) { return NULL; } @@ -140,7 +142,8 @@ ngx_radix32tree_insert(ngx_radix_tree_t } while (bit & mask) { - if (!(next = ngx_radix_alloc(tree))) { + next = ngx_radix_alloc(tree); + if (next == NULL) { return NGX_ERROR; } @@ -266,7 +269,8 @@ ngx_radix_alloc(ngx_radix_tree_t *tree) } if (tree->size < sizeof(ngx_radix_node_t)) { - if (!(tree->start = ngx_palloc(tree->pool, ngx_pagesize))) { + tree->start = ngx_palloc(tree->pool, ngx_pagesize); + if (tree->start == NULL) { return NULL; } diff --git a/src/core/ngx_regex.c b/src/core/ngx_regex.c --- a/src/core/ngx_regex.c +++ b/src/core/ngx_regex.c @@ -79,7 +79,7 @@ ngx_regex_t *ngx_regex_compile(ngx_str_t } -ngx_uint_t ngx_regex_capture_count(ngx_regex_t *re) +ngx_int_t ngx_regex_capture_count(ngx_regex_t *re) { int rc, n; @@ -87,7 +87,11 @@ ngx_uint_t ngx_regex_capture_count(ngx_r rc = pcre_fullinfo(re, NULL, PCRE_INFO_CAPTURECOUNT, &n); - return (ngx_uint_t) n; + if (rc < 0) { + return (ngx_int_t) rc; + } + + return (ngx_int_t) n; } diff --git a/src/core/ngx_regex.h b/src/core/ngx_regex.h --- a/src/core/ngx_regex.h +++ b/src/core/ngx_regex.h @@ -23,11 +23,12 @@ typedef pcre ngx_regex_t; void ngx_regex_init(void); ngx_regex_t *ngx_regex_compile(ngx_str_t *pattern, ngx_int_t options, ngx_pool_t *pool, ngx_str_t *err); -ngx_uint_t ngx_regex_capture_count(ngx_regex_t *re); +ngx_int_t ngx_regex_capture_count(ngx_regex_t *re); ngx_int_t ngx_regex_exec(ngx_regex_t *re, ngx_str_t *s, int *captures, ngx_int_t size); -#define ngx_regex_exec_n "pcre_exec()" +#define ngx_regex_exec_n "pcre_exec()" +#define ngx_regex_capture_count_n "pcre_fullinfo()" #endif /* _NGX_REGEX_H_INCLUDED_ */ diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -34,7 +34,8 @@ ngx_pstrdup(ngx_pool_t *pool, ngx_str_t { u_char *dst; - if (!(dst = ngx_palloc(pool, src->len))) { + dst = ngx_palloc(pool, src->len); + if (dst == NULL) { return NULL; } @@ -489,6 +490,84 @@ ngx_atoi(u_char *line, size_t n) } +ssize_t +ngx_atosz(u_char *line, size_t n) +{ + ssize_t value; + + if (n == 0) { + return NGX_ERROR; + } + + for (value = 0; n--; line++) { + if (*line < '0' || *line > '9') { + return NGX_ERROR; + } + + value = value * 10 + (*line - '0'); + } + + if (value < 0) { + return NGX_ERROR; + + } else { + return value; + } +} + + +off_t +ngx_atoof(u_char *line, size_t n) +{ + off_t value; + + if (n == 0) { + return NGX_ERROR; + } + + for (value = 0; n--; line++) { + if (*line < '0' || *line > '9') { + return NGX_ERROR; + } + + value = value * 10 + (*line - '0'); + } + + if (value < 0) { + return NGX_ERROR; + + } else { + return value; + } +} + + +time_t +ngx_atotm(u_char *line, size_t n) +{ + time_t value; + + if (n == 0) { + return NGX_ERROR; + } + + for (value = 0; n--; line++) { + if (*line < '0' || *line > '9') { + return NGX_ERROR; + } + + value = value * 10 + (*line - '0'); + } + + if (value < 0) { + return NGX_ERROR; + + } else { + return value; + } +} + + ngx_int_t ngx_hextoi(u_char *line, size_t n) { diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h --- a/src/core/ngx_string.h +++ b/src/core/ngx_string.h @@ -23,6 +23,7 @@ typedef struct { #define ngx_tolower(c) (u_char) ((c >= 'A' && c <= 'Z') ? (c | 0x20) : c) +#define ngx_toupper(c) (u_char) ((c >= 'a' && c <= 'z') ? (c & ~0x20) : c) #if (NGX_WIN32) @@ -81,6 +82,9 @@ ngx_int_t ngx_rstrncmp(u_char *s1, u_cha ngx_int_t ngx_rstrncasecmp(u_char *s1, u_char *s2, size_t n); ngx_int_t ngx_atoi(u_char *line, size_t n); +ssize_t ngx_atosz(u_char *line, size_t n); +off_t ngx_atoof(u_char *line, size_t n); +time_t ngx_atotm(u_char *line, size_t n); ngx_int_t ngx_hextoi(u_char *line, size_t n); void ngx_md5_text(u_char *text, u_char *md5); diff --git a/src/core/ngx_times.c b/src/core/ngx_times.c --- a/src/core/ngx_times.c +++ b/src/core/ngx_times.c @@ -70,8 +70,8 @@ static char *week[] = { "Sun", "Mon", " static char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - -void ngx_time_init(void) +void +ngx_time_init(void) { struct timeval tv; @@ -104,9 +104,12 @@ void ngx_time_init(void) #if (NGX_THREADS) -ngx_int_t ngx_time_mutex_init(ngx_log_t *log) +ngx_int_t +ngx_time_mutex_init(ngx_log_t *log) { - if (!(ngx_time_mutex = ngx_mutex_init(log, NGX_MUTEX_LIGHT))) { + ngx_time_mutex = ngx_mutex_init(log, NGX_MUTEX_LIGHT); + + if (ngx_time_mutex == NULL) { return NGX_ERROR; } @@ -116,7 +119,8 @@ ngx_int_t ngx_time_mutex_init(ngx_log_t #endif -void ngx_time_update(time_t s) +void +ngx_time_update(time_t s) { u_char *p; ngx_tm_t tm; @@ -209,7 +213,8 @@ void ngx_time_update(time_t s) } -u_char *ngx_http_time(u_char *buf, time_t t) +u_char * +ngx_http_time(u_char *buf, time_t t) { ngx_tm_t tm; @@ -226,7 +231,8 @@ u_char *ngx_http_time(u_char *buf, time_ } -u_char *ngx_http_cookie_time(u_char *buf, time_t t) +u_char * +ngx_http_cookie_time(u_char *buf, time_t t) { ngx_tm_t tm; @@ -252,7 +258,8 @@ u_char *ngx_http_cookie_time(u_char *buf } -void ngx_gmtime(time_t t, ngx_tm_t *tp) +void +ngx_gmtime(time_t t, ngx_tm_t *tp) { ngx_int_t sec, min, hour, mday, mon, year, wday, yday, days; diff --git a/src/core/ngx_unix_domain.c b/src/core/ngx_unix_domain.c --- a/src/core/ngx_unix_domain.c +++ b/src/core/ngx_unix_domain.c @@ -59,11 +59,13 @@ ngx_peers_t *ngx_unix_upstream_parse(ngx /* MP: ngx_shared_palloc() */ - if (!(peers = ngx_pcalloc(cf->pool, sizeof(ngx_peers_t)))) { + peers = ngx_pcalloc(cf->pool, sizeof(ngx_peers_t)); + if (peers == NULL) { return NULL; } - if (!(sun = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_un)))) { + sun = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_un)); + if (sun == NULL) { return NULL; } diff --git a/src/event/modules/ngx_devpoll_module.c b/src/event/modules/ngx_devpoll_module.c --- a/src/event/modules/ngx_devpoll_module.c +++ b/src/event/modules/ngx_devpoll_module.c @@ -134,19 +134,21 @@ ngx_devpoll_init(ngx_cycle_t *cycle) ngx_free(change_list); } - ngx_test_null(change_list, - ngx_alloc(sizeof(struct pollfd) * dpcf->changes, - cycle->log), - NGX_ERROR); + change_list = ngx_alloc(sizeof(struct pollfd) * dpcf->changes, + cycle->log); + if (change_list == NULL) { + return NGX_ERROR; + } if (change_index) { ngx_free(change_index); } - ngx_test_null(change_index, - ngx_alloc(sizeof(ngx_event_t *) * dpcf->changes, - cycle->log), - NGX_ERROR); + change_index = ngx_alloc(sizeof(ngx_event_t *) * dpcf->changes, + cycle->log); + if (change_index == NULL) { + return NGX_ERROR; + } } max_changes = dpcf->changes; @@ -156,10 +158,11 @@ ngx_devpoll_init(ngx_cycle_t *cycle) ngx_free(event_list); } - ngx_test_null(event_list, - ngx_alloc(sizeof(struct pollfd) * dpcf->events, - cycle->log), - NGX_ERROR); + event_list = ngx_alloc(sizeof(struct pollfd) * dpcf->events, + cycle->log); + if (event_list == NULL) { + return NGX_ERROR; + } } nevents = dpcf->events; @@ -318,11 +321,13 @@ ngx_devpoll_process_events(ngx_cycle_t * { int events, revents; ngx_int_t i; - ngx_uint_t j, lock, accept_lock, expire; + ngx_uint_t lock, accept_lock, expire; size_t n; ngx_msec_t timer; ngx_err_t err; +#if 0 ngx_cycle_t **old_cycle; +#endif ngx_event_t *rev, *wev; ngx_connection_t *c; ngx_epoch_msec_t delta; @@ -580,8 +585,10 @@ ngx_devpoll_create_conf(ngx_cycle_t *cyc { ngx_devpoll_conf_t *dpcf; - ngx_test_null(dpcf, ngx_palloc(cycle->pool, sizeof(ngx_devpoll_conf_t)), - NGX_CONF_ERROR); + dpcf = ngx_palloc(cycle->pool, sizeof(ngx_devpoll_conf_t)); + if (dpcf == NULL) { + return NGX_CONF_ERROR; + } dpcf->changes = NGX_CONF_UNSET; dpcf->events = NGX_CONF_UNSET; diff --git a/src/event/modules/ngx_epoll_module.c b/src/event/modules/ngx_epoll_module.c --- a/src/event/modules/ngx_epoll_module.c +++ b/src/event/modules/ngx_epoll_module.c @@ -133,7 +133,6 @@ ngx_module_t ngx_epoll_module = { static ngx_int_t ngx_epoll_init(ngx_cycle_t *cycle) { - size_t n; ngx_event_conf_t *ecf; ngx_epoll_conf_t *epcf; @@ -380,7 +379,6 @@ static ngx_int_t ngx_epoll_process_events(ngx_cycle_t *cycle) { int events; - size_t n; uint32_t revents; ngx_int_t instance, i; ngx_uint_t lock, accept_lock, expire; @@ -663,8 +661,10 @@ ngx_epoll_create_conf(ngx_cycle_t *cycle { ngx_epoll_conf_t *epcf; - ngx_test_null(epcf, ngx_palloc(cycle->pool, sizeof(ngx_epoll_conf_t)), - NGX_CONF_ERROR); + epcf = ngx_palloc(cycle->pool, sizeof(ngx_epoll_conf_t)); + if (epcf == NULL) { + return NGX_CONF_ERROR; + } epcf->events = NGX_CONF_UNSET; diff --git a/src/event/modules/ngx_kqueue_module.c b/src/event/modules/ngx_kqueue_module.c --- a/src/event/modules/ngx_kqueue_module.c +++ b/src/event/modules/ngx_kqueue_module.c @@ -123,11 +123,13 @@ ngx_kqueue_init(ngx_cycle_t *cycle) #if (NGX_THREADS) - if (!(list_mutex = ngx_mutex_init(cycle->log, 0))) { + list_mutex = ngx_mutex_init(cycle->log, 0); + if (list_mutex == NULL) { return NGX_ERROR; } - if (!(kevent_mutex = ngx_mutex_init(cycle->log, 0))) { + kevent_mutex = ngx_mutex_init(cycle->log, 0); + if (kevent_mutex == NULL) { return NGX_ERROR; } @@ -797,8 +799,10 @@ ngx_kqueue_create_conf(ngx_cycle_t *cycl { ngx_kqueue_conf_t *kcf; - ngx_test_null(kcf, ngx_palloc(cycle->pool, sizeof(ngx_kqueue_conf_t)), - NGX_CONF_ERROR); + kcf = ngx_palloc(cycle->pool, sizeof(ngx_kqueue_conf_t)); + if (kcf == NULL) { + return NGX_CONF_ERROR; + } kcf->changes = NGX_CONF_UNSET; kcf->events = NGX_CONF_UNSET; diff --git a/src/event/modules/ngx_poll_module.c b/src/event/modules/ngx_poll_module.c --- a/src/event/modules/ngx_poll_module.c +++ b/src/event/modules/ngx_poll_module.c @@ -73,10 +73,11 @@ ngx_poll_init(ngx_cycle_t *cycle) || cycle->old_cycle == NULL || cycle->old_cycle->connection_n < cycle->connection_n) { - ngx_test_null(list, - ngx_alloc(sizeof(struct pollfd) * cycle->connection_n, - cycle->log), - NGX_ERROR); + list = ngx_alloc(sizeof(struct pollfd) * cycle->connection_n, + cycle->log); + if (list == NULL) { + return NGX_ERROR; + } if (event_list) { ngx_memcpy(list, event_list, sizeof(ngx_event_t *) * nevents); @@ -90,10 +91,11 @@ ngx_poll_init(ngx_cycle_t *cycle) ngx_free(ready_index); } - ngx_test_null(ready_index, - ngx_alloc(sizeof(ngx_event_t *) * 2 * cycle->connection_n, - cycle->log), - NGX_ERROR); + ready_index = ngx_alloc(sizeof(ngx_event_t *) * 2 * cycle->connection_n, + cycle->log); + if (ready_index == NULL) { + return NGX_ERROR; + } #endif } diff --git a/src/event/modules/ngx_rtsig_module.c b/src/event/modules/ngx_rtsig_module.c --- a/src/event/modules/ngx_rtsig_module.c +++ b/src/event/modules/ngx_rtsig_module.c @@ -274,9 +274,8 @@ static ngx_int_t ngx_rtsig_process_events(ngx_cycle_t *cycle) { int signo; - ngx_int_t instance, i; + ngx_int_t instance; ngx_uint_t expire; - size_t n; ngx_msec_t timer; ngx_err_t err; siginfo_t si; @@ -777,8 +776,10 @@ ngx_rtsig_create_conf(ngx_cycle_t *cycle { ngx_rtsig_conf_t *rtscf; - ngx_test_null(rtscf, ngx_palloc(cycle->pool, sizeof(ngx_rtsig_conf_t)), - NGX_CONF_ERROR); + rtscf = ngx_palloc(cycle->pool, sizeof(ngx_rtsig_conf_t)); + if (rtscf == NULL) { + return NGX_CONF_ERROR; + } rtscf->signo = NGX_CONF_UNSET; rtscf->overflow_events = NGX_CONF_UNSET; diff --git a/src/event/modules/ngx_select_module.c b/src/event/modules/ngx_select_module.c --- a/src/event/modules/ngx_select_module.c +++ b/src/event/modules/ngx_select_module.c @@ -72,7 +72,8 @@ ngx_module_t ngx_select_module = { }; -static ngx_int_t ngx_select_init(ngx_cycle_t *cycle) +static ngx_int_t +ngx_select_init(ngx_cycle_t *cycle) { ngx_event_t **index; @@ -86,10 +87,11 @@ static ngx_int_t ngx_select_init(ngx_cyc || cycle->old_cycle == NULL || cycle->old_cycle->connection_n < cycle->connection_n) { - ngx_test_null(index, - ngx_alloc(sizeof(ngx_event_t *) * 2 * cycle->connection_n, - cycle->log), - NGX_ERROR); + index = ngx_alloc(sizeof(ngx_event_t *) * 2 * cycle->connection_n, + cycle->log); + if (index == NULL) { + return NGX_ERROR; + } if (event_index) { ngx_memcpy(index, event_index, sizeof(ngx_event_t *) * nevents); @@ -101,10 +103,12 @@ static ngx_int_t ngx_select_init(ngx_cyc if (ready_index) { ngx_free(ready_index); } - ngx_test_null(ready_index, - ngx_alloc(sizeof(ngx_event_t *) * 2 * cycle->connection_n, - cycle->log), - NGX_ERROR); + + ready_index = ngx_alloc(sizeof(ngx_event_t *) * 2 * cycle->connection_n, + cycle->log); + if (ready_index == NULL) { + return NGX_ERROR; + } #endif } @@ -124,7 +128,8 @@ static ngx_int_t ngx_select_init(ngx_cyc } -static void ngx_select_done(ngx_cycle_t *cycle) +static void +ngx_select_done(ngx_cycle_t *cycle) { ngx_free(event_index); #if 0 @@ -135,7 +140,8 @@ static void ngx_select_done(ngx_cycle_t } -static ngx_int_t ngx_select_add_event(ngx_event_t *ev, int event, u_int flags) +static ngx_int_t +ngx_select_add_event(ngx_event_t *ev, int event, u_int flags) { ngx_connection_t *c; @@ -196,7 +202,8 @@ static ngx_int_t ngx_select_add_event(ng } -static ngx_int_t ngx_select_del_event(ngx_event_t *ev, int event, u_int flags) +static ngx_int_t +ngx_select_del_event(ngx_event_t *ev, int event, u_int flags) { ngx_connection_t *c; @@ -248,7 +255,8 @@ static ngx_int_t ngx_select_del_event(ng } -static ngx_int_t ngx_select_process_events(ngx_cycle_t *cycle) +static ngx_int_t +ngx_select_process_events(ngx_cycle_t *cycle) { int ready, nready; ngx_uint_t i, found, lock, expire; @@ -592,7 +600,8 @@ static ngx_int_t ngx_select_process_even } -static char *ngx_select_init_conf(ngx_cycle_t *cycle, void *conf) +static char * +ngx_select_init_conf(ngx_cycle_t *cycle, void *conf) { ngx_event_conf_t *ecf; 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 @@ -219,7 +219,8 @@ static ngx_int_t ngx_event_module_init(n #endif - if (!(shared = ngx_create_shared_memory(size, cycle->log))) { + shared = ngx_create_shared_memory(size, cycle->log); + if (shared == NULL) { return NGX_ERROR; } @@ -272,7 +273,8 @@ static ngx_int_t ngx_event_process_init( } #if (NGX_THREADS) - if (!(ngx_posted_events_mutex = ngx_mutex_init(cycle->log, 0))) { + ngx_posted_events_mutex = ngx_mutex_init(cycle->log, 0); + if (ngx_posted_events_mutex == NULL) { return NGX_ERROR; } #endif @@ -497,42 +499,47 @@ ngx_int_t ngx_send_lowat(ngx_connection_ static char *ngx_events_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - int m; - char *rv; + char *rv; void ***ctx; + ngx_uint_t i; ngx_conf_t pcf; - ngx_event_module_t *module; + ngx_event_module_t *m; /* count the number of the event modules and set up their indices */ ngx_event_max_module = 0; - for (m = 0; ngx_modules[m]; m++) { - if (ngx_modules[m]->type != NGX_EVENT_MODULE) { + for (i = 0; ngx_modules[i]; i++) { + if (ngx_modules[i]->type != NGX_EVENT_MODULE) { continue; } - ngx_modules[m]->ctx_index = ngx_event_max_module++; + ngx_modules[i]->ctx_index = ngx_event_max_module++; } - ngx_test_null(ctx, ngx_pcalloc(cf->pool, sizeof(void *)), NGX_CONF_ERROR); + ctx = ngx_pcalloc(cf->pool, sizeof(void *)); + if (ctx == NULL) { + return NGX_CONF_ERROR; + } - ngx_test_null(*ctx, - ngx_pcalloc(cf->pool, ngx_event_max_module * sizeof(void *)), - NGX_CONF_ERROR); + *ctx = ngx_pcalloc(cf->pool, ngx_event_max_module * sizeof(void *)); + if (*ctx == NULL) { + return NGX_CONF_ERROR; + } *(void **) conf = ctx; - for (m = 0; ngx_modules[m]; m++) { - if (ngx_modules[m]->type != NGX_EVENT_MODULE) { + for (i = 0; ngx_modules[i]; i++) { + if (ngx_modules[i]->type != NGX_EVENT_MODULE) { continue; } - module = ngx_modules[m]->ctx; + m = ngx_modules[i]->ctx; - if (module->create_conf) { - ngx_test_null((*ctx)[ngx_modules[m]->ctx_index], - module->create_conf(cf->cycle), - NGX_CONF_ERROR); + if (m->create_conf) { + (*ctx)[ngx_modules[i]->ctx_index] = m->create_conf(cf->cycle); + if ((*ctx)[ngx_modules[i]->ctx_index] == NULL) { + return NGX_CONF_ERROR; + } } } @@ -540,22 +547,23 @@ static char *ngx_events_block(ngx_conf_t cf->ctx = ctx; cf->module_type = NGX_EVENT_MODULE; cf->cmd_type = NGX_EVENT_CONF; + rv = ngx_conf_parse(cf, NULL); + *cf = pcf; if (rv != NGX_CONF_OK) return rv; - for (m = 0; ngx_modules[m]; m++) { - if (ngx_modules[m]->type != NGX_EVENT_MODULE) { + for (i = 0; ngx_modules[i]; i++) { + if (ngx_modules[i]->type != NGX_EVENT_MODULE) { continue; } - module = ngx_modules[m]->ctx; + m = ngx_modules[i]->ctx; - if (module->init_conf) { - rv = module->init_conf(cf->cycle, - (*ctx)[ngx_modules[m]->ctx_index]); + if (m->init_conf) { + rv = m->init_conf(cf->cycle, (*ctx)[ngx_modules[i]->ctx_index]); if (rv != NGX_CONF_OK) { return rv; } @@ -668,7 +676,8 @@ static char *ngx_event_debug_connection( /* AF_INET only */ - if (!(addr = ngx_push_array(&ecf->debug_connection))) { + addr = ngx_array_push(&ecf->debug_connection); + if (addr == NULL) { return NGX_CONF_ERROR; } @@ -704,8 +713,10 @@ static void *ngx_event_create_conf(ngx_c { ngx_event_conf_t *ecf; - ngx_test_null(ecf, ngx_palloc(cycle->pool, sizeof(ngx_event_conf_t)), - NGX_CONF_ERROR); + ecf = ngx_palloc(cycle->pool, sizeof(ngx_event_conf_t)); + if (ecf == NULL) { + return NGX_CONF_ERROR; + } ecf->connections = NGX_CONF_UNSET_UINT; ecf->use = NGX_CONF_UNSET_UINT; @@ -715,8 +726,13 @@ static void *ngx_event_create_conf(ngx_c ecf->name = (void *) NGX_CONF_UNSET; #if (NGX_DEBUG) - ngx_init_array(ecf->debug_connection, cycle->pool, 4, sizeof(in_addr_t), - NGX_CONF_ERROR); + + if (ngx_array_init(&ecf->debug_connection, cycle->pool, 4, + sizeof(in_addr_t)) == NGX_ERROR) + { + return NGX_CONF_ERROR; + } + #endif return ecf; @@ -727,7 +743,12 @@ static char *ngx_event_init_conf(ngx_cyc { ngx_event_conf_t *ecf = conf; - int fd, rtsig; +#if (NGX_HAVE_EPOLL) && !(NGX_TEST_BUILD_EPOLL) + int fd; +#endif +#if (NGX_HAVE_RTSIG) + ngx_uint_t rtsig; +#endif ngx_int_t i, connections; ngx_module_t *module; ngx_core_conf_t *ccf; @@ -735,8 +756,6 @@ static char *ngx_event_init_conf(ngx_cyc connections = NGX_CONF_UNSET_UINT; module = NULL; - rtsig = 0; - fd = 0; #if (NGX_HAVE_EPOLL) && !(NGX_TEST_BUILD_EPOLL) @@ -760,6 +779,9 @@ static char *ngx_event_init_conf(ngx_cyc connections = DEFAULT_CONNECTIONS; module = &ngx_rtsig_module; rtsig = 1; + + } else { + rtsig = 0; } #endif @@ -782,11 +804,10 @@ static char *ngx_event_init_conf(ngx_cyc if (module == NULL) { -#if (NGX_WIN32) +#if (NGX_WIN32 || FD_SETSIZE >= DEFAULT_CONNECTIONS) connections = DEFAULT_CONNECTIONS; #else - connections = FD_SETSIZE < DEFAULT_CONNECTIONS ? FD_SETSIZE: - DEFAULT_CONNECTIONS; + connections = FD_SETSIZE; #endif module = &ngx_select_module; } @@ -828,7 +849,15 @@ static char *ngx_event_init_conf(ngx_cyc ngx_conf_init_msec_value(ecf->accept_mutex_delay, 500); - if (!rtsig || ecf->accept_mutex) { +#if (NGX_HAVE_RTSIG) + + if (!rtsig) { + return NGX_CONF_OK; + } + +#endif + + if (ecf->accept_mutex) { 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 @@ -16,7 +16,10 @@ static u_char *ngx_accept_log_error(ngx_ void ngx_event_accept(ngx_event_t *ev) { - ngx_uint_t instance, accepted; + ngx_uint_t instance; +#if 0 + ngx_uint_t accepted; +#endif socklen_t len; struct sockaddr *sa; ngx_err_t err; @@ -43,8 +46,10 @@ ngx_event_accept(ngx_event_t *ev) &ls->listening->addr_text, ev->available); ev->ready = 0; + pool = NULL; +#if 0 accepted = 0; - pool = NULL; +#endif do { @@ -56,17 +61,20 @@ ngx_event_accept(ngx_event_t *ev) * case and besides the pool can be got from the free pool list. */ - if (!(pool = ngx_create_pool(ls->listening->pool_size, ev->log))) { + pool = ngx_create_pool(ls->listening->pool_size, ev->log); + if (pool == NULL) { return; } } - if (!(sa = ngx_palloc(pool, ls->listening->socklen))) { + sa = ngx_palloc(pool, ls->listening->socklen); + if (sa == NULL) { ngx_destroy_pool(pool); return; } - if (!(log = ngx_palloc(pool, sizeof(ngx_log_t)))) { + log = ngx_palloc(pool, sizeof(ngx_log_t)); + if (log == NULL) { ngx_destroy_pool(pool); return; } @@ -331,7 +339,9 @@ ngx_event_accept(ngx_event_t *ev) ev->available--; } +#if 0 accepted++; +#endif } while (ev->available); } 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 @@ -20,8 +20,6 @@ static void ngx_ssl_read_handler(ngx_eve ngx_int_t ngx_ssl_init(ngx_log_t *log) { - ENGINE *engine; - SSL_library_init(); SSL_load_error_strings(); ENGINE_load_builtin_engines(); @@ -36,11 +34,13 @@ ngx_ssl_create_session(ngx_ssl_ctx_t *ss { ngx_ssl_t *ssl; - if (!(ssl = ngx_pcalloc(c->pool, sizeof(ngx_ssl_t)))) { + ssl = ngx_pcalloc(c->pool, sizeof(ngx_ssl_t)); + if (ssl == NULL) { return NGX_ERROR; } - if (!(ssl->buf = ngx_create_temp_buf(c->pool, NGX_SSL_BUFSIZE))) { + ssl->buf = ngx_create_temp_buf(c->pool, NGX_SSL_BUFSIZE); + if (ssl->buf == NULL) { return NGX_ERROR; } @@ -586,7 +586,7 @@ ngx_ssl_error(ngx_uint_t level, ngx_log_ p = ngx_vsnprintf(errstr, sizeof(errstr) - 1, fmt, args); va_end(args); - p = ngx_cpystrn(p, " (SSL: ", last - p); + p = ngx_cpystrn(p, (u_char *) " (SSL: ", last - p); ERR_error_string_n(ERR_get_error(), (char *) p, last - p); 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 @@ -165,13 +165,15 @@ static ngx_int_t ngx_event_pipe_read_ups /* allocate a new buf if it's still allowed */ - if (!(b = ngx_create_temp_buf(p->pool, p->bufs.size))) { + b = ngx_create_temp_buf(p->pool, p->bufs.size); + if (b == NULL) { return NGX_ABORT; } p->allocated++; - if (!(chain = ngx_alloc_chain_link(p->pool))) { + chain = ngx_alloc_chain_link(p->pool); + if (chain == NULL) { return NGX_ABORT; } @@ -495,7 +497,13 @@ static ngx_int_t ngx_event_pipe_write_to } cl->next = NULL; - ngx_chain_add_link(out, ll, cl); + + if (out) { + *ll = cl; + } else { + out = cl; + } + ll = &cl->next; } ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0, @@ -635,11 +643,17 @@ static ngx_int_t ngx_event_pipe_write_ch b->in_file = 1; b->temp_file = 1; - ngx_chain_add_link(p->out, p->last_out, cl); + if (p->out) { + *p->last_out = cl; + } else { + p->out = cl; + } + p->last_out = &cl->next; if (b->last_shadow) { - if (!(tl = ngx_alloc_chain_link(p->pool))) { + tl = ngx_alloc_chain_link(p->pool); + if (tl == NULL) { return NGX_ABORT; } @@ -676,7 +690,8 @@ ngx_int_t ngx_event_pipe_copy_input_filt p->free = p->free->next; } else { - if (!(b = ngx_alloc_buf(p->pool))) { + b = ngx_alloc_buf(p->pool); + if (b == NULL) { return NGX_ERROR; } } @@ -688,7 +703,8 @@ ngx_int_t ngx_event_pipe_copy_input_filt b->recycled = 1; buf->shadow = b; - if (!(cl = ngx_alloc_chain_link(p->pool))) { + cl = ngx_alloc_chain_link(p->pool); + if (cl == NULL) { return NGX_ERROR; } @@ -697,7 +713,12 @@ ngx_int_t ngx_event_pipe_copy_input_filt ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d", b->num); - ngx_chain_add_link(p->in, p->last_in, cl); + if (p->in) { + *p->last_in = cl; + } else { + p->in = cl; + } + p->last_in = &cl->next; return NGX_OK; } @@ -766,7 +787,8 @@ ngx_int_t ngx_event_pipe_add_free_buf(ng { ngx_chain_t *cl; - if (!(cl = ngx_alloc_chain_link(p->pool))) { + cl = ngx_alloc_chain_link(p->pool); + if (cl == NULL) { return NGX_ERROR; } diff --git a/src/event/ngx_event_posted.c b/src/event/ngx_event_posted.c --- a/src/event/ngx_event_posted.c +++ b/src/event/ngx_event_posted.c @@ -43,10 +43,10 @@ void ngx_event_process_posted(ngx_cycle_ void ngx_wakeup_worker_thread(ngx_cycle_t *cycle) { ngx_int_t i; +#if 0 ngx_uint_t busy; ngx_event_t *ev; -#if 0 busy = 1; if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) { diff --git a/src/event/ngx_event_timer.c b/src/event/ngx_event_timer.c --- a/src/event/ngx_event_timer.c +++ b/src/event/ngx_event_timer.c @@ -31,7 +31,8 @@ ngx_event_timer_init(ngx_log_t *log) ngx_event_timer_rbtree = &ngx_event_timer_sentinel; #if (NGX_THREADS) - if (!(ngx_event_timer_mutex = ngx_mutex_init(log, 0))) { + ngx_event_timer_mutex = ngx_mutex_init(log, 0); + if (ngx_event_timer_mutex == NULL) { return NGX_ERROR; } #endif diff --git a/src/event/ngx_event_timer.h b/src/event/ngx_event_timer.h --- a/src/event/ngx_event_timer.h +++ b/src/event/ngx_event_timer.h @@ -13,8 +13,8 @@ #include -#define NGX_TIMER_INFINITE -1 -#define NGX_TIMER_ERROR -2 +#define NGX_TIMER_INFINITE (ngx_msec_t) -1 +#define NGX_TIMER_ERROR (ngx_msec_t) -2 /* diff --git a/src/http/modules/ngx_http_access_handler.c b/src/http/modules/ngx_http_access_handler.c deleted file mode 100644 --- a/src/http/modules/ngx_http_access_handler.c +++ /dev/null @@ -1,214 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#include -#include -#include - - -/* AF_INET only */ - -typedef struct { - in_addr_t mask; - in_addr_t addr; - unsigned deny; -} ngx_http_access_rule_t; - - -typedef struct { - ngx_array_t *rules; /* array of ngx_http_access_rule_t */ -} ngx_http_access_loc_conf_t; - - -static ngx_int_t ngx_http_access_handler(ngx_http_request_t *r); -static char *ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); -static void *ngx_http_access_create_loc_conf(ngx_conf_t *cf); -static char *ngx_http_access_merge_loc_conf(ngx_conf_t *cf, - void *parent, void *child); -static ngx_int_t ngx_http_access_init(ngx_cycle_t *cycle); - - -static ngx_command_t ngx_http_access_commands[] = { - - { ngx_string("allow"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_http_access_rule, - NGX_HTTP_LOC_CONF_OFFSET, - 0, - NULL }, - - { ngx_string("deny"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_http_access_rule, - NGX_HTTP_LOC_CONF_OFFSET, - 0, - NULL }, - - ngx_null_command -}; - - - -ngx_http_module_t ngx_http_access_module_ctx = { - NULL, /* pre conf */ - - NULL, /* create main configuration */ - NULL, /* init main configuration */ - - NULL, /* create server configuration */ - NULL, /* merge server configuration */ - - ngx_http_access_create_loc_conf, /* create location configuration */ - ngx_http_access_merge_loc_conf /* merge location configuration */ -}; - - -ngx_module_t ngx_http_access_module = { - NGX_MODULE, - &ngx_http_access_module_ctx, /* module context */ - ngx_http_access_commands, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - ngx_http_access_init, /* init module */ - NULL /* init process */ -}; - - -static ngx_int_t ngx_http_access_handler(ngx_http_request_t *r) -{ - ngx_uint_t i; - struct sockaddr_in *sin; - ngx_http_access_rule_t *rule; - ngx_http_access_loc_conf_t *alcf; - - alcf = ngx_http_get_module_loc_conf(r, ngx_http_access_module); - - if (alcf->rules == NULL) { - return NGX_OK; - } - - /* AF_INET only */ - - sin = (struct sockaddr_in *) r->connection->sockaddr; - - rule = alcf->rules->elts; - for (i = 0; i < alcf->rules->nelts; i++) { - - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "%08XD %08XD %08XD", - sin->sin_addr.s_addr, rule[i].mask, rule[i].addr); - - if ((sin->sin_addr.s_addr & rule[i].mask) == rule[i].addr) { - if (rule[i].deny) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "access forbidden by rule"); - - return NGX_HTTP_FORBIDDEN; - } - - return NGX_OK; - } - } - - return NGX_OK; -} - - -static char *ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf) -{ - ngx_http_access_loc_conf_t *alcf = conf; - - ngx_str_t *value; - ngx_inet_cidr_t in_cidr; - ngx_http_access_rule_t *rule; - - if (alcf->rules == NULL) { - alcf->rules = ngx_create_array(cf->pool, 4, - sizeof(ngx_http_access_rule_t)); - if (alcf->rules == NULL) { - return NGX_CONF_ERROR; - } - } - - if (!(rule = ngx_push_array(alcf->rules))) { - return NGX_CONF_ERROR; - } - - value = cf->args->elts; - - rule->deny = (value[0].data[0] == 'd') ? 1 : 0; - - if (value[1].len == 3 && ngx_strcmp(value[1].data, "all") == 0) { - rule->mask = 0; - rule->addr = 0; - - return NGX_CONF_OK; - } - - rule->addr = inet_addr((char *) value[1].data); - - if (rule->addr != INADDR_NONE) { - rule->mask = 0xffffffff; - - return NGX_CONF_OK; - } - - if (ngx_ptocidr(&value[1], &in_cidr) == NGX_ERROR) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", - &value[1]); - return NGX_CONF_ERROR; - } - - rule->mask = in_cidr.mask; - rule->addr = in_cidr.addr; - - return NGX_CONF_OK; -} - - -static void *ngx_http_access_create_loc_conf(ngx_conf_t *cf) -{ - ngx_http_access_loc_conf_t *conf; - - if (!(conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_access_loc_conf_t)))) { - return NGX_CONF_ERROR; - } - - return conf; -} - - -static char *ngx_http_access_merge_loc_conf(ngx_conf_t *cf, - void *parent, void *child) -{ - ngx_http_access_loc_conf_t *prev = parent; - ngx_http_access_loc_conf_t *conf = child; - - if (conf->rules == NULL) { - conf->rules = prev->rules; - } - - return NGX_CONF_OK; -} - - -static ngx_int_t ngx_http_access_init(ngx_cycle_t *cycle) -{ - ngx_http_handler_pt *h; - ngx_http_core_main_conf_t *cmcf; - - cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module); - - h = ngx_push_array(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers); - if (h == NULL) { - return NGX_ERROR; - } - - *h = ngx_http_access_handler; - - return NGX_OK; -} diff --git a/src/http/modules/ngx_http_access_module.c b/src/http/modules/ngx_http_access_module.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_access_module.c @@ -0,0 +1,219 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +/* AF_INET only */ + +typedef struct { + in_addr_t mask; + in_addr_t addr; + unsigned deny; +} ngx_http_access_rule_t; + + +typedef struct { + ngx_array_t *rules; /* array of ngx_http_access_rule_t */ +} ngx_http_access_loc_conf_t; + + +static ngx_int_t ngx_http_access_handler(ngx_http_request_t *r); +static char *ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static void *ngx_http_access_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_access_merge_loc_conf(ngx_conf_t *cf, + void *parent, void *child); +static ngx_int_t ngx_http_access_init(ngx_cycle_t *cycle); + + +static ngx_command_t ngx_http_access_commands[] = { + + { ngx_string("allow"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_access_rule, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("deny"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_access_rule, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + + +ngx_http_module_t ngx_http_access_module_ctx = { + NULL, /* pre conf */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_access_create_loc_conf, /* create location configuration */ + ngx_http_access_merge_loc_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_access_module = { + NGX_MODULE, + &ngx_http_access_module_ctx, /* module context */ + ngx_http_access_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + ngx_http_access_init, /* init module */ + NULL /* init process */ +}; + + +static ngx_int_t +ngx_http_access_handler(ngx_http_request_t *r) +{ + ngx_uint_t i; + struct sockaddr_in *sin; + ngx_http_access_rule_t *rule; + ngx_http_access_loc_conf_t *alcf; + + alcf = ngx_http_get_module_loc_conf(r, ngx_http_access_module); + + if (alcf->rules == NULL) { + return NGX_OK; + } + + /* AF_INET only */ + + sin = (struct sockaddr_in *) r->connection->sockaddr; + + rule = alcf->rules->elts; + for (i = 0; i < alcf->rules->nelts; i++) { + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "%08XD %08XD %08XD", + sin->sin_addr.s_addr, rule[i].mask, rule[i].addr); + + if ((sin->sin_addr.s_addr & rule[i].mask) == rule[i].addr) { + if (rule[i].deny) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "access forbidden by rule"); + + return NGX_HTTP_FORBIDDEN; + } + + return NGX_OK; + } + } + + return NGX_OK; +} + + +static char * +ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_access_loc_conf_t *alcf = conf; + + ngx_str_t *value; + ngx_inet_cidr_t in_cidr; + ngx_http_access_rule_t *rule; + + if (alcf->rules == NULL) { + alcf->rules = ngx_array_create(cf->pool, 4, + sizeof(ngx_http_access_rule_t)); + if (alcf->rules == NULL) { + return NGX_CONF_ERROR; + } + } + + rule = ngx_array_push(alcf->rules); + if (rule == NULL) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + + rule->deny = (value[0].data[0] == 'd') ? 1 : 0; + + if (value[1].len == 3 && ngx_strcmp(value[1].data, "all") == 0) { + rule->mask = 0; + rule->addr = 0; + + return NGX_CONF_OK; + } + + rule->addr = inet_addr((char *) value[1].data); + + if (rule->addr != INADDR_NONE) { + rule->mask = 0xffffffff; + + return NGX_CONF_OK; + } + + if (ngx_ptocidr(&value[1], &in_cidr) == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", + &value[1]); + return NGX_CONF_ERROR; + } + + rule->mask = in_cidr.mask; + rule->addr = in_cidr.addr; + + return NGX_CONF_OK; +} + + +static void * +ngx_http_access_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_access_loc_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_access_loc_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + return conf; +} + + +static char * +ngx_http_access_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_access_loc_conf_t *prev = parent; + ngx_http_access_loc_conf_t *conf = child; + + if (conf->rules == NULL) { + conf->rules = prev->rules; + } + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_access_init(ngx_cycle_t *cycle) +{ + ngx_http_handler_pt *h; + ngx_http_core_main_conf_t *cmcf; + + cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module); + + h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_access_handler; + + return NGX_OK; +} diff --git a/src/http/modules/ngx_http_autoindex_handler.c b/src/http/modules/ngx_http_autoindex_handler.c deleted file mode 100644 --- a/src/http/modules/ngx_http_autoindex_handler.c +++ /dev/null @@ -1,560 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#include -#include -#include - - -#if 0 - -typedef struct { - ngx_buf_t *buf; - size_t size; - ngx_pool_t *pool; - size_t alloc_size; - ngx_chain_t **last_out; -} ngx_http_autoindex_ctx_t; - -#endif - - -typedef struct { - ngx_str_t name; - ngx_uint_t escape; - ngx_uint_t dir; - time_t mtime; - off_t size; -} ngx_http_autoindex_entry_t; - - -typedef struct { - ngx_flag_t enable; -} ngx_http_autoindex_loc_conf_t; - - -#define NGX_HTTP_AUTOINDEX_NAME_LEN 50 - - -static int ngx_http_autoindex_cmp_entries(const void *one, const void *two); -static ngx_int_t ngx_http_autoindex_error(ngx_http_request_t *r, - ngx_dir_t *dir, u_char *name); -static ngx_int_t ngx_http_autoindex_init(ngx_cycle_t *cycle); -static void *ngx_http_autoindex_create_loc_conf(ngx_conf_t *cf); -static char *ngx_http_autoindex_merge_loc_conf(ngx_conf_t *cf, - void *parent, void *child); - - -static ngx_command_t ngx_http_autoindex_commands[] = { - - { ngx_string("autoindex"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_autoindex_loc_conf_t, enable), - NULL }, - - ngx_null_command -}; - - -ngx_http_module_t ngx_http_autoindex_module_ctx = { - NULL, /* pre conf */ - - NULL, /* create main configuration */ - NULL, /* init main configuration */ - - NULL, /* create server configuration */ - NULL, /* merge server configuration */ - - ngx_http_autoindex_create_loc_conf, /* create location configration */ - ngx_http_autoindex_merge_loc_conf /* merge location configration */ -}; - - -ngx_module_t ngx_http_autoindex_module = { - NGX_MODULE, - &ngx_http_autoindex_module_ctx, /* module context */ - ngx_http_autoindex_commands, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - ngx_http_autoindex_init, /* init module */ - NULL /* init process */ -}; - - -static u_char title[] = -"" CRLF -"Index of " -; - - -static u_char header[] = -"" CRLF -"" CRLF -"

Index of " -; - -static u_char tail[] = -"" CRLF -"" CRLF -; - - -static ngx_int_t -ngx_http_autoindex_handler(ngx_http_request_t *r) -{ - u_char *last; - size_t len; - ngx_tm_t tm; - ngx_int_t rc; - ngx_uint_t i, level; - ngx_err_t err; - ngx_buf_t *b; - ngx_chain_t out; - ngx_str_t dname, fname; - ngx_dir_t dir; - ngx_pool_t *pool; - ngx_array_t entries; - ngx_http_core_loc_conf_t *clcf; - ngx_http_autoindex_entry_t *entry; - ngx_http_autoindex_loc_conf_t *alcf; - - static char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - - if (r->uri.data[r->uri.len - 1] != '/') { - return NGX_DECLINED; - } - - /* TODO: Win32 */ - if (r->zero_in_uri) { - return NGX_DECLINED; - } - - alcf = ngx_http_get_module_loc_conf(r, ngx_http_autoindex_module); - - if (!alcf->enable) { - return NGX_DECLINED; - } - - /* TODO: pool should be temporary pool */ - pool = r->pool; - - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - - if (clcf->alias) { - dname.data = ngx_palloc(pool, clcf->root.len + r->uri.len - + NGX_DIR_MASK_LEN + 1 - - clcf->name.len); - if (dname.data == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - last = ngx_cpymem(dname.data, clcf->root.data, clcf->root.len); - last = ngx_cpystrn(last, r->uri.data + clcf->name.len, - r->uri.len - clcf->name.len + 1); - - } else { - dname.data = ngx_palloc(pool, clcf->root.len + r->uri.len - + NGX_DIR_MASK_LEN); - if (dname.data == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - last = ngx_cpymem(dname.data, clcf->root.data, clcf->root.len); - last = ngx_cpystrn(last, r->uri.data, r->uri.len); - } - - dname.len = last - dname.data; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http autoindex: \"%s\"", dname.data); - - - if (ngx_open_dir(&dname, &dir) == NGX_ERROR) { - err = ngx_errno; - - if (err == NGX_ENOENT || err == NGX_ENOTDIR) { - level = NGX_LOG_ERR; - rc = NGX_HTTP_NOT_FOUND; - - } else if (err == NGX_EACCES) { - 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_dir_n " \"%s\" failed", dname.data); - - return rc; - } - -#if (NGX_SUPPRESS_WARN) - /* MSVC thinks 'entries' may be used without having been initialized */ - ngx_memzero(&entries, sizeof(ngx_array_t)); -#endif - - if (ngx_array_init(&entries, pool, 50, sizeof(ngx_http_autoindex_entry_t)) - == NGX_ERROR) - { - return ngx_http_autoindex_error(r, &dir, dname.data); - } - - fname.len = 0; -#if (NGX_SUPPRESS_WARN) - fname.data = NULL; -#endif - - for ( ;; ) { - ngx_set_errno(0); - - if (ngx_read_dir(&dir) == NGX_ERROR) { - err = ngx_errno; - - if (err == NGX_ENOMOREFILES) { - rc = NGX_OK; - - } else { - ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, - ngx_read_dir_n " \"%s\" failed", dname.data); - return ngx_http_autoindex_error(r, &dir, dname.data); - } - - break; - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http autoindex file: \"%s\"", ngx_de_name(&dir)); - - len = ngx_de_namelen(&dir); - - if (len == 1 && ngx_de_name(&dir)[0] == '.') { - continue; - } - - if (len == 2 - && ngx_de_name(&dir)[0] == '.' - && ngx_de_name(&dir)[1] == '.') - { - continue; - } - - if (!dir.valid_info) { - - if (dname.len + 1 + len > fname.len) { - fname.len = dname.len + 1 + len + 32; - - if (!(fname.data = ngx_palloc(pool, fname.len))) { - return ngx_http_autoindex_error(r, &dir, dname.data); - } - - last = ngx_cpystrn(fname.data, dname.data, - dname.len + 1); - *last++ = '/'; - } - - ngx_cpystrn(last, ngx_de_name(&dir), len + 1); - - if (ngx_de_info(fname.data, &dir) == NGX_FILE_ERROR) { - err = ngx_errno; - - if (err != NGX_ENOENT) { - ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, - ngx_de_info_n " \"%s\" failed", fname.data); - return ngx_http_autoindex_error(r, &dir, dname.data); - } - - if (ngx_de_link_info(fname.data, &dir) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, - ngx_de_link_info_n " \"%s\" failed", - fname.data); - return ngx_http_autoindex_error(r, &dir, dname.data); - } - } - } - - if (!(entry = ngx_array_push(&entries))) { - return ngx_http_autoindex_error(r, &dir, dname.data); - } - - entry->name.len = len; - entry->escape = 2 * ngx_escape_uri(NULL, ngx_de_name(&dir), len, - NGX_ESCAPE_HTML); - - if (!(entry->name.data = ngx_palloc(pool, len + entry->escape + 1))) { - return ngx_http_autoindex_error(r, &dir, dname.data); - } - - ngx_cpystrn(entry->name.data, ngx_de_name(&dir), len + 1); - - entry->dir = ngx_de_is_dir(&dir); - entry->mtime = ngx_de_mtime(&dir); - entry->size = ngx_de_size(&dir); - } - - if (ngx_close_dir(&dir) == NGX_ERROR) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, - ngx_close_dir_n " \"%s\" failed", dname.data); - } - - len = sizeof(title) - 1 - + r->uri.len - + sizeof(header) - 1 - + r->uri.len - + sizeof("

") - 1 - + sizeof("
../" CRLF) - 1
-          + sizeof("

") - 1 - + sizeof(tail) - 1; - - entry = entries.elts; - for (i = 0; i < entries.nelts; i++) { - len += sizeof("") - 1 - + NGX_HTTP_AUTOINDEX_NAME_LEN + sizeof(">") - 2 - + sizeof("") - 1 - + sizeof(" 28-Sep-1970 12:00 ") - 1 - + 19 - + 2; - } - - if (!(b = ngx_create_temp_buf(r->pool, len))) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - if (entries.nelts > 1) { - ngx_qsort(entry, (size_t) entries.nelts, - sizeof(ngx_http_autoindex_entry_t), - ngx_http_autoindex_cmp_entries); - } - - b->last = ngx_cpymem(b->last, title, sizeof(title) - 1); - b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len); - b->last = ngx_cpymem(b->last, header, sizeof(header) - 1); - b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len); - b->last = ngx_cpymem(b->last, "", sizeof("") - 1); - - b->last = ngx_cpymem(b->last, "
../" CRLF,
-                         sizeof("
../" CRLF) - 1);
-
-    for (i = 0; i < entries.nelts; i++) {
-        b->last = ngx_cpymem(b->last, "last, entry[i].name.data, entry[i].name.len,
-                           NGX_ESCAPE_HTML);
-
-            b->last += entry[i].name.len + entry[i].escape;
-
-        } else {
-            b->last = ngx_cpymem(b->last, entry[i].name.data,
-                                 entry[i].name.len);
-        }
-
-        if (entry[i].dir) {
-            *b->last++ = '/';
-        }
-
-        *b->last++ = '"';
-        *b->last++ = '>';
-
-        b->last = ngx_cpystrn(b->last, entry[i].name.data,
-                              NGX_HTTP_AUTOINDEX_NAME_LEN + 1);
-
-        len = entry[i].name.len;
-
-        if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) {
-            b->last = ngx_cpymem(b->last - 3, "..>",
-                                 sizeof("..>") - 1);
-
-        } else {
-            if (entry[i].dir && NGX_HTTP_AUTOINDEX_NAME_LEN - len > 0) {
-                *b->last++ = '/';
-                len++;
-            }
-
-            b->last = ngx_cpymem(b->last, "", sizeof("") - 1);
-            ngx_memset(b->last, ' ', NGX_HTTP_AUTOINDEX_NAME_LEN - len);
-            b->last += NGX_HTTP_AUTOINDEX_NAME_LEN - len;
-        }
-
-        *b->last++ = ' ';
-
-        ngx_gmtime(entry[i].mtime, &tm);
-
-        b->last = ngx_sprintf(b->last, "%02d-%s-%d %02d:%02d ",
-                              tm.ngx_tm_mday,
-                              months[tm.ngx_tm_mon - 1],
-                              tm.ngx_tm_year,
-                              tm.ngx_tm_hour,
-                              tm.ngx_tm_min);
-
-        if (entry[i].dir) {
-            b->last = ngx_cpymem(b->last,  "                  -",
-                                 sizeof("                  -") - 1);
-
-        } else {
-            b->last = ngx_sprintf(b->last, "%19O", entry[i].size);
-        }
-
-        *b->last++ = CR;
-        *b->last++ = LF;
-    }
-
-    /* TODO: free temporary pool */
-
-    b->last = ngx_cpymem(b->last, "

", sizeof("

") - 1); - - b->last = ngx_cpymem(b->last, tail, sizeof(tail) - 1); - - r->headers_out.status = NGX_HTTP_OK; - r->headers_out.content_length_n = b->last - b->pos; - - r->headers_out.content_type = ngx_list_push(&r->headers_out.headers); - if (r->headers_out.content_type == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - r->headers_out.content_type->key.len = 0; - r->headers_out.content_type->key.data = NULL; - r->headers_out.content_type->value.len = sizeof("text/html") - 1; - r->headers_out.content_type->value.data = (u_char *) "text/html"; - - rc = ngx_http_send_header(r); - - if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { - return rc; - } - - if (!r->main) { - b->last_buf = 1; - } - - out.buf = b; - out.next = NULL; - - return ngx_http_output_filter(r, &out); -} - - -static int -ngx_http_autoindex_cmp_entries(const void *one, const void *two) -{ - ngx_http_autoindex_entry_t *first = (ngx_http_autoindex_entry_t *) one; - ngx_http_autoindex_entry_t *second = (ngx_http_autoindex_entry_t *) two; - - if (first->dir && !second->dir) { - /* move the directories to the start */ - return -1; - } - - if (!first->dir && second->dir) { - /* move the directories to the start */ - return 1; - } - - return (int) ngx_strcmp(first->name.data, second->name.data); -} - - -#if 0 - -static ngx_buf_t * -ngx_http_autoindex_alloc(ngx_http_autoindex_ctx_t *ctx, size_t size) -{ - ngx_chain_t *cl; - - if (ctx->buf) { - - if ((size_t) (ctx->buf->end - ctx->buf->last) >= size) { - return ctx->buf; - } - - ctx->size += ctx->buf->last - ctx->buf->pos; - } - - if (!(ctx->buf = ngx_create_temp_buf(ctx->pool, ctx->alloc_size))) { - return NULL; - } - - if (!(cl = ngx_alloc_chain_link(ctx->pool))) { - return NULL; - } - - cl->buf = ctx->buf; - cl->next = NULL; - - *ctx->last_out = cl; - ctx->last_out = &cl->next; - - return ctx->buf; -} - -#endif - - -static ngx_int_t -ngx_http_autoindex_error(ngx_http_request_t *r, ngx_dir_t *dir, u_char *name) -{ - if (ngx_close_dir(dir) == NGX_ERROR) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, - ngx_close_dir_n " \"%s\" failed", name); - } - - return NGX_HTTP_INTERNAL_SERVER_ERROR; -} - - -static ngx_int_t -ngx_http_autoindex_init(ngx_cycle_t *cycle) -{ - ngx_http_handler_pt *h; - ngx_http_core_main_conf_t *cmcf; - - cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module); - - h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers); - if (h == NULL) { - return NGX_ERROR; - } - - *h = ngx_http_autoindex_handler; - - return NGX_OK; -} - - -static void * -ngx_http_autoindex_create_loc_conf(ngx_conf_t *cf) -{ - ngx_http_autoindex_loc_conf_t *conf; - - conf = ngx_palloc(cf->pool, sizeof(ngx_http_autoindex_loc_conf_t)); - if (conf == NULL) { - return NGX_CONF_ERROR; - } - - conf->enable = NGX_CONF_UNSET; - - return conf; -} - - -static char * -ngx_http_autoindex_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) -{ - ngx_http_autoindex_loc_conf_t *prev = parent; - ngx_http_autoindex_loc_conf_t *conf = child; - - ngx_conf_merge_value(conf->enable, prev->enable, 0); - - return NGX_CONF_OK; -} diff --git a/src/http/modules/ngx_http_autoindex_module.c b/src/http/modules/ngx_http_autoindex_module.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_autoindex_module.c @@ -0,0 +1,563 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +#if 0 + +typedef struct { + ngx_buf_t *buf; + size_t size; + ngx_pool_t *pool; + size_t alloc_size; + ngx_chain_t **last_out; +} ngx_http_autoindex_ctx_t; + +#endif + + +typedef struct { + ngx_str_t name; + ngx_uint_t escape; + ngx_uint_t dir; + time_t mtime; + off_t size; +} ngx_http_autoindex_entry_t; + + +typedef struct { + ngx_flag_t enable; +} ngx_http_autoindex_loc_conf_t; + + +#define NGX_HTTP_AUTOINDEX_NAME_LEN 50 + + +static int ngx_http_autoindex_cmp_entries(const void *one, const void *two); +static ngx_int_t ngx_http_autoindex_error(ngx_http_request_t *r, + ngx_dir_t *dir, u_char *name); +static ngx_int_t ngx_http_autoindex_init(ngx_cycle_t *cycle); +static void *ngx_http_autoindex_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_autoindex_merge_loc_conf(ngx_conf_t *cf, + void *parent, void *child); + + +static ngx_command_t ngx_http_autoindex_commands[] = { + + { ngx_string("autoindex"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_autoindex_loc_conf_t, enable), + NULL }, + + ngx_null_command +}; + + +ngx_http_module_t ngx_http_autoindex_module_ctx = { + NULL, /* pre conf */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_autoindex_create_loc_conf, /* create location configration */ + ngx_http_autoindex_merge_loc_conf /* merge location configration */ +}; + + +ngx_module_t ngx_http_autoindex_module = { + NGX_MODULE, + &ngx_http_autoindex_module_ctx, /* module context */ + ngx_http_autoindex_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + ngx_http_autoindex_init, /* init module */ + NULL /* init process */ +}; + + +static u_char title[] = +"" CRLF +"Index of " +; + + +static u_char header[] = +"" CRLF +"" CRLF +"

Index of " +; + +static u_char tail[] = +"" CRLF +"" CRLF +; + + +static ngx_int_t +ngx_http_autoindex_handler(ngx_http_request_t *r) +{ + u_char *last; + size_t len; + ngx_tm_t tm; + ngx_int_t rc; + ngx_uint_t i, level; + ngx_err_t err; + ngx_buf_t *b; + ngx_chain_t out; + ngx_str_t dname, fname; + ngx_dir_t dir; + ngx_pool_t *pool; + ngx_array_t entries; + ngx_http_core_loc_conf_t *clcf; + ngx_http_autoindex_entry_t *entry; + ngx_http_autoindex_loc_conf_t *alcf; + + static char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + + if (r->uri.data[r->uri.len - 1] != '/') { + return NGX_DECLINED; + } + + /* TODO: Win32 */ + if (r->zero_in_uri) { + return NGX_DECLINED; + } + + alcf = ngx_http_get_module_loc_conf(r, ngx_http_autoindex_module); + + if (!alcf->enable) { + return NGX_DECLINED; + } + + /* TODO: pool should be temporary pool */ + pool = r->pool; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (clcf->alias) { + dname.data = ngx_palloc(pool, clcf->root.len + r->uri.len + + NGX_DIR_MASK_LEN + 1 + - clcf->name.len); + if (dname.data == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + last = ngx_cpymem(dname.data, clcf->root.data, clcf->root.len); + last = ngx_cpystrn(last, r->uri.data + clcf->name.len, + r->uri.len - clcf->name.len + 1); + + } else { + dname.data = ngx_palloc(pool, clcf->root.len + r->uri.len + + NGX_DIR_MASK_LEN); + if (dname.data == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + last = ngx_cpymem(dname.data, clcf->root.data, clcf->root.len); + last = ngx_cpystrn(last, r->uri.data, r->uri.len); + } + + dname.len = last - dname.data; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http autoindex: \"%s\"", dname.data); + + + if (ngx_open_dir(&dname, &dir) == NGX_ERROR) { + err = ngx_errno; + + if (err == NGX_ENOENT || err == NGX_ENOTDIR) { + level = NGX_LOG_ERR; + rc = NGX_HTTP_NOT_FOUND; + + } else if (err == NGX_EACCES) { + 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_dir_n " \"%s\" failed", dname.data); + + return rc; + } + +#if (NGX_SUPPRESS_WARN) + /* MSVC thinks 'entries' may be used without having been initialized */ + ngx_memzero(&entries, sizeof(ngx_array_t)); +#endif + + if (ngx_array_init(&entries, pool, 50, sizeof(ngx_http_autoindex_entry_t)) + == NGX_ERROR) + { + return ngx_http_autoindex_error(r, &dir, dname.data); + } + + fname.len = 0; +#if (NGX_SUPPRESS_WARN) + fname.data = NULL; +#endif + + 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, r->connection->log, err, + ngx_read_dir_n " \"%s\" failed", dname.data); + return ngx_http_autoindex_error(r, &dir, dname.data); + } + + break; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http autoindex file: \"%s\"", ngx_de_name(&dir)); + + len = ngx_de_namelen(&dir); + + if (len == 1 && ngx_de_name(&dir)[0] == '.') { + continue; + } + + if (len == 2 + && ngx_de_name(&dir)[0] == '.' + && ngx_de_name(&dir)[1] == '.') + { + continue; + } + + if (!dir.valid_info) { + + if (dname.len + 1 + len > fname.len) { + fname.len = dname.len + 1 + len + 32; + + fname.data = ngx_palloc(pool, fname.len); + if (fname.data == NULL) { + return ngx_http_autoindex_error(r, &dir, dname.data); + } + + last = ngx_cpystrn(fname.data, dname.data, + dname.len + 1); + *last++ = '/'; + } + + ngx_cpystrn(last, ngx_de_name(&dir), len + 1); + + if (ngx_de_info(fname.data, &dir) == NGX_FILE_ERROR) { + err = ngx_errno; + + if (err != NGX_ENOENT) { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, + ngx_de_info_n " \"%s\" failed", fname.data); + return ngx_http_autoindex_error(r, &dir, dname.data); + } + + if (ngx_de_link_info(fname.data, &dir) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, + ngx_de_link_info_n " \"%s\" failed", + fname.data); + return ngx_http_autoindex_error(r, &dir, dname.data); + } + } + } + + entry = ngx_array_push(&entries); + if (entry == NULL) { + return ngx_http_autoindex_error(r, &dir, dname.data); + } + + entry->name.len = len; + entry->escape = 2 * ngx_escape_uri(NULL, ngx_de_name(&dir), len, + NGX_ESCAPE_HTML); + + entry->name.data = ngx_palloc(pool, len + entry->escape + 1); + if (entry->name.data == NULL) { + return ngx_http_autoindex_error(r, &dir, dname.data); + } + + ngx_cpystrn(entry->name.data, ngx_de_name(&dir), len + 1); + + entry->dir = ngx_de_is_dir(&dir); + entry->mtime = ngx_de_mtime(&dir); + entry->size = ngx_de_size(&dir); + } + + if (ngx_close_dir(&dir) == NGX_ERROR) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, + ngx_close_dir_n " \"%s\" failed", dname.data); + } + + len = sizeof(title) - 1 + + r->uri.len + + sizeof(header) - 1 + + r->uri.len + + sizeof("

") - 1 + + sizeof("
../" CRLF) - 1
+          + sizeof("

") - 1 + + sizeof(tail) - 1; + + entry = entries.elts; + for (i = 0; i < entries.nelts; i++) { + len += sizeof("") - 1 + + NGX_HTTP_AUTOINDEX_NAME_LEN + sizeof(">") - 2 + + sizeof("") - 1 + + sizeof(" 28-Sep-1970 12:00 ") - 1 + + 19 + + 2; + } + + b = ngx_create_temp_buf(r->pool, len); + if (b == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + if (entries.nelts > 1) { + ngx_qsort(entry, (size_t) entries.nelts, + sizeof(ngx_http_autoindex_entry_t), + ngx_http_autoindex_cmp_entries); + } + + b->last = ngx_cpymem(b->last, title, sizeof(title) - 1); + b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len); + b->last = ngx_cpymem(b->last, header, sizeof(header) - 1); + b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len); + b->last = ngx_cpymem(b->last, "", sizeof("") - 1); + + b->last = ngx_cpymem(b->last, "
../" CRLF,
+                         sizeof("
../" CRLF) - 1);
+
+    for (i = 0; i < entries.nelts; i++) {
+        b->last = ngx_cpymem(b->last, "last, entry[i].name.data, entry[i].name.len,
+                           NGX_ESCAPE_HTML);
+
+            b->last += entry[i].name.len + entry[i].escape;
+
+        } else {
+            b->last = ngx_cpymem(b->last, entry[i].name.data,
+                                 entry[i].name.len);
+        }
+
+        if (entry[i].dir) {
+            *b->last++ = '/';
+        }
+
+        *b->last++ = '"';
+        *b->last++ = '>';
+
+        b->last = ngx_cpystrn(b->last, entry[i].name.data,
+                              NGX_HTTP_AUTOINDEX_NAME_LEN + 1);
+
+        len = entry[i].name.len;
+
+        if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) {
+            b->last = ngx_cpymem(b->last - 3, "..>",
+                                 sizeof("..>") - 1);
+
+        } else {
+            if (entry[i].dir && NGX_HTTP_AUTOINDEX_NAME_LEN - len > 0) {
+                *b->last++ = '/';
+                len++;
+            }
+
+            b->last = ngx_cpymem(b->last, "", sizeof("") - 1);
+            ngx_memset(b->last, ' ', NGX_HTTP_AUTOINDEX_NAME_LEN - len);
+            b->last += NGX_HTTP_AUTOINDEX_NAME_LEN - len;
+        }
+
+        *b->last++ = ' ';
+
+        ngx_gmtime(entry[i].mtime, &tm);
+
+        b->last = ngx_sprintf(b->last, "%02d-%s-%d %02d:%02d ",
+                              tm.ngx_tm_mday,
+                              months[tm.ngx_tm_mon - 1],
+                              tm.ngx_tm_year,
+                              tm.ngx_tm_hour,
+                              tm.ngx_tm_min);
+
+        if (entry[i].dir) {
+            b->last = ngx_cpymem(b->last,  "                  -",
+                                 sizeof("                  -") - 1);
+
+        } else {
+            b->last = ngx_sprintf(b->last, "%19O", entry[i].size);
+        }
+
+        *b->last++ = CR;
+        *b->last++ = LF;
+    }
+
+    /* TODO: free temporary pool */
+
+    b->last = ngx_cpymem(b->last, "

", sizeof("

") - 1); + + b->last = ngx_cpymem(b->last, tail, sizeof(tail) - 1); + + r->headers_out.status = NGX_HTTP_OK; + r->headers_out.content_length_n = b->last - b->pos; + + r->headers_out.content_type = ngx_list_push(&r->headers_out.headers); + if (r->headers_out.content_type == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + r->headers_out.content_type->key.len = 0; + r->headers_out.content_type->key.data = NULL; + r->headers_out.content_type->value.len = sizeof("text/html") - 1; + r->headers_out.content_type->value.data = (u_char *) "text/html"; + + rc = ngx_http_send_header(r); + + if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { + return rc; + } + + if (!r->main) { + b->last_buf = 1; + } + + out.buf = b; + out.next = NULL; + + return ngx_http_output_filter(r, &out); +} + + +static int +ngx_http_autoindex_cmp_entries(const void *one, const void *two) +{ + ngx_http_autoindex_entry_t *first = (ngx_http_autoindex_entry_t *) one; + ngx_http_autoindex_entry_t *second = (ngx_http_autoindex_entry_t *) two; + + if (first->dir && !second->dir) { + /* move the directories to the start */ + return -1; + } + + if (!first->dir && second->dir) { + /* move the directories to the start */ + return 1; + } + + return (int) ngx_strcmp(first->name.data, second->name.data); +} + + +#if 0 + +static ngx_buf_t * +ngx_http_autoindex_alloc(ngx_http_autoindex_ctx_t *ctx, size_t size) +{ + ngx_chain_t *cl; + + if (ctx->buf) { + + if ((size_t) (ctx->buf->end - ctx->buf->last) >= size) { + return ctx->buf; + } + + ctx->size += ctx->buf->last - ctx->buf->pos; + } + + ctx->buf = ngx_create_temp_buf(ctx->pool, ctx->alloc_size); + if (ctx->buf == NULL) { + return NULL; + } + + cl = ngx_alloc_chain_link(ctx->pool); + if (cl == NULL) { + return NULL; + } + + cl->buf = ctx->buf; + cl->next = NULL; + + *ctx->last_out = cl; + ctx->last_out = &cl->next; + + return ctx->buf; +} + +#endif + + +static ngx_int_t +ngx_http_autoindex_error(ngx_http_request_t *r, ngx_dir_t *dir, u_char *name) +{ + if (ngx_close_dir(dir) == NGX_ERROR) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, + ngx_close_dir_n " \"%s\" failed", name); + } + + return NGX_HTTP_INTERNAL_SERVER_ERROR; +} + + +static ngx_int_t +ngx_http_autoindex_init(ngx_cycle_t *cycle) +{ + ngx_http_handler_pt *h; + ngx_http_core_main_conf_t *cmcf; + + cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module); + + h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_autoindex_handler; + + return NGX_OK; +} + + +static void * +ngx_http_autoindex_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_autoindex_loc_conf_t *conf; + + conf = ngx_palloc(cf->pool, sizeof(ngx_http_autoindex_loc_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + conf->enable = NGX_CONF_UNSET; + + return conf; +} + + +static char * +ngx_http_autoindex_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_autoindex_loc_conf_t *prev = parent; + ngx_http_autoindex_loc_conf_t *conf = child; + + ngx_conf_merge_value(conf->enable, prev->enable, 0); + + return NGX_CONF_OK; +} diff --git a/src/http/modules/ngx_http_charset_filter.c b/src/http/modules/ngx_http_charset_filter.c deleted file mode 100644 --- a/src/http/modules/ngx_http_charset_filter.c +++ /dev/null @@ -1,588 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#include -#include -#include - - -typedef struct { - char **tables; - ngx_str_t name; - ngx_uint_t server; /* unsigned server:1; */ -} ngx_http_charset_t; - - -typedef struct { - ngx_int_t src; - ngx_int_t dst; - char *src2dst; - char *dst2src; -} ngx_http_charset_tables_t; - - -typedef struct { - ngx_array_t charsets; /* ngx_http_charset_t */ - ngx_array_t tables; /* ngx_http_charset_tables_t */ -} ngx_http_charset_main_conf_t; - - -typedef struct { - ngx_flag_t enable; - ngx_flag_t autodetect; - - ngx_int_t default_charset; - ngx_int_t source_charset; -} ngx_http_charset_loc_conf_t; - - -typedef struct { - ngx_int_t server; - ngx_int_t client; -} ngx_http_charset_ctx_t; - - -static ngx_uint_t ngx_charset_recode(ngx_buf_t *b, char *table); - -static char *ngx_charset_map_block(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); -static char *ngx_charset_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf); - -static char *ngx_http_set_charset_slot(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); -static ngx_int_t ngx_http_add_charset(ngx_array_t *charsets, ngx_str_t *name); - -static ngx_int_t ngx_http_charset_filter_init(ngx_cycle_t *cycle); - -static void *ngx_http_charset_create_main_conf(ngx_conf_t *cf); -static char *ngx_http_charset_init_main_conf(ngx_conf_t *cf, void *conf); -static void *ngx_http_charset_create_loc_conf(ngx_conf_t *cf); -static char *ngx_http_charset_merge_loc_conf(ngx_conf_t *cf, - void *parent, void *child); - - -static ngx_command_t ngx_http_charset_filter_commands[] = { - - { ngx_string("charset_map"), - NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE2, - ngx_charset_map_block, - NGX_HTTP_MAIN_CONF_OFFSET, - 0, - NULL }, - - { ngx_string("default_charset"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_http_set_charset_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_charset_loc_conf_t, default_charset), - NULL }, - - { ngx_string("source_charset"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_http_set_charset_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_charset_loc_conf_t, source_charset), - NULL }, - - { ngx_string("charset"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_charset_loc_conf_t, enable), - NULL }, - - { ngx_string("autodetect_charset"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_charset_loc_conf_t, autodetect), - NULL }, - - ngx_null_command -}; - - -static ngx_http_module_t ngx_http_charset_filter_module_ctx = { - NULL, /* pre conf */ - - ngx_http_charset_create_main_conf, /* create main configuration */ - ngx_http_charset_init_main_conf, /* init main configuration */ - - NULL, /* create server configuration */ - NULL, /* merge server configuration */ - - ngx_http_charset_create_loc_conf, /* create location configuration */ - ngx_http_charset_merge_loc_conf /* merge location configuration */ -}; - - -ngx_module_t ngx_http_charset_filter_module = { - NGX_MODULE, - &ngx_http_charset_filter_module_ctx, /* module context */ - ngx_http_charset_filter_commands, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - ngx_http_charset_filter_init, /* init module */ - NULL /* init process */ -}; - - -static ngx_http_output_header_filter_pt ngx_http_next_header_filter; -static ngx_http_output_body_filter_pt ngx_http_next_body_filter; - - -static ngx_int_t ngx_http_charset_header_filter(ngx_http_request_t *r) -{ - ngx_http_charset_t *charsets; - ngx_http_charset_ctx_t *ctx; - ngx_http_charset_loc_conf_t *lcf; - ngx_http_charset_main_conf_t *mcf; - - mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module); - lcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module); - - if (lcf->enable == 0) { - return ngx_http_next_header_filter(r); - } - - if (r->headers_out.content_type == NULL) { - return ngx_http_next_header_filter(r); - } - - if (ngx_strncasecmp(r->headers_out.content_type->value.data, - "text/", 5) != 0 - && ngx_strncasecmp(r->headers_out.content_type->value.data, - "application/x-javascript", 24) != 0) - { - return ngx_http_next_header_filter(r); - } - - if (ngx_strstr(r->headers_out.content_type->value.data, "charset") != NULL) - { - return ngx_http_next_header_filter(r); - } - - if (r->headers_out.status == NGX_HTTP_MOVED_PERMANENTLY - && r->headers_out.status == NGX_HTTP_MOVED_TEMPORARILY) - { - /* - * do not set charset for the redirect because NN 4.x uses this - * charset instead of the next page charset - */ - - r->headers_out.charset.len = 0; - return ngx_http_next_header_filter(r); - } - - if (r->headers_out.charset.len) { - return ngx_http_next_header_filter(r); - } - - charsets = mcf->charsets.elts; - r->headers_out.charset = charsets[lcf->default_charset].name; - - if (lcf->default_charset == lcf->source_charset) { - return ngx_http_next_header_filter(r); - } - - ngx_http_create_ctx(r, ctx, ngx_http_charset_filter_module, - sizeof(ngx_http_charset_ctx_t), NGX_ERROR); - - r->filter_need_in_memory = 1; - - return ngx_http_next_header_filter(r); -} - - -static ngx_int_t ngx_http_charset_body_filter(ngx_http_request_t *r, - ngx_chain_t *in) -{ - char *table; - ngx_chain_t *cl; - ngx_http_charset_t *charsets; - ngx_http_charset_ctx_t *ctx; - ngx_http_charset_loc_conf_t *lcf; - ngx_http_charset_main_conf_t *mcf; - - ctx = ngx_http_get_module_ctx(r, ngx_http_charset_filter_module); - - if (ctx == NULL) { - return ngx_http_next_body_filter(r, in); - } - - mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module); - lcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module); - - charsets = mcf->charsets.elts; - table = charsets[lcf->source_charset].tables[lcf->default_charset]; - - for (cl = in; cl; cl = cl->next) { - ngx_charset_recode(cl->buf, table); - } - - return ngx_http_next_body_filter(r, in); -} - - -static ngx_uint_t ngx_charset_recode(ngx_buf_t *b, char *table) -{ - u_char *p; - ngx_uint_t change; - - change = 0; - - for (p = b->pos; p < b->last; p++) { - if (*p != table[*p]) { - change = 1; - break; - } - } - - if (change) { - - while (p < b->last) { - *p = table[*p]; - p++; - } - - b->in_file = 0; - } - - return change; -} - - -static char *ngx_charset_map_block(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf) -{ - ngx_http_charset_main_conf_t *mcf = conf; - - char *rv; - ngx_int_t src, dst; - ngx_uint_t i; - ngx_str_t *value; - ngx_conf_t pvcf; - ngx_http_charset_tables_t *table; - - value = cf->args->elts; - - src = ngx_http_add_charset(&mcf->charsets, &value[1]); - if (src == NGX_ERROR) { - return NGX_CONF_ERROR; - } - - dst = ngx_http_add_charset(&mcf->charsets, &value[2]); - if (dst == NGX_ERROR) { - return NGX_CONF_ERROR; - } - - if (src == dst) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"charset_map\" between the same charsets " - "\"%V\" and \"%V\"", &value[1], &value[2]); - return NGX_CONF_ERROR; - } - - table = mcf->tables.elts; - for (i = 0; i < mcf->tables.nelts; i++) { - if ((src == table->src && dst == table->dst) - || (src == table->dst && dst == table->src)) - { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "duplicate \"charset_map\" between " - "\"%V\" and \"%V\"", &value[1], &value[2]); - return NGX_CONF_ERROR; - } - } - - if (!(table = ngx_push_array(&mcf->tables))) { - return NGX_CONF_ERROR; - } - - table->src = src; - table->dst = dst; - - if (!(table->src2dst = ngx_palloc(cf->pool, 256))) { - return NGX_CONF_ERROR; - } - - if (!(table->dst2src = ngx_palloc(cf->pool, 256))) { - return NGX_CONF_ERROR; - } - - for (i = 0; i < 128; i++) { - table->src2dst[i] = (char) i; - table->dst2src[i] = (char) i; - } - - for (/* void */; i < 256; i++) { - table->src2dst[i] = '?'; - table->dst2src[i] = '?'; - } - - pvcf = *cf; - cf->ctx = table; - cf->handler = ngx_charset_map; - cf->handler_conf = conf; - rv = ngx_conf_parse(cf, NULL); - *cf = pvcf; - - return rv; -} - - -static char *ngx_charset_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) -{ - ngx_int_t src, dst; - ngx_str_t *value; - ngx_http_charset_tables_t *table; - - if (cf->args->nelts != 2) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameters number"); - return NGX_CONF_ERROR; - } - - value = cf->args->elts; - - src = ngx_hextoi(value[0].data, value[0].len); - if (src == NGX_ERROR || src > 255) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid value \"%V\"", &value[0]); - return NGX_CONF_ERROR; - } - - dst = ngx_hextoi(value[1].data, value[1].len); - if (dst == NGX_ERROR || dst > 255) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid value \"%V\"", &value[1]); - return NGX_CONF_ERROR; - } - - table = cf->ctx; - - table->src2dst[src] = (char) dst; - table->dst2src[dst] = (char) src; - - return NGX_CONF_OK; -} - - -static char *ngx_http_set_charset_slot(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf) -{ - char *p = conf; - - ngx_int_t *cp; - ngx_str_t *value; - ngx_http_charset_t *charset; - ngx_http_charset_main_conf_t *mcf; - - cp = (ngx_int_t *) (p + cmd->offset); - - if (*cp != NGX_CONF_UNSET) { - return "is duplicate"; - } - - mcf = ngx_http_conf_get_module_main_conf(cf, - ngx_http_charset_filter_module); - - value = cf->args->elts; - - *cp = ngx_http_add_charset(&mcf->charsets, &value[1]); - if (*cp == NGX_ERROR) { - return NGX_CONF_ERROR; - } - - if (cmd->offset == offsetof(ngx_http_charset_loc_conf_t, source_charset)) { - charset = mcf->charsets.elts; - charset[*cp].server = 1; - } - - return NGX_CONF_OK; -} - - -static ngx_int_t ngx_http_add_charset(ngx_array_t *charsets, ngx_str_t *name) -{ - ngx_uint_t i; - ngx_http_charset_t *c; - - c = charsets->elts; - for (i = 0; i < charsets->nelts; i++) { - if (name->len != c[i].name.len) { - continue; - } - - if (ngx_strcasecmp(name->data, c[i].name.data) == 0) { - break; - } - } - - if (i < charsets->nelts) { - return i; - } - - if (!(c = ngx_push_array(charsets))) { - return NGX_ERROR; - } - - c->tables = NULL; - c->name = *name; - c->server = 0; - - return i; -} - - -static ngx_int_t ngx_http_charset_filter_init(ngx_cycle_t *cycle) -{ - ngx_http_next_header_filter = ngx_http_top_header_filter; - ngx_http_top_header_filter = ngx_http_charset_header_filter; - - ngx_http_next_body_filter = ngx_http_top_body_filter; - ngx_http_top_body_filter = ngx_http_charset_body_filter; - - return NGX_OK; -} - - -static void *ngx_http_charset_create_main_conf(ngx_conf_t *cf) -{ - ngx_http_charset_main_conf_t *mcf; - - if (!(mcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_charset_main_conf_t)))) { - return NGX_CONF_ERROR; - } - - ngx_init_array(mcf->charsets, cf->pool, 2, sizeof(ngx_http_charset_t), - NGX_CONF_ERROR); - - ngx_init_array(mcf->tables, cf->pool, 4, sizeof(ngx_http_charset_tables_t), - NGX_CONF_ERROR); - - return mcf; -} - - -static char *ngx_http_charset_init_main_conf(ngx_conf_t *cf, void *conf) -{ - ngx_http_charset_main_conf_t *mcf = conf; - - ngx_uint_t i, n; - ngx_http_charset_t *charset; - ngx_http_charset_tables_t *tables; - - tables = mcf->tables.elts; - charset = mcf->charsets.elts; - - for (i = 0; i < mcf->charsets.nelts; i++) { - if (!charset[i].server) { - continue; - } - - charset[i].tables = ngx_pcalloc(cf->pool, - sizeof(char *) * mcf->charsets.nelts); - - if (charset[i].tables == NULL) { - return NGX_CONF_ERROR; - } - - for (n = 0; n < mcf->tables.nelts; n++) { - if ((ngx_int_t) i == tables[n].src) { - charset[i].tables[tables[n].dst] = tables[n].src2dst; - continue; - } - - if ((ngx_int_t) i == tables[n].dst) { - charset[i].tables[tables[n].src] = tables[n].dst2src; - } - } - } - - for (i = 0; i < mcf->charsets.nelts; i++) { - if (!charset[i].server) { - continue; - } - - for (n = 0; n < mcf->charsets.nelts; n++) { - if (i == n) { - continue; - } - - if (charset[i].tables[n]) { - continue; - } - - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - " no \"charset_map\" between the charsets " - "\"%V\" and \"%V\"", - &charset[i].name, &charset[n].name); - return NGX_CONF_ERROR; - } - } - - return NGX_CONF_OK; -} - - -static void *ngx_http_charset_create_loc_conf(ngx_conf_t *cf) -{ - ngx_http_charset_loc_conf_t *lcf; - - if (!(lcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_charset_loc_conf_t)))) { - return NGX_CONF_ERROR; - } - - lcf->enable = NGX_CONF_UNSET; - lcf->autodetect = NGX_CONF_UNSET; - lcf->default_charset = NGX_CONF_UNSET; - lcf->source_charset = NGX_CONF_UNSET; - - return lcf; -} - - -static char *ngx_http_charset_merge_loc_conf(ngx_conf_t *cf, - void *parent, void *child) -{ - ngx_http_charset_loc_conf_t *prev = parent; - ngx_http_charset_loc_conf_t *conf = child; - - ngx_conf_merge_value(conf->enable, prev->enable, 0); - ngx_conf_merge_value(conf->autodetect, prev->autodetect, 0); - - - if (conf->default_charset == NGX_CONF_UNSET) { - conf->default_charset = prev->default_charset; - } - - if (conf->source_charset == NGX_CONF_UNSET) { - conf->source_charset = prev->source_charset; - } - - if (conf->default_charset == NGX_CONF_UNSET - && conf->source_charset != NGX_CONF_UNSET) - { - conf->default_charset = conf->source_charset; - } - - if (conf->source_charset == NGX_CONF_UNSET - && conf->default_charset != NGX_CONF_UNSET) - { - conf->source_charset = conf->default_charset; - } - - if (conf->enable - && (conf->default_charset == NGX_CONF_UNSET - || conf->source_charset == NGX_CONF_UNSET)) - { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "the \"source_charset\" or \"default_charset\" " - "must be specified when \"charset\" is on"); - return NGX_CONF_ERROR; - } - - return NGX_CONF_OK; -} diff --git a/src/http/modules/ngx_http_charset_filter_module.c b/src/http/modules/ngx_http_charset_filter_module.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_charset_filter_module.c @@ -0,0 +1,615 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +typedef struct { + char **tables; + ngx_str_t name; + ngx_uint_t server; /* unsigned server:1; */ +} ngx_http_charset_t; + + +typedef struct { + ngx_int_t src; + ngx_int_t dst; + char *src2dst; + char *dst2src; +} ngx_http_charset_tables_t; + + +typedef struct { + ngx_array_t charsets; /* ngx_http_charset_t */ + ngx_array_t tables; /* ngx_http_charset_tables_t */ +} ngx_http_charset_main_conf_t; + + +typedef struct { + ngx_flag_t enable; + ngx_flag_t autodetect; + + ngx_int_t default_charset; + ngx_int_t source_charset; +} ngx_http_charset_loc_conf_t; + + +typedef struct { + ngx_int_t server; + ngx_int_t client; +} ngx_http_charset_ctx_t; + + +static ngx_uint_t ngx_charset_recode(ngx_buf_t *b, char *table); + +static char *ngx_charset_map_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_charset_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf); + +static char *ngx_http_set_charset_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static ngx_int_t ngx_http_add_charset(ngx_array_t *charsets, ngx_str_t *name); + +static ngx_int_t ngx_http_charset_filter_init(ngx_cycle_t *cycle); + +static void *ngx_http_charset_create_main_conf(ngx_conf_t *cf); +static char *ngx_http_charset_init_main_conf(ngx_conf_t *cf, void *conf); +static void *ngx_http_charset_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_charset_merge_loc_conf(ngx_conf_t *cf, + void *parent, void *child); + + +static ngx_command_t ngx_http_charset_filter_commands[] = { + + { ngx_string("charset_map"), + NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE2, + ngx_charset_map_block, + NGX_HTTP_MAIN_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("default_charset"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_set_charset_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_charset_loc_conf_t, default_charset), + NULL }, + + { ngx_string("source_charset"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_set_charset_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_charset_loc_conf_t, source_charset), + NULL }, + + { ngx_string("charset"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_charset_loc_conf_t, enable), + NULL }, + + { ngx_string("autodetect_charset"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_charset_loc_conf_t, autodetect), + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_charset_filter_module_ctx = { + NULL, /* pre conf */ + + ngx_http_charset_create_main_conf, /* create main configuration */ + ngx_http_charset_init_main_conf, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_charset_create_loc_conf, /* create location configuration */ + ngx_http_charset_merge_loc_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_charset_filter_module = { + NGX_MODULE, + &ngx_http_charset_filter_module_ctx, /* module context */ + ngx_http_charset_filter_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + ngx_http_charset_filter_init, /* init module */ + NULL /* init process */ +}; + + +static ngx_http_output_header_filter_pt ngx_http_next_header_filter; +static ngx_http_output_body_filter_pt ngx_http_next_body_filter; + + +static ngx_int_t +ngx_http_charset_header_filter(ngx_http_request_t *r) +{ + ngx_http_charset_t *charsets; + ngx_http_charset_ctx_t *ctx; + ngx_http_charset_loc_conf_t *lcf; + ngx_http_charset_main_conf_t *mcf; + + mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module); + lcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module); + + if (lcf->enable == 0) { + return ngx_http_next_header_filter(r); + } + + if (r->headers_out.content_type == NULL) { + return ngx_http_next_header_filter(r); + } + + if (ngx_strncasecmp(r->headers_out.content_type->value.data, + "text/", 5) != 0 + && ngx_strncasecmp(r->headers_out.content_type->value.data, + "application/x-javascript", 24) != 0) + { + return ngx_http_next_header_filter(r); + } + + if (ngx_strstr(r->headers_out.content_type->value.data, "charset") != NULL) + { + return ngx_http_next_header_filter(r); + } + + if (r->headers_out.status == NGX_HTTP_MOVED_PERMANENTLY + || r->headers_out.status == NGX_HTTP_MOVED_TEMPORARILY) + { + /* + * do not set charset for the redirect because NN 4.x uses this + * charset instead of the next page charset + */ + + r->headers_out.charset.len = 0; + return ngx_http_next_header_filter(r); + } + + if (r->headers_out.charset.len) { + return ngx_http_next_header_filter(r); + } + + charsets = mcf->charsets.elts; + r->headers_out.charset = charsets[lcf->default_charset].name; + + if (lcf->default_charset == lcf->source_charset) { + return ngx_http_next_header_filter(r); + } + + + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_charset_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_http_set_ctx(r, ctx, ngx_http_charset_filter_module); + + + r->filter_need_in_memory = 1; + + return ngx_http_next_header_filter(r); +} + + +static ngx_int_t +ngx_http_charset_body_filter(ngx_http_request_t *r, ngx_chain_t *in) +{ + char *table; + ngx_chain_t *cl; + ngx_http_charset_t *charsets; + ngx_http_charset_ctx_t *ctx; + ngx_http_charset_loc_conf_t *lcf; + ngx_http_charset_main_conf_t *mcf; + + ctx = ngx_http_get_module_ctx(r, ngx_http_charset_filter_module); + + if (ctx == NULL) { + return ngx_http_next_body_filter(r, in); + } + + mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module); + lcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module); + + charsets = mcf->charsets.elts; + table = charsets[lcf->source_charset].tables[lcf->default_charset]; + + for (cl = in; cl; cl = cl->next) { + ngx_charset_recode(cl->buf, table); + } + + return ngx_http_next_body_filter(r, in); +} + + +static ngx_uint_t +ngx_charset_recode(ngx_buf_t *b, char *table) +{ + u_char *p; + ngx_uint_t change; + + change = 0; + + for (p = b->pos; p < b->last; p++) { + if (*p != table[*p]) { + change = 1; + break; + } + } + + if (change) { + + while (p < b->last) { + *p = table[*p]; + p++; + } + + b->in_file = 0; + } + + return change; +} + + +static char * +ngx_charset_map_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_charset_main_conf_t *mcf = conf; + + char *rv; + ngx_int_t src, dst; + ngx_uint_t i; + ngx_str_t *value; + ngx_conf_t pvcf; + ngx_http_charset_tables_t *table; + + value = cf->args->elts; + + src = ngx_http_add_charset(&mcf->charsets, &value[1]); + if (src == NGX_ERROR) { + return NGX_CONF_ERROR; + } + + dst = ngx_http_add_charset(&mcf->charsets, &value[2]); + if (dst == NGX_ERROR) { + return NGX_CONF_ERROR; + } + + if (src == dst) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"charset_map\" between the same charsets " + "\"%V\" and \"%V\"", &value[1], &value[2]); + return NGX_CONF_ERROR; + } + + table = mcf->tables.elts; + for (i = 0; i < mcf->tables.nelts; i++) { + if ((src == table->src && dst == table->dst) + || (src == table->dst && dst == table->src)) + { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "duplicate \"charset_map\" between " + "\"%V\" and \"%V\"", &value[1], &value[2]); + return NGX_CONF_ERROR; + } + } + + table = ngx_array_push(&mcf->tables); + if (table == NULL) { + return NGX_CONF_ERROR; + } + + table->src = src; + table->dst = dst; + + table->src2dst = ngx_palloc(cf->pool, 256); + if (table->src2dst == NULL) { + return NGX_CONF_ERROR; + } + + table->dst2src = ngx_palloc(cf->pool, 256); + if (table->dst2src == NULL) { + return NGX_CONF_ERROR; + } + + for (i = 0; i < 128; i++) { + table->src2dst[i] = (char) i; + table->dst2src[i] = (char) i; + } + + for (/* void */; i < 256; i++) { + table->src2dst[i] = '?'; + table->dst2src[i] = '?'; + } + + pvcf = *cf; + cf->ctx = table; + cf->handler = ngx_charset_map; + cf->handler_conf = conf; + + rv = ngx_conf_parse(cf, NULL); + + *cf = pvcf; + + return rv; +} + + +static char * +ngx_charset_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) +{ + ngx_int_t src, dst; + ngx_str_t *value; + ngx_http_charset_tables_t *table; + + if (cf->args->nelts != 2) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameters number"); + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + + src = ngx_hextoi(value[0].data, value[0].len); + if (src == NGX_ERROR || src > 255) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid value \"%V\"", &value[0]); + return NGX_CONF_ERROR; + } + + dst = ngx_hextoi(value[1].data, value[1].len); + if (dst == NGX_ERROR || dst > 255) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid value \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } + + table = cf->ctx; + + table->src2dst[src] = (char) dst; + table->dst2src[dst] = (char) src; + + return NGX_CONF_OK; +} + + +static char * +ngx_http_set_charset_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *p = conf; + + ngx_int_t *cp; + ngx_str_t *value; + ngx_http_charset_t *charset; + ngx_http_charset_main_conf_t *mcf; + + cp = (ngx_int_t *) (p + cmd->offset); + + if (*cp != NGX_CONF_UNSET) { + return "is duplicate"; + } + + mcf = ngx_http_conf_get_module_main_conf(cf, + ngx_http_charset_filter_module); + + value = cf->args->elts; + + *cp = ngx_http_add_charset(&mcf->charsets, &value[1]); + if (*cp == NGX_ERROR) { + return NGX_CONF_ERROR; + } + + if (cmd->offset == offsetof(ngx_http_charset_loc_conf_t, source_charset)) { + charset = mcf->charsets.elts; + charset[*cp].server = 1; + } + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_add_charset(ngx_array_t *charsets, ngx_str_t *name) +{ + ngx_uint_t i; + ngx_http_charset_t *c; + + c = charsets->elts; + for (i = 0; i < charsets->nelts; i++) { + if (name->len != c[i].name.len) { + continue; + } + + if (ngx_strcasecmp(name->data, c[i].name.data) == 0) { + break; + } + } + + if (i < charsets->nelts) { + return i; + } + + c = ngx_array_push(charsets); + if (c == NULL) { + return NGX_ERROR; + } + + c->tables = NULL; + c->name = *name; + c->server = 0; + + return i; +} + + +static ngx_int_t +ngx_http_charset_filter_init(ngx_cycle_t *cycle) +{ + ngx_http_next_header_filter = ngx_http_top_header_filter; + ngx_http_top_header_filter = ngx_http_charset_header_filter; + + ngx_http_next_body_filter = ngx_http_top_body_filter; + ngx_http_top_body_filter = ngx_http_charset_body_filter; + + return NGX_OK; +} + + +static void * +ngx_http_charset_create_main_conf(ngx_conf_t *cf) +{ + ngx_http_charset_main_conf_t *mcf; + + mcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_charset_main_conf_t)); + if (mcf == NULL) { + return NGX_CONF_ERROR; + } + + if (ngx_array_init(&mcf->charsets, cf->pool, 2, sizeof(ngx_http_charset_t)) + == NGX_ERROR) + { + return NGX_CONF_ERROR; + } + + if (ngx_array_init(&mcf->tables, cf->pool, 4, + sizeof(ngx_http_charset_tables_t)) == NGX_ERROR) + { + return NGX_CONF_ERROR; + } + + return mcf; +} + + +static char * +ngx_http_charset_init_main_conf(ngx_conf_t *cf, void *conf) +{ + ngx_http_charset_main_conf_t *mcf = conf; + + ngx_uint_t i, n; + ngx_http_charset_t *charset; + ngx_http_charset_tables_t *tables; + + tables = mcf->tables.elts; + charset = mcf->charsets.elts; + + for (i = 0; i < mcf->charsets.nelts; i++) { + if (!charset[i].server) { + continue; + } + + charset[i].tables = ngx_pcalloc(cf->pool, + sizeof(char *) * mcf->charsets.nelts); + if (charset[i].tables == NULL) { + return NGX_CONF_ERROR; + } + + for (n = 0; n < mcf->tables.nelts; n++) { + if ((ngx_int_t) i == tables[n].src) { + charset[i].tables[tables[n].dst] = tables[n].src2dst; + continue; + } + + if ((ngx_int_t) i == tables[n].dst) { + charset[i].tables[tables[n].src] = tables[n].dst2src; + } + } + } + + for (i = 0; i < mcf->charsets.nelts; i++) { + if (!charset[i].server) { + continue; + } + + for (n = 0; n < mcf->charsets.nelts; n++) { + if (i == n) { + continue; + } + + if (charset[i].tables[n]) { + continue; + } + + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + " no \"charset_map\" between the charsets " + "\"%V\" and \"%V\"", + &charset[i].name, &charset[n].name); + return NGX_CONF_ERROR; + } + } + + return NGX_CONF_OK; +} + + +static void * +ngx_http_charset_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_charset_loc_conf_t *lcf; + + lcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_charset_loc_conf_t)); + if (lcf == NULL) { + return NGX_CONF_ERROR; + } + + lcf->enable = NGX_CONF_UNSET; + lcf->autodetect = NGX_CONF_UNSET; + lcf->default_charset = NGX_CONF_UNSET; + lcf->source_charset = NGX_CONF_UNSET; + + return lcf; +} + + +static char * +ngx_http_charset_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_charset_loc_conf_t *prev = parent; + ngx_http_charset_loc_conf_t *conf = child; + + ngx_conf_merge_value(conf->enable, prev->enable, 0); + ngx_conf_merge_value(conf->autodetect, prev->autodetect, 0); + + + if (conf->default_charset == NGX_CONF_UNSET) { + conf->default_charset = prev->default_charset; + } + + if (conf->source_charset == NGX_CONF_UNSET) { + conf->source_charset = prev->source_charset; + } + + if (conf->default_charset == NGX_CONF_UNSET + && conf->source_charset != NGX_CONF_UNSET) + { + conf->default_charset = conf->source_charset; + } + + if (conf->source_charset == NGX_CONF_UNSET + && conf->default_charset != NGX_CONF_UNSET) + { + conf->source_charset = conf->default_charset; + } + + if (conf->enable + && (conf->default_charset == NGX_CONF_UNSET + || conf->source_charset == NGX_CONF_UNSET)) + { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the \"source_charset\" or \"default_charset\" " + "must be specified when \"charset\" is on"); + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} diff --git a/src/http/modules/ngx_http_chunked_filter.c b/src/http/modules/ngx_http_chunked_filter.c deleted file mode 100644 --- a/src/http/modules/ngx_http_chunked_filter.c +++ /dev/null @@ -1,173 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#include -#include -#include - - -static ngx_int_t ngx_http_chunked_filter_init(ngx_cycle_t *cycle); - - -static ngx_http_module_t ngx_http_chunked_filter_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_chunked_filter_module = { - NGX_MODULE, - &ngx_http_chunked_filter_module_ctx, /* module context */ - NULL, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - ngx_http_chunked_filter_init, /* init module */ - NULL /* init process */ -}; - - -static ngx_http_output_header_filter_pt ngx_http_next_header_filter; -static ngx_http_output_body_filter_pt ngx_http_next_body_filter; - - -static ngx_int_t ngx_http_chunked_header_filter(ngx_http_request_t *r) -{ - if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED) { - return ngx_http_next_header_filter(r); - } - - if (r->headers_out.content_length_n == -1) { - if (r->http_version < NGX_HTTP_VERSION_11) { - r->keepalive = 0; - - } else { - r->chunked = 1; - } - } - - return ngx_http_next_header_filter(r); -} - - -static ngx_int_t ngx_http_chunked_body_filter(ngx_http_request_t *r, - ngx_chain_t *in) -{ - u_char *chunk; - off_t size; - ngx_buf_t *b; - ngx_chain_t out, tail, *cl, *tl, **ll; - - if (in == NULL || !r->chunked || r->header_only) { - return ngx_http_next_body_filter(r, in); - } - - out.buf = NULL; - ll = &out.next; - - size = 0; - cl = in; - - for ( ;; ) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http chunk: %d", ngx_buf_size(cl->buf)); - - size += ngx_buf_size(cl->buf); - - if (cl->buf->flush || ngx_buf_in_memory(cl->buf) || cl->buf->in_file) { - - if (!(tl = ngx_alloc_chain_link(r->pool))) { - return NGX_ERROR; - } - - tl->buf = cl->buf; - *ll = tl; - ll = &tl->next; - } - - if (cl->next == NULL) { - break; - } - - cl = cl->next; - } - - if (size) { - if (!(b = ngx_calloc_buf(r->pool))) { - return NGX_ERROR; - } - - chunk = ngx_palloc(r->pool, sizeof("0000000000000000" CRLF) - 1); - if (chunk == NULL) { - return NGX_ERROR; - } - - b->temporary = 1; - b->pos = chunk; - b->last = ngx_sprintf(chunk, "%xO" CRLF, size); - - out.buf = b; - } - - if (cl->buf->last_buf) { - if (!(b = ngx_calloc_buf(r->pool))) { - return NGX_ERROR; - } - - b->memory = 1; - b->last_buf = 1; - b->pos = (u_char *) CRLF "0" CRLF CRLF; - b->last = b->pos + 7; - - cl->buf->last_buf = 0; - - if (size == 0) { - b->pos += 2; - out.buf = b; - out.next = NULL; - - return ngx_http_next_body_filter(r, &out); - } - - } else { - if (size == 0) { - *ll = NULL; - return ngx_http_next_body_filter(r, out.next); - } - - if (!(b = ngx_calloc_buf(r->pool))) { - return NGX_ERROR; - } - - b->memory = 1; - b->pos = (u_char *) CRLF; - b->last = b->pos + 2; - } - - tail.buf = b; - tail.next = NULL; - *ll = &tail; - - return ngx_http_next_body_filter(r, &out); -} - - -static ngx_int_t ngx_http_chunked_filter_init(ngx_cycle_t *cycle) -{ - ngx_http_next_header_filter = ngx_http_top_header_filter; - ngx_http_top_header_filter = ngx_http_chunked_header_filter; - - ngx_http_next_body_filter = ngx_http_top_body_filter; - ngx_http_top_body_filter = ngx_http_chunked_body_filter; - - return NGX_OK; -} diff --git a/src/http/modules/ngx_http_chunked_filter_module.c b/src/http/modules/ngx_http_chunked_filter_module.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_chunked_filter_module.c @@ -0,0 +1,181 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +static ngx_int_t ngx_http_chunked_filter_init(ngx_cycle_t *cycle); + + +static ngx_http_module_t ngx_http_chunked_filter_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_chunked_filter_module = { + NGX_MODULE, + &ngx_http_chunked_filter_module_ctx, /* module context */ + NULL, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + ngx_http_chunked_filter_init, /* init module */ + NULL /* init process */ +}; + + +static ngx_http_output_header_filter_pt ngx_http_next_header_filter; +static ngx_http_output_body_filter_pt ngx_http_next_body_filter; + + +static ngx_int_t +ngx_http_chunked_header_filter(ngx_http_request_t *r) +{ + if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED) { + return ngx_http_next_header_filter(r); + } + + if (r->headers_out.content_length_n == -1) { + if (r->http_version < NGX_HTTP_VERSION_11) { + r->keepalive = 0; + + } else { + r->chunked = 1; + } + } + + return ngx_http_next_header_filter(r); +} + + +static ngx_int_t +ngx_http_chunked_body_filter(ngx_http_request_t *r, ngx_chain_t *in) +{ + u_char *chunk; + off_t size; + ngx_buf_t *b; + ngx_chain_t out, tail, *cl, *tl, **ll; + + if (in == NULL || !r->chunked || r->header_only) { + return ngx_http_next_body_filter(r, in); + } + + out.buf = NULL; + ll = &out.next; + + size = 0; + cl = in; + + for ( ;; ) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http chunk: %d", ngx_buf_size(cl->buf)); + + size += ngx_buf_size(cl->buf); + + if (cl->buf->flush || ngx_buf_in_memory(cl->buf) || cl->buf->in_file) { + + tl = ngx_alloc_chain_link(r->pool); + if (tl == NULL) { + return NGX_ERROR; + } + + tl->buf = cl->buf; + *ll = tl; + ll = &tl->next; + } + + if (cl->next == NULL) { + break; + } + + cl = cl->next; + } + + if (size) { + b = ngx_calloc_buf(r->pool); + if (b == NULL) { + return NGX_ERROR; + } + + /* the "0000000000000000" is 64-bit hexadimal string */ + + chunk = ngx_palloc(r->pool, sizeof("0000000000000000" CRLF) - 1); + if (chunk == NULL) { + return NGX_ERROR; + } + + b->temporary = 1; + b->pos = chunk; + b->last = ngx_sprintf(chunk, "%xO" CRLF, size); + + out.buf = b; + } + + if (cl->buf->last_buf) { + b = ngx_calloc_buf(r->pool); + if (b == NULL) { + return NGX_ERROR; + } + + b->memory = 1; + b->last_buf = 1; + b->pos = (u_char *) CRLF "0" CRLF CRLF; + b->last = b->pos + 7; + + cl->buf->last_buf = 0; + + if (size == 0) { + b->pos += 2; + out.buf = b; + out.next = NULL; + + return ngx_http_next_body_filter(r, &out); + } + + } else { + if (size == 0) { + *ll = NULL; + return ngx_http_next_body_filter(r, out.next); + } + + b = ngx_calloc_buf(r->pool); + if (b == NULL) { + return NGX_ERROR; + } + + b->memory = 1; + b->pos = (u_char *) CRLF; + b->last = b->pos + 2; + } + + tail.buf = b; + tail.next = NULL; + *ll = &tail; + + return ngx_http_next_body_filter(r, &out); +} + + +static ngx_int_t +ngx_http_chunked_filter_init(ngx_cycle_t *cycle) +{ + ngx_http_next_header_filter = ngx_http_top_header_filter; + ngx_http_top_header_filter = ngx_http_chunked_header_filter; + + ngx_http_next_body_filter = ngx_http_top_body_filter; + ngx_http_top_body_filter = ngx_http_chunked_body_filter; + + return NGX_OK; +} diff --git a/src/http/modules/ngx_http_fastcgi_handler.c b/src/http/modules/ngx_http_fastcgi_handler.c deleted file mode 100644 --- a/src/http/modules/ngx_http_fastcgi_handler.c +++ /dev/null @@ -1,2272 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#include -#include -#include -#include - - -typedef struct { - ngx_http_upstream_conf_t upstream; - - ngx_peers_t *peers; - - ngx_uint_t params; - - ngx_str_t root; - ngx_str_t index; - - ngx_array_t *vars; - - ngx_str_t *location; -} ngx_http_fastcgi_loc_conf_t; - - -typedef struct { - ngx_list_t headers; - - ngx_table_elt_t *status; - - ngx_table_elt_t *content_type; - ngx_table_elt_t *content_length; - ngx_table_elt_t *x_powered_by; - -#if (NGX_HTTP_GZIP) - ngx_table_elt_t *content_encoding; -#endif -} ngx_http_fastcgi_headers_in_t; - - -typedef struct { - ngx_http_fastcgi_headers_in_t headers_in; -} ngx_http_fastcgi_upstream_t; - - -typedef enum { - ngx_http_fastcgi_st_version = 0, - ngx_http_fastcgi_st_type, - ngx_http_fastcgi_st_request_id_hi, - ngx_http_fastcgi_st_request_id_lo, - ngx_http_fastcgi_st_content_length_hi, - ngx_http_fastcgi_st_content_length_lo, - ngx_http_fastcgi_st_padding_length, - ngx_http_fastcgi_st_reserved, - ngx_http_fastcgi_st_data, - ngx_http_fastcgi_st_padding, -} ngx_http_fastcgi_state_e; - - -typedef struct { - ngx_http_fastcgi_state_e state; - u_char *pos; - u_char *last; - ngx_uint_t type; - size_t length; - size_t padding; - - ngx_uint_t header; - - ngx_http_fastcgi_upstream_t *upstream; -} ngx_http_fastcgi_ctx_t; - - -#define NGX_HTTP_FASTCGI_REMOTE_ADDR 0x00000002 -#define NGX_HTTP_FASTCGI_REMOTE_USER 0x00000004 -#define NGX_HTTP_FASTCGI_SERVER_NAME 0x00000008 -#define NGX_HTTP_FASTCGI_SERVER_ADDR 0x00000010 -#define NGX_HTTP_FASTCGI_SERVER_PORT 0x00000020 -#define NGX_HTTP_FASTCGI_SCRIPT_NAME 0x00000040 -#define NGX_HTTP_FASTCGI_AUTH_TYPE 0x00000080 -#define NGX_HTTP_FASTCGI_SERVER_PROTOCOL 0x00000100 -#define NGX_HTTP_FASTCGI_SERVER_SOFTWARE 0x00000200 -#define NGX_HTTP_FASTCGI_GATEWAY_INTERFACE 0x00000400 -#define NGX_HTTP_FASTCGI_REQUEST_URI 0x00000800 -#define NGX_HTTP_FASTCGI_REDIRECT_STATUS 0x00001000 -#define NGX_HTTP_FASTCGI_DOCUMENT_ROOT 0x00002000 -#define NGX_HTTP_FASTCGI_SCRIPT_FILENAME 0x00004000 -#define NGX_HTTP_FASTCGI_REMOTE_PORT 0x00008000 - - -#define NGX_HTTP_FASTCGI_RESPONDER 1 - -#define NGX_HTTP_FASTCGI_BEGIN_REQUEST 1 -#define NGX_HTTP_FASTCGI_ABORT_REQUEST 2 -#define NGX_HTTP_FASTCGI_END_REQUEST 3 -#define NGX_HTTP_FASTCGI_PARAMS 4 -#define NGX_HTTP_FASTCGI_STDIN 5 -#define NGX_HTTP_FASTCGI_STDOUT 6 -#define NGX_HTTP_FASTCGI_STDERR 7 -#define NGX_HTTP_FASTCGI_DATA 8 - - -typedef struct { - u_char version; - u_char type; - u_char request_id_hi; - u_char request_id_lo; - u_char content_length_hi; - u_char content_length_lo; - u_char padding_length; - u_char reserved; -} ngx_http_fastcgi_header_t; - - -typedef struct { - u_char role_hi; - u_char role_lo; - u_char flags; - u_char reserved[5]; -} ngx_http_fastcgi_begin_request_t; - - -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); -static ngx_int_t ngx_http_fastcgi_send_header(ngx_http_request_t *r); -static ngx_int_t ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, - ngx_buf_t *buf); -static ngx_int_t ngx_http_fastcgi_process_record(ngx_http_request_t *r, - ngx_http_fastcgi_ctx_t *f); -static void ngx_http_fastcgi_abort_request(ngx_http_request_t *r); -static void ngx_http_fastcgi_finalize_request(ngx_http_request_t *r, - ngx_int_t rc); - -static char *ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); -static char *ngx_http_fastcgi_set_var(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); -static char *ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post, - void *data); -static void *ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf); -static char *ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, - void *parent, void *child); - - -static ngx_str_t ngx_http_fastcgi_methods[] = { - ngx_string("GET"), - ngx_string("HEAD"), - ngx_string("POST") -}; - - -static ngx_str_t ngx_http_fastcgi_uri = ngx_string("/"); - - -static ngx_http_header_t ngx_http_fastcgi_headers_in[] = { - { ngx_string("Status"), offsetof(ngx_http_fastcgi_headers_in_t, status) }, - - { ngx_string("Content-Type"), - offsetof(ngx_http_fastcgi_headers_in_t, content_type) }, - - { ngx_string("Content-Length"), - offsetof(ngx_http_fastcgi_headers_in_t, content_length) }, - - { ngx_string("X-Powered-By"), - offsetof(ngx_http_fastcgi_headers_in_t, x_powered_by) }, - -#if (NGX_HTTP_GZIP) - { ngx_string("Content-Encoding"), - offsetof(ngx_http_fastcgi_headers_in_t, content_encoding) }, -#endif - - { ngx_null_string, 0 } -}; - - -static ngx_conf_post_t ngx_http_fastcgi_lowat_post = - { ngx_http_fastcgi_lowat_check }; - -static ngx_conf_bitmask_t ngx_http_fastcgi_next_upstream_masks[] = { - { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR }, - { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT }, - { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER }, - { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 }, - { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 }, - { ngx_null_string, 0 } -}; - - -static ngx_conf_bitmask_t ngx_http_fastcgi_params_masks[] = { - { ngx_string("remote_addr"), NGX_HTTP_FASTCGI_REMOTE_ADDR }, - { ngx_string("server_port"), NGX_HTTP_FASTCGI_SERVER_PORT }, - { ngx_string("server_addr"), NGX_HTTP_FASTCGI_SERVER_ADDR }, - { ngx_string("server_name"), NGX_HTTP_FASTCGI_SERVER_NAME }, - { ngx_string("script_name"), NGX_HTTP_FASTCGI_SCRIPT_NAME }, - - { ngx_string("server_protocol"), NGX_HTTP_FASTCGI_SERVER_PROTOCOL }, - { ngx_string("server_software"), NGX_HTTP_FASTCGI_SERVER_SOFTWARE }, - { ngx_string("gateway_interface"), NGX_HTTP_FASTCGI_GATEWAY_INTERFACE }, - - { ngx_string("redirect_status"), NGX_HTTP_FASTCGI_REDIRECT_STATUS }, - { ngx_string("request_uri"), NGX_HTTP_FASTCGI_REQUEST_URI }, - - { ngx_string("document_root"), NGX_HTTP_FASTCGI_DOCUMENT_ROOT }, - { ngx_string("script_filename"), NGX_HTTP_FASTCGI_SCRIPT_FILENAME }, - { ngx_string("remote_port"), NGX_HTTP_FASTCGI_REMOTE_PORT }, - - { ngx_null_string, 0 } -}; - - -static ngx_command_t ngx_http_fastcgi_commands[] = { - - { ngx_string("fastcgi_pass"), - NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_http_fastcgi_pass, - NGX_HTTP_LOC_CONF_OFFSET, - 0, - NULL }, - - { ngx_string("fastcgi_root"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_fastcgi_loc_conf_t, root), - NULL }, - - { ngx_string("fastcgi_index"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_str_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_fastcgi_loc_conf_t, index), - NULL }, - - { ngx_string("fastcgi_connect_timeout"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_msec_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_fastcgi_loc_conf_t, upstream.connect_timeout), - NULL }, - - { ngx_string("fastcgi_send_timeout"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_msec_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_fastcgi_loc_conf_t, upstream.send_timeout), - NULL }, - - { ngx_string("fastcgi_send_lowat"), - 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_fastcgi_loc_conf_t, upstream.send_lowat), - &ngx_http_fastcgi_lowat_post }, - - { ngx_string("fastcgi_header_buffer_size"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_fastcgi_loc_conf_t, upstream.header_buffer_size), - NULL }, - - { ngx_string("fastcgi_redirect_errors"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_fastcgi_loc_conf_t, upstream.redirect_errors), - NULL }, - - { ngx_string("fastcgi_x_powered_by"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_fastcgi_loc_conf_t, upstream.x_powered_by), - NULL }, - - { ngx_string("fastcgi_read_timeout"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_msec_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_fastcgi_loc_conf_t, upstream.read_timeout), - NULL }, - - { ngx_string("fastcgi_buffers"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, - ngx_conf_set_bufs_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_fastcgi_loc_conf_t, upstream.bufs), - NULL }, - - { ngx_string("fastcgi_busy_buffers_size"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_fastcgi_loc_conf_t, upstream.busy_buffers_size), - NULL }, - - { 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 }, - - { ngx_string("fastcgi_max_temp_file_size"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_fastcgi_loc_conf_t, upstream.max_temp_file_size), - NULL }, - - { ngx_string("fastcgi_temp_file_write_size"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_fastcgi_loc_conf_t, upstream.temp_file_write_size), - NULL }, - - { ngx_string("fastcgi_next_upstream"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY, - ngx_conf_set_bitmask_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_fastcgi_loc_conf_t, upstream.next_upstream), - &ngx_http_fastcgi_next_upstream_masks }, - - { ngx_string("fastcgi_set_var"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_http_fastcgi_set_var, - NGX_HTTP_LOC_CONF_OFFSET, - 0, - NULL }, - - { ngx_string("fastcgi_params"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY, - ngx_conf_set_bitmask_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_fastcgi_loc_conf_t, params), - &ngx_http_fastcgi_params_masks }, - - ngx_null_command -}; - - -ngx_http_module_t ngx_http_fastcgi_module_ctx = { - NULL, /* pre conf */ - - NULL, /* create main configuration */ - NULL, /* init main configuration */ - - NULL, /* create server configuration */ - NULL, /* merge server configuration */ - - ngx_http_fastcgi_create_loc_conf, /* create location configuration */ - ngx_http_fastcgi_merge_loc_conf /* merge location configuration */ -}; - - -ngx_module_t ngx_http_fastcgi_module = { - NGX_MODULE, - &ngx_http_fastcgi_module_ctx, /* module context */ - ngx_http_fastcgi_commands, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - NULL, /* init module */ - NULL /* init process */ -}; - - -static ngx_int_t -ngx_http_fastcgi_handler(ngx_http_request_t *r) -{ - ngx_int_t rc; - ngx_http_upstream_t *u; - ngx_http_fastcgi_loc_conf_t *flcf; - - flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); - - if (!(u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t)))) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - u->peer.log = r->connection->log; - u->peer.log_error = NGX_ERROR_ERR; - u->peer.peers = flcf->peers; - u->peer.tries = flcf->peers->number; -#if (NGX_THREADS) - u->peer.lock = &r->connection->lock; -#endif - - u->output.tag = (ngx_buf_tag_t) &ngx_http_fastcgi_module; - - u->conf = &flcf->upstream; - - u->location = flcf->location; - - u->create_request = ngx_http_fastcgi_create_request; - u->reinit_request = ngx_http_fastcgi_reinit_request; - u->process_header = ngx_http_fastcgi_process_header; - u->send_header = ngx_http_fastcgi_send_header; - u->abort_request = ngx_http_fastcgi_abort_request; - u->finalize_request = ngx_http_fastcgi_finalize_request; - - u->pipe.input_filter = ngx_http_fastcgi_input_filter; - u->pipe.input_ctx = r; - - u->log_ctx = r->connection->log->data; - u->log_handler = ngx_http_upstream_log_error; - - u->schema.len = sizeof("fastcgi://") - 1; - u->schema.data = (u_char *) "fastcgi://"; - u->uri.len = sizeof("/") - 1; - u->uri.data = (u_char *) "/"; - - r->upstream = u; - - rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init); - - if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { - return rc; - } - - return NGX_DONE; -} - - -static ngx_int_t -ngx_http_fastcgi_create_request(ngx_http_request_t *r) -{ - u_char ch, *pos, addr_text[INET_ADDRSTRLEN], - port_text[sizeof("65535") - 1]; - size_t size, len, index, padding, - addr_len, port_len; - off_t file_pos; - ngx_buf_t *b; - socklen_t slen; - ngx_chain_t *cl, *body; - ngx_uint_t i, n, next, *vindex, port; - ngx_list_part_t *part; - ngx_table_elt_t *header; - struct sockaddr_in sin, *sinp; - ngx_http_variable_t *var; - ngx_http_variable_value_t *value; - ngx_http_core_loc_conf_t *clcf; - ngx_http_core_main_conf_t *cmcf; - ngx_http_fastcgi_header_t *h; - ngx_http_fastcgi_loc_conf_t *flcf; - ngx_http_fastcgi_begin_request_t *br; - - - flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); - - if ((flcf->params & NGX_HTTP_FASTCGI_SERVER_ADDR) && r->in_addr == 0) { - - slen = sizeof(struct sockaddr_in); - if (getsockname(r->connection->fd, - (struct sockaddr *) &sin, &slen) == -1) - { - ngx_log_error(NGX_LOG_CRIT, r->connection->log, - ngx_socket_errno, "getsockname() failed"); - return NGX_ERROR; - } - - r->in_addr = sin.sin_addr.s_addr; - } - - addr_len = ngx_inet_ntop(r->connection->listening->family, &r->in_addr, - addr_text, INET_ADDRSTRLEN); - if (addr_len == 0) { - return NGX_ERROR; - } - -#if (NGX_SUPPRESS_WARN) - clcf = NULL; - var = NULL; - vindex = NULL; -#endif - - - if (r->upstream->method) { - len = 1 + 1 + sizeof("REQUEST_METHOD") - 1 - + ngx_http_fastcgi_methods[r->upstream->method - 1].len; - - } else { - len = 1 + ((r->method_name.len - 1 > 127) ? 4 : 1) - + sizeof("REQUEST_METHOD") - 1 - + r->method_name.len - 1; - } - - - index = (r->uri.data[r->uri.len - 1] == '/') ? flcf->index.len : 0; - - len += 1 + ((flcf->root.len + r->uri.len + index > 127) ? 4 : 1) - + sizeof("PATH_TRANSLATED") - 1 - + flcf->root.len + r->uri.len + index; - - if (r->args.len) { - len += 1 + ((r->args.len > 127) ? 4 : 1) + sizeof("QUERY_STRING") - 1 - + r->args.len; - } - - if (r->headers_in.content_length_n > 0) { - len += 1 + ((r->headers_in.content_length->value.len > 127) ? 4 : 1) - + sizeof("CONTENT_LENGTH") - 1 - + r->headers_in.content_length->value.len; - } - - - if (r->headers_in.content_type) { - len += 1 + ((r->headers_in.content_type->value.len > 127) ? 4 : 1) - + sizeof("CONTENT_TYPE") - 1 - + r->headers_in.content_type->value.len; - } - - - if (flcf->params & NGX_HTTP_FASTCGI_REDIRECT_STATUS) { - len += 1 + 1 + sizeof("REDIRECT_STATUS200") - 1; - } - - if (flcf->params & NGX_HTTP_FASTCGI_REQUEST_URI) { - len += 1 + ((r->unparsed_uri.len > 127) ? 4 : 1) - + sizeof("REQUEST_URI") - 1 + r->unparsed_uri.len; - } - - if (flcf->params & NGX_HTTP_FASTCGI_DOCUMENT_ROOT) { - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - len += 1 + ((clcf->root.len > 127) ? 4 : 1) - + sizeof("DOCUMENT_ROOT") - 1 + clcf->root.len; - } - - if (flcf->params & NGX_HTTP_FASTCGI_SCRIPT_FILENAME) { - len += 1 + ((flcf->root.len + r->uri.len + index > 127) ? 4 : 1) - + sizeof("SCRIPT_FILENAME") - 1 - + flcf->root.len + r->uri.len + index; - } - - if (flcf->params & NGX_HTTP_FASTCGI_SCRIPT_NAME) { - len += 1 + ((r->uri.len + index > 127) ? 4 : 1) - + sizeof("SCRIPT_NAME") - 1 + r->uri.len + index ; - } - - if (flcf->params & NGX_HTTP_FASTCGI_REMOTE_ADDR) { - len += 1 + 1 + sizeof("REMOTE_ADDR") - 1 + r->connection->addr_text.len; - } - - port_len = 0; - - if (flcf->params & NGX_HTTP_FASTCGI_REMOTE_PORT) { - - /* AF_INET only */ - - if (r->connection->sockaddr->sa_family == AF_INET) { - sinp = (struct sockaddr_in *) r->connection->sockaddr; - - port = ntohs(sinp->sin_port); - - if (port > 0 && port < 65536) { - port_len = ngx_sprintf(port_text, "%ui", port) - port_text; - } - - len += 1 + 1 + sizeof("REMOTE_PORT") - 1 + port_len; - } - } - - if (flcf->params & NGX_HTTP_FASTCGI_SERVER_NAME) { - len += 1 + 1 + sizeof("SERVER_NAME") - 1 + r->server_name.len; - } - - if (flcf->params & NGX_HTTP_FASTCGI_SERVER_PORT) { - len += 1 + 1 + sizeof("SERVER_PORT") - 1 + r->port_text->len - 1; - } - - if (flcf->params & NGX_HTTP_FASTCGI_SERVER_ADDR) { - len += 1 + 1 + sizeof("SERVER_ADDR") - 1 + addr_len; - } - - if (flcf->params & NGX_HTTP_FASTCGI_SERVER_PROTOCOL - && r->http_protocol.len) - { - len += 1 + ((r->http_protocol.len > 127) ? 4 : 1) - + sizeof("SERVER_PROTOCOL") - 1 + r->http_protocol.len; - } - - if (flcf->params & NGX_HTTP_FASTCGI_SERVER_SOFTWARE) { - len += 1 + 1 + sizeof("SERVER_SOFTWARE") - 1 + sizeof(NGINX_VER) - 1; - } - - if (flcf->params & NGX_HTTP_FASTCGI_GATEWAY_INTERFACE) { - len += 1 + 1 + sizeof("GATEWAY_INTERFACE") - 1 + sizeof("CGI/1.1") - 1; - } - - - if (flcf->vars) { - cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); - - var = cmcf->variables.elts; - vindex = flcf->vars->elts; - - for (i = 0; i < flcf->vars->nelts; i++) { - - if (!(value = ngx_http_get_indexed_variable(r, vindex[i]))) { - continue; - } - - if (value->text.len) { - len += 1 + 1 + var[vindex[i]].name.len + value->text.len; - } - } - } - - - part = &r->headers_in.headers.part; - header = part->elts; - - for (i = 0; /* void */; i++) { - - if (i >= part->nelts) { - if (part->next == NULL) { - break; - } - - part = part->next; - header = part->elts; - i = 0; - } - - len += ((header[i].key.len > 127) ? 4 : 1) - + ((header[i].value.len > 127) ? 4 : 1) - + 5 + header[i].key.len + header[i].value.len; - } - - - if (len > 65535) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - "fastcgi: the request record is too big"); - return NGX_ERROR; - } - - - padding = 8 - len % 8; - padding = (padding == 8) ? 0 : padding; - - - size = sizeof(ngx_http_fastcgi_header_t) - + sizeof(ngx_http_fastcgi_begin_request_t) - - + sizeof(ngx_http_fastcgi_header_t) /* NGX_HTTP_FASTCGI_PARAMS */ - + len + padding - + sizeof(ngx_http_fastcgi_header_t) /* NGX_HTTP_FASTCGI_PARAMS */ - - + sizeof(ngx_http_fastcgi_header_t); /* NGX_HTTP_FASTCGI_STDIN */ - - - if (!(b = ngx_create_temp_buf(r->pool, size))) { - return NGX_ERROR; - } - - if (!(cl = ngx_alloc_chain_link(r->pool))) { - return NGX_ERROR; - } - - cl->buf = b; - - h = (ngx_http_fastcgi_header_t *) b->pos; - - h->version = 1; - h->type = NGX_HTTP_FASTCGI_BEGIN_REQUEST; - h->request_id_hi = 0; - h->request_id_lo = 1; - h->content_length_hi = 0; - h->content_length_lo = sizeof(ngx_http_fastcgi_begin_request_t); - h->padding_length = 0; - h->reserved = 0; - - br = (ngx_http_fastcgi_begin_request_t *) - (b->pos + sizeof(ngx_http_fastcgi_header_t)); - br->role_hi = 0; - br->role_lo = NGX_HTTP_FASTCGI_RESPONDER; - br->flags = 0; /* NGX_HTTP_FASTCGI_KEEP_CONN */ - br->reserved[0] = 0; - br->reserved[1] = 0; - br->reserved[2] = 0; - br->reserved[3] = 0; - br->reserved[4] = 0; - - h = (ngx_http_fastcgi_header_t *) - (b->pos + sizeof(ngx_http_fastcgi_header_t) - + sizeof(ngx_http_fastcgi_begin_request_t)); - - h->version = 1; - h->type = NGX_HTTP_FASTCGI_PARAMS; - h->request_id_hi = 0; - h->request_id_lo = 1; - h->content_length_hi = (u_char) ((len >> 8) & 0xff); - h->content_length_lo = (u_char) (len & 0xff); - h->padding_length = (u_char) padding; - h->reserved = 0; - - b->last = b->pos + sizeof(ngx_http_fastcgi_header_t) - + sizeof(ngx_http_fastcgi_begin_request_t) - + sizeof(ngx_http_fastcgi_header_t); - - - *b->last++ = sizeof("PATH_TRANSLATED") - 1; - - len = flcf->root.len + r->uri.len + index; - if (len > 127) { - *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); - *b->last++ = (u_char) ((len >> 16) & 0xff); - *b->last++ = (u_char) ((len >> 8) & 0xff); - *b->last++ = (u_char) (len & 0xff); - - } else { - *b->last++ = (u_char) len; - } - - b->last = ngx_cpymem(b->last, "PATH_TRANSLATED", - sizeof("PATH_TRANSLATED") - 1); - b->last = ngx_cpymem(b->last, flcf->root.data, flcf->root.len); - b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len); - - if (index) { - b->last = ngx_cpymem(b->last, flcf->index.data, index); - } - - - *b->last++ = sizeof("REQUEST_METHOD") - 1; - - if (r->upstream->method) { - *b->last++ = (u_char) - ngx_http_fastcgi_methods[r->upstream->method - 1].len; - - b->last = ngx_cpymem(b->last, "REQUEST_METHOD", - sizeof("REQUEST_METHOD") - 1); - - b->last = ngx_cpymem(b->last, - ngx_http_fastcgi_methods[r->upstream->method - 1].data, - ngx_http_fastcgi_methods[r->upstream->method - 1].len); - - } else { - len = r->method_name.len - 1; - if (len > 127) { - *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); - *b->last++ = (u_char) ((len >> 16) & 0xff); - *b->last++ = (u_char) ((len >> 8) & 0xff); - *b->last++ = (u_char) (len & 0xff); - - } else { - *b->last++ = (u_char) len; - } - - b->last = ngx_cpymem(b->last, "REQUEST_METHOD", - sizeof("REQUEST_METHOD") - 1); - b->last = ngx_cpymem(b->last, r->method_name.data, len); - } - - - if (r->args.len) { - *b->last++ = sizeof("QUERY_STRING") - 1; - - len = r->args.len; - if (len > 127) { - *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); - *b->last++ = (u_char) ((len >> 16) & 0xff); - *b->last++ = (u_char) ((len >> 8) & 0xff); - *b->last++ = (u_char) (len & 0xff); - - } else { - *b->last++ = (u_char) len; - } - - b->last = ngx_cpymem(b->last, "QUERY_STRING", - sizeof("QUERY_STRING") - 1); - b->last = ngx_cpymem(b->last, r->args.data, len); - } - - - if (r->headers_in.content_length_n > 0) { - *b->last++ = sizeof("CONTENT_LENGTH") - 1; - - len = r->headers_in.content_length->value.len; - if (len > 127) { - *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); - *b->last++ = (u_char) ((len >> 16) & 0xff); - *b->last++ = (u_char) ((len >> 8) & 0xff); - *b->last++ = (u_char) (len & 0xff); - - } else { - *b->last++ = (u_char) len; - } - - b->last = ngx_cpymem(b->last, "CONTENT_LENGTH", - sizeof("CONTENT_LENGTH") - 1); - b->last = ngx_cpymem(b->last, r->headers_in.content_length->value.data, - len); - } - - - if (r->headers_in.content_type) { - *b->last++ = sizeof("CONTENT_TYPE") - 1; - - len = r->headers_in.content_type->value.len; - if (len > 127) { - *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); - *b->last++ = (u_char) ((len >> 16) & 0xff); - *b->last++ = (u_char) ((len >> 8) & 0xff); - *b->last++ = (u_char) (len & 0xff); - - } else { - *b->last++ = (u_char) len; - } - - b->last = ngx_cpymem(b->last, "CONTENT_TYPE", - sizeof("CONTENT_TYPE") - 1); - b->last = ngx_cpymem(b->last, r->headers_in.content_type->value.data, - len); - } - - - if (flcf->params & NGX_HTTP_FASTCGI_REDIRECT_STATUS) { - *b->last++ = sizeof("REDIRECT_STATUS") - 1; - *b->last++ = sizeof("200") - 1; - b->last = ngx_cpymem(b->last, "REDIRECT_STATUS200", - sizeof("REDIRECT_STATUS200") - 1); - } - - - if (flcf->params & NGX_HTTP_FASTCGI_REQUEST_URI) { - *b->last++ = sizeof("REQUEST_URI") - 1; - - len = r->unparsed_uri.len; - if (len > 127) { - *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); - *b->last++ = (u_char) ((len >> 16) & 0xff); - *b->last++ = (u_char) ((len >> 8) & 0xff); - *b->last++ = (u_char) (len & 0xff); - - } else { - *b->last++ = (u_char) len; - } - - b->last = ngx_cpymem(b->last, "REQUEST_URI", sizeof("REQUEST_URI") - 1); - b->last = ngx_cpymem(b->last, r->unparsed_uri.data, len); - } - - - if (flcf->params & NGX_HTTP_FASTCGI_DOCUMENT_ROOT) { - *b->last++ = sizeof("DOCUMENT_ROOT") - 1; - - len = clcf->root.len; - if (len > 127) { - *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); - *b->last++ = (u_char) ((len >> 16) & 0xff); - *b->last++ = (u_char) ((len >> 8) & 0xff); - *b->last++ = (u_char) (len & 0xff); - - } else { - *b->last++ = (u_char) len; - } - - b->last = ngx_cpymem(b->last, "DOCUMENT_ROOT", - sizeof("DOCUMENT_ROOT") - 1); - b->last = ngx_cpymem(b->last, clcf->root.data, len); - } - - - if (flcf->params & NGX_HTTP_FASTCGI_SCRIPT_FILENAME) { - *b->last++ = sizeof("SCRIPT_FILENAME") - 1; - - len = flcf->root.len + r->uri.len + index; - if (len > 127) { - *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); - *b->last++ = (u_char) ((len >> 16) & 0xff); - *b->last++ = (u_char) ((len >> 8) & 0xff); - *b->last++ = (u_char) (len & 0xff); - - } else { - *b->last++ = (u_char) len; - } - - b->last = ngx_cpymem(b->last, "SCRIPT_FILENAME", - sizeof("SCRIPT_FILENAME") - 1); - b->last = ngx_cpymem(b->last, flcf->root.data, flcf->root.len); - b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len); - - if (index) { - b->last = ngx_cpymem(b->last, flcf->index.data, index); - } - } - - - if (flcf->params & NGX_HTTP_FASTCGI_SCRIPT_NAME) { - *b->last++ = sizeof("SCRIPT_NAME") - 1; - - len = r->uri.len + index; - if (len > 127) { - *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); - *b->last++ = (u_char) ((len >> 16) & 0xff); - *b->last++ = (u_char) ((len >> 8) & 0xff); - *b->last++ = (u_char) (len & 0xff); - - } else { - *b->last++ = (u_char) len; - } - - b->last = ngx_cpymem(b->last, "SCRIPT_NAME", sizeof("SCRIPT_NAME") - 1); - b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len); - - if (index) { - b->last = ngx_cpymem(b->last, flcf->index.data, index); - } - } - - - if (flcf->params & NGX_HTTP_FASTCGI_REMOTE_ADDR) { - *b->last++ = sizeof("REMOTE_ADDR") - 1; - *b->last++ = (u_char) (r->connection->addr_text.len); - b->last = ngx_cpymem(b->last, "REMOTE_ADDR", sizeof("REMOTE_ADDR") - 1); - b->last = ngx_cpymem(b->last, r->connection->addr_text.data, - r->connection->addr_text.len); - } - - - if (port_len) { - *b->last++ = sizeof("REMOTE_PORT") - 1; - *b->last++ = (u_char) port_len; - b->last = ngx_cpymem(b->last, "REMOTE_PORT", sizeof("REMOTE_PORT") - 1); - b->last = ngx_cpymem(b->last, port_text, port_len); - } - - - if (flcf->params & NGX_HTTP_FASTCGI_SERVER_NAME) { - *b->last++ = sizeof("SERVER_NAME") - 1; - *b->last++ = (u_char) r->server_name.len; - b->last = ngx_cpymem(b->last, "SERVER_NAME", sizeof("SERVER_NAME") - 1); - b->last = ngx_cpymem(b->last, r->server_name.data, r->server_name.len); - } - - - if (flcf->params & NGX_HTTP_FASTCGI_SERVER_PORT) { - *b->last++ = sizeof("SERVER_PORT") - 1; - *b->last++ = (u_char) (r->port_text->len - 1); - b->last = ngx_cpymem(b->last, "SERVER_PORT", sizeof("SERVER_PORT") - 1); - b->last = ngx_cpymem(b->last, r->port_text->data + 1, - r->port_text->len - 1); - } - - - if (flcf->params & NGX_HTTP_FASTCGI_SERVER_ADDR) { - *b->last++ = sizeof("SERVER_ADDR") - 1; - *b->last++ = (u_char) addr_len; - b->last = ngx_cpymem(b->last, "SERVER_ADDR", sizeof("SERVER_ADDR") - 1); - b->last = ngx_cpymem(b->last, addr_text, addr_len); - } - - - if (flcf->params & NGX_HTTP_FASTCGI_SERVER_PROTOCOL - && r->http_protocol.len) - { - *b->last++ = sizeof("SERVER_PROTOCOL") - 1; - - len = r->http_protocol.len; - if (len > 127) { - *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); - *b->last++ = (u_char) ((len >> 16) & 0xff); - *b->last++ = (u_char) ((len >> 8) & 0xff); - *b->last++ = (u_char) (len & 0xff); - - } else { - *b->last++ = (u_char) len; - } - - b->last = ngx_cpymem(b->last, "SERVER_PROTOCOL", - sizeof("SERVER_PROTOCOL") - 1); - b->last = ngx_cpymem(b->last, r->http_protocol.data, len); - } - - - if (flcf->params & NGX_HTTP_FASTCGI_SERVER_SOFTWARE) { - *b->last++ = sizeof("SERVER_SOFTWARE") - 1; - *b->last++ = (u_char) (sizeof(NGINX_VER) - 1); - b->last = ngx_cpymem(b->last, "SERVER_SOFTWARE", - sizeof("SERVER_SOFTWARE") - 1); - b->last = ngx_cpymem(b->last, NGINX_VER, sizeof(NGINX_VER) - 1); - } - - - if (flcf->params & NGX_HTTP_FASTCGI_GATEWAY_INTERFACE) { - *b->last++ = sizeof("GATEWAY_INTERFACE") - 1; - *b->last++ = (u_char) (sizeof("CGI/1.1") - 1); - b->last = ngx_cpymem(b->last, "GATEWAY_INTERFACE", - sizeof("GATEWAY_INTERFACE") - 1); - b->last = ngx_cpymem(b->last, "CGI/1.1", sizeof("CGI/1.1") - 1); - } - - - if (flcf->vars) { - for (i = 0; i < flcf->vars->nelts; i++) { - - if (!(value = ngx_http_get_indexed_variable(r, vindex[i]))) { - continue; - } - - if (value->text.len == 0) { - continue; - } - - *b->last++ = (u_char) var[vindex[i]].name.len; - *b->last++ = (u_char) value->text.len; - - b->last = ngx_cpymem(b->last, var[vindex[i]].name.data, - var[vindex[i]].name.len); - - b->last = ngx_cpymem(b->last, value->text.data, value->text.len); - } - } - - - part = &r->headers_in.headers.part; - header = part->elts; - - for (i = 0; /* void */; i++) { - - if (i >= part->nelts) { - if (part->next == NULL) { - break; - } - - part = part->next; - header = part->elts; - i = 0; - } - - len = 5 + header[i].key.len; - if (len > 127) { - *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); - *b->last++ = (u_char) ((len >> 16) & 0xff); - *b->last++ = (u_char) ((len >> 8) & 0xff); - *b->last++ = (u_char) (len & 0xff); - - } else { - *b->last++ = (u_char) len; - } - - len = header[i].value.len; - if (len > 127) { - *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); - *b->last++ = (u_char) ((len >> 16) & 0xff); - *b->last++ = (u_char) ((len >> 8) & 0xff); - *b->last++ = (u_char) (len & 0xff); - - } else { - *b->last++ = (u_char) len; - } - - b->last = ngx_cpymem(b->last, "HTTP_", sizeof("HTTP_") - 1); - - for (n = 0; n < header[i].key.len; n++) { - ch = header[i].key.data[n]; - - if (ch >= 'a' && ch <= 'z') { - ch &= ~0x20; - - } else if (ch == '-') { - ch = '_'; - } - - *b->last++ = ch; - } - - b->last = ngx_cpymem(b->last, header[i].value.data, - header[i].value.len); - } - - - if (padding) { - ngx_memzero(b->last, padding); - b->last += padding; - } - - - h = (ngx_http_fastcgi_header_t *) b->last; - b->last += sizeof(ngx_http_fastcgi_header_t); - - h->version = 1; - h->type = NGX_HTTP_FASTCGI_PARAMS; - h->request_id_hi = 0; - h->request_id_lo = 1; - h->content_length_hi = 0; - h->content_length_lo = 0; - h->padding_length = 0; - h->reserved = 0; - - h = (ngx_http_fastcgi_header_t *) b->last; - b->last += sizeof(ngx_http_fastcgi_header_t); - - body = r->request_body->bufs; - r->request_body->bufs = cl; - -#if (NGX_SUPPRESS_WARN) - file_pos = 0; - pos = NULL; -#endif - - while (body) { - - if (body->buf->in_file) { - file_pos = body->buf->file_pos; - - } else { - pos = body->buf->pos; - } - - next = 0; - - do { - if (!(b = ngx_alloc_buf(r->pool))) { - return NGX_ERROR; - } - - ngx_memcpy(b, body->buf, sizeof(ngx_buf_t)); - - if (body->buf->in_file) { - b->file_pos = file_pos; - file_pos += 32 * 1024; - - if (file_pos > body->buf->file_last) { - file_pos = body->buf->file_last; - next = 1; - } - - b->file_last = file_pos; - len = (ngx_uint_t) (file_pos - b->file_pos); - - } else { - b->pos = pos; - pos += 32 * 1024; - - if (pos > body->buf->last) { - pos = body->buf->last; - next = 1; - } - - b->last = pos; - len = (ngx_uint_t) (pos - b->pos); - } - - padding = 8 - len % 8; - padding = (padding == 8) ? 0 : padding; - - h->version = 1; - h->type = NGX_HTTP_FASTCGI_STDIN; - h->request_id_hi = 0; - h->request_id_lo = 1; - h->content_length_hi = (u_char) ((len >> 8) & 0xff); - h->content_length_lo = (u_char) (len & 0xff); - h->padding_length = (u_char) padding; - h->reserved = 0; - - if (!(cl->next = ngx_alloc_chain_link(r->pool))) { - return NGX_ERROR; - } - - cl = cl->next; - cl->buf = b; - - b = ngx_create_temp_buf(r->pool, sizeof(ngx_http_fastcgi_header_t) - + padding); - if (b == NULL) { - return NGX_ERROR; - } - - if (padding) { - ngx_memzero(b->last, padding); - b->last += padding; - } - - h = (ngx_http_fastcgi_header_t *) b->last; - b->last += sizeof(ngx_http_fastcgi_header_t); - - if (!(cl->next = ngx_alloc_chain_link(r->pool))) { - return NGX_ERROR; - } - - cl = cl->next; - cl->buf = b; - - } while (!next); - - body = body->next; - } - - h->version = 1; - h->type = NGX_HTTP_FASTCGI_STDIN; - h->request_id_hi = 0; - h->request_id_lo = 1; - h->content_length_hi = 0; - h->content_length_lo = 0; - h->padding_length = 0; - h->reserved = 0; - - cl->next = NULL; - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_fastcgi_reinit_request(ngx_http_request_t *r) -{ - ngx_http_fastcgi_ctx_t *f; - - f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module); - - if (f == NULL) { - return NGX_OK; - } - - f->state = ngx_http_fastcgi_st_version; - f->header = 0; - - ngx_memzero(&f->upstream->headers_in, - sizeof(ngx_http_fastcgi_headers_in_t)); - - if (f->upstream->headers_in.headers.part.elts) { - if (ngx_list_init(&f->upstream->headers_in.headers, r->pool, 8, - sizeof(ngx_table_elt_t)) == NGX_ERROR) - { - return NGX_ERROR; - } - } - - return NGX_OK; -} - - -static ngx_int_t ngx_http_fastcgi_process_header(ngx_http_request_t *r) -{ - u_char *start, *last; - ngx_str_t *status_line, line; - ngx_int_t rc, status; - ngx_uint_t i; - ngx_table_elt_t *h; - ngx_http_upstream_t *u; - ngx_http_fastcgi_ctx_t *f; - - f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module); - - if (f == NULL) { - if (!(f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t)))) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - ngx_http_set_ctx(r, f, ngx_http_fastcgi_module); - - f->upstream = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_upstream_t)); - if (f->upstream == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - if (ngx_list_init(&f->upstream->headers_in.headers, r->pool, 8, - sizeof(ngx_table_elt_t)) == NGX_ERROR) - { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - } - - u = r->upstream; - - for ( ;; ) { - - if (f->state < ngx_http_fastcgi_st_data) { - - f->pos = u->header_in.pos; - f->last = u->header_in.last; - - rc = ngx_http_fastcgi_process_record(r, f); - - u->header_in.pos = f->pos; - u->header_in.last = f->last; - - if (rc == NGX_AGAIN) { - return NGX_AGAIN; - } - - if (rc == NGX_ERROR) { - return NGX_HTTP_UPSTREAM_INVALID_HEADER; - } - - if (f->type != NGX_HTTP_FASTCGI_STDOUT - && f->type != NGX_HTTP_FASTCGI_STDERR) - { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "upstream sent unexpected FastCGI record: %d", - f->type); - - return NGX_HTTP_UPSTREAM_INVALID_HEADER; - } - - if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "upstream closed prematurely FastCGI stdout"); - - return NGX_HTTP_UPSTREAM_INVALID_HEADER; - } - } - - if (f->state == ngx_http_fastcgi_st_padding) { - - if (u->header_in.pos + f->padding < u->header_in.last) { - f->state = ngx_http_fastcgi_st_version; - u->header_in.pos += f->padding; - - continue; - } - - if (u->header_in.pos + f->padding == u->header_in.last) { - f->state = ngx_http_fastcgi_st_version; - u->header_in.pos = u->header_in.last; - - return NGX_AGAIN; - } - - f->padding -= u->header_in.last - u->header_in.pos; - u->header_in.pos = u->header_in.last; - - return NGX_AGAIN; - } - - - /* f->state == ngx_http_fastcgi_st_data */ - - if (f->type == NGX_HTTP_FASTCGI_STDERR) { - - if (f->header) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - "upstream split a header in FastCGI records"); - - return NGX_HTTP_UPSTREAM_INVALID_HEADER; - } - - if (f->length) { - line.data = u->header_in.pos; - - if (u->header_in.pos + f->length <= u->header_in.last) { - line.len = f->length; - u->header_in.pos += f->length; - f->length = 0; - f->state = ngx_http_fastcgi_st_padding; - - } else { - line.len = u->header_in.last - u->header_in.pos; - f->length -= u->header_in.last - u->header_in.pos; - u->header_in.pos = u->header_in.last; - } - - while (line.data[line.len - 1] == LF - || line.data[line.len - 1] == CR - || line.data[line.len - 1] == '.' - || line.data[line.len - 1] == ' ') - { - line.len--; - } - - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "FastCGI sent in stderr: \"%V\"", &line); - - if (u->header_in.pos == u->header_in.last) { - return NGX_AGAIN; - } - - } else { - f->state = ngx_http_fastcgi_st_version; - } - - continue; - } - - - /* f->type == NGX_HTTP_FASTCGI_STDOUT */ - - start = u->header_in.pos; - - if (u->header_in.pos + f->length < u->header_in.last) { - - /* - * set u->header_in.last to the end of the FastCGI record data - * for ngx_http_parse_header_line() - */ - - last = u->header_in.last; - u->header_in.last = u->header_in.pos + f->length; - - } else { - last = NULL; - } - - f->header = 1; - - for ( ;; ) { - - rc = ngx_http_parse_header_line(r, &u->header_in); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http fastcgi parser: %d", rc); - - if (rc == NGX_AGAIN) { - break; - } - - if (rc == NGX_OK) { - - /* a header line has been parsed successfully */ - - if (!(h = ngx_list_push(&f->upstream->headers_in.headers))) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - h->key.len = r->header_name_end - r->header_name_start; - h->value.len = r->header_end - r->header_start; - - h->key.data = ngx_palloc(r->pool, - h->key.len + 1 + h->value.len + 1); - if (h->key.data == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - h->value.data = h->key.data + h->key.len + 1; - - ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1); - ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1); - - for (i = 0; ngx_http_fastcgi_headers_in[i].name.len != 0; i++) { - if (ngx_http_fastcgi_headers_in[i].name.len != h->key.len) { - continue; - } - - if (ngx_strcasecmp(ngx_http_fastcgi_headers_in[i].name.data, - h->key.data) == 0) - { - *((ngx_table_elt_t **) - ((char *) &f->upstream->headers_in - + ngx_http_fastcgi_headers_in[i].offset)) = h; - break; - } - } - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http fastcgi header: \"%V: %V\"", - &h->key, &h->value); - - continue; - } - - if (rc == NGX_HTTP_PARSE_HEADER_DONE) { - - /* a whole header has been parsed successfully */ - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http fastcgi header done"); - - if (f->upstream->headers_in.status) { - status_line = &f->upstream->headers_in.status->value; - - status = ngx_atoi(status_line->data, 3); - - if (status == NGX_ERROR) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - r->headers_out.status = status; - r->headers_out.status_line = *status_line; - - } else { - r->headers_out.status = 200; - r->headers_out.status_line.len = sizeof("200 OK") - 1; - r->headers_out.status_line.data = (u_char *) "200 OK"; - } - - u->state->status = r->headers_out.status; -#if 0 - if (u->cachable) { - u->cachable = ngx_http_upstream_is_cachable(r); - } -#endif - - break; - } - - /* there was error while a header line parsing */ - - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - ngx_http_upstream_header_errors[rc - - NGX_HTTP_PARSE_HEADER_ERROR]); - - return NGX_HTTP_UPSTREAM_INVALID_HEADER; - - } - - if (last) { - u->header_in.last = last; - } - - f->length -= u->header_in.pos - start; - - if (rc == NGX_AGAIN) { - if (u->header_in.pos == u->header_in.last) { - return NGX_AGAIN; - } - - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - "upstream split a header in FastCGI records"); - - return NGX_HTTP_UPSTREAM_INVALID_HEADER; - } - - if (f->length == 0) { - if (f->padding) { - f->state = ngx_http_fastcgi_st_padding; - } else { - f->state = ngx_http_fastcgi_st_version; - } - } - - return NGX_OK; - } -} - - -static ngx_int_t -ngx_http_fastcgi_send_header(ngx_http_request_t *r) -{ - ngx_uint_t i; - ngx_list_part_t *part; - ngx_table_elt_t *ho, *h; - ngx_http_fastcgi_ctx_t *f; - ngx_http_fastcgi_headers_in_t *headers_in; - - f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module); - - headers_in = &f->upstream->headers_in; - part = &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; - } - - /* ignore some headers */ - - if (&h[i] == headers_in->status) { - continue; - } - - - if (&h[i] == headers_in->x_powered_by - && !r->upstream->conf->x_powered_by) - { - continue; - } - - - /* "Content-Type" is handled specially */ - - if (&h[i] == headers_in->content_type) { - r->headers_out.content_type = &h[i]; - r->headers_out.content_type->key.len = 0; - continue; - } - - - /* copy some header pointers and set up r->headers_out */ - - if (!(ho = ngx_list_push(&r->headers_out.headers))) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - *ho = h[i]; - -#if (NGX_HTTP_GZIP) - if (&h[i] == headers_in->content_encoding) { - r->headers_out.content_encoding = ho; - continue; - } -#endif - - if (&h[i] == headers_in->content_length) { - r->headers_out.content_length = ho; - r->headers_out.content_length_n = ngx_atoi(ho->value.data, - ho->value.len); - continue; - } - } - - return ngx_http_send_header(r); -} - - -static ngx_int_t -ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) -{ - ngx_int_t rc; - ngx_buf_t *b, **prev; - ngx_str_t line; - ngx_chain_t *cl; - ngx_http_request_t *r; - ngx_http_fastcgi_ctx_t *f; - - if (buf->pos == buf->last) { - return NGX_OK; - } - - r = p->input_ctx; - f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module); - - b = NULL; - prev = &buf->shadow; - - f->pos = buf->pos; - f->last = buf->last; - - for ( ;; ) { - if (f->state < ngx_http_fastcgi_st_data) { - - rc = ngx_http_fastcgi_process_record(r, f); - - if (rc == NGX_AGAIN) { - break; - } - - if (rc == NGX_ERROR) { - return NGX_ERROR; - } - - if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) { - f->state = ngx_http_fastcgi_st_version; - p->upstream_done = 1; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0, - "http fastcgi closed stdout"); - - continue; - } - - if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) { - f->state = ngx_http_fastcgi_st_version; - p->upstream_done = 1; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0, - "http fastcgi sent end request"); - - break; - } - } - - - if (f->state == ngx_http_fastcgi_st_padding) { - - if (f->pos + f->padding < f->last) { - f->state = ngx_http_fastcgi_st_version; - f->pos += f->padding; - - continue; - } - - if (f->pos + f->padding == f->last) { - f->state = ngx_http_fastcgi_st_version; - - break; - } - - f->padding -= f->last - f->pos; - - break; - } - - - /* f->state == ngx_http_fastcgi_st_data */ - - if (f->type == NGX_HTTP_FASTCGI_STDERR) { - - if (f->length) { - line.data = f->pos; - - if (f->pos + f->length <= f->last) { - line.len = f->length; - f->pos += f->length; - f->length = 0; - f->state = ngx_http_fastcgi_st_padding; - - } else { - line.len = f->last - f->pos; - f->length -= f->last - f->pos; - f->pos = f->last; - } - - while (line.data[line.len - 1] == LF - || line.data[line.len - 1] == CR - || line.data[line.len - 1] == '.' - || line.data[line.len - 1] == ' ') - { - line.len--; - } - - ngx_log_error(NGX_LOG_ERR, p->log, 0, - "FastCGI sent in stderr: \"%V\"", &line); - - if (f->pos == f->last) { - break; - } - - } else { - f->state = ngx_http_fastcgi_st_version; - } - - continue; - } - - - /* f->type == NGX_HTTP_FASTCGI_STDOUT */ - - if (p->free) { - b = p->free->buf; - p->free = p->free->next; - - } else { - if (!(b = ngx_alloc_buf(p->pool))) { - return NGX_ERROR; - } - } - - ngx_memzero(b, sizeof(ngx_buf_t)); - - b->pos = f->pos; - b->start = buf->start; - b->end = buf->end; - b->tag = p->tag; - b->temporary = 1; - b->recycled = 1; - - *prev = b; - prev = &b->shadow; - - if (!(cl = ngx_alloc_chain_link(p->pool))) { - return NGX_ERROR; - } - - cl->buf = b; - cl->next = NULL; - - /* STUB */ b->num = buf->num; - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d", b->num); - - ngx_chain_add_link(p->in, p->last_in, cl); - - if (f->pos + f->length < f->last) { - - if (f->padding) { - f->state = ngx_http_fastcgi_st_padding; - } else { - f->state = ngx_http_fastcgi_st_version; - } - - f->pos += f->length; - b->last = f->pos; - - continue; - } - - if (f->pos + f->length == f->last) { - - if (f->padding) { - f->state = ngx_http_fastcgi_st_padding; - } else { - f->state = ngx_http_fastcgi_st_version; - } - - b->last = f->last; - - break; - } - - f->length -= f->last - f->pos; - - b->last = f->last; - - break; - - } - - if (b) { - b->shadow = buf; - b->last_shadow = 1; - - return NGX_OK; - } - - /* there is no data record in the buf, add it to free chain */ - - if (ngx_event_pipe_add_free_buf(p, buf) != NGX_OK) { - return NGX_ERROR; - } - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_fastcgi_process_record(ngx_http_request_t *r, - ngx_http_fastcgi_ctx_t *f) -{ - u_char ch, *p; - ngx_http_upstream_t *u; - ngx_http_fastcgi_state_e state; - - u = r->upstream; - - state = f->state; - - for (p = f->pos; p < f->last; p++) { - - ch = *p; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http fastcgi record byte: %02Xd", ch); - - switch (state) { - - case ngx_http_fastcgi_st_version: - if (ch != 1) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "upstream sent unsupported FastCGI " - "protocol version: %d", ch); - return NGX_ERROR; - } - state = ngx_http_fastcgi_st_type; - break; - - case ngx_http_fastcgi_st_type: - switch (ch) { - case NGX_HTTP_FASTCGI_STDOUT: - case NGX_HTTP_FASTCGI_STDERR: - case NGX_HTTP_FASTCGI_END_REQUEST: - f->type = (ngx_uint_t) ch; - break; - default: - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "upstream sent invalid FastCGI " - "record type: %d", ch); - return NGX_ERROR; - - } - state = ngx_http_fastcgi_st_request_id_hi; - break; - - /* we support the single request per connection */ - - case ngx_http_fastcgi_st_request_id_hi: - if (ch != 0) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "upstream sent unexpected FastCGI " - "request id high byte: %d", ch); - return NGX_ERROR; - } - state = ngx_http_fastcgi_st_request_id_lo; - break; - - case ngx_http_fastcgi_st_request_id_lo: - if (ch != 1) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "upstream sent unexpected FastCGI " - "request id low byte: %d", ch); - return NGX_ERROR; - } - state = ngx_http_fastcgi_st_content_length_hi; - break; - - case ngx_http_fastcgi_st_content_length_hi: - f->length = ch << 8; - state = ngx_http_fastcgi_st_content_length_lo; - break; - - case ngx_http_fastcgi_st_content_length_lo: - f->length |= (size_t) ch; - state = ngx_http_fastcgi_st_padding_length; - break; - - case ngx_http_fastcgi_st_padding_length: - f->padding = (size_t) ch; - state = ngx_http_fastcgi_st_reserved; - break; - - case ngx_http_fastcgi_st_reserved: - state = ngx_http_fastcgi_st_data; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http fastcgi record length: %z", f->length); - - f->pos = p + 1; - f->state = state; - - return NGX_OK; - - /* suppress warning */ - case ngx_http_fastcgi_st_data: - case ngx_http_fastcgi_st_padding: - break; - } - } - - f->pos = p + 1; - f->state = state; - - return NGX_AGAIN; -} - - -static void -ngx_http_fastcgi_abort_request(ngx_http_request_t *r) -{ - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "abort http fastcgi request"); - - return; -} - - -static void -ngx_http_fastcgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc) -{ - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "finalize http fastcgi request"); - - return; -} - - -static char * -ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_http_fastcgi_loc_conf_t *lcf = conf; - - ngx_str_t *value; - ngx_inet_upstream_t inet_upstream; - ngx_http_core_loc_conf_t *clcf; -#if (NGX_HAVE_UNIX_DOMAIN) - ngx_unix_domain_upstream_t unix_upstream; -#endif - - value = cf->args->elts; - - if (ngx_strncasecmp(value[1].data, "unix:", 5) == 0) { - -#if (NGX_HAVE_UNIX_DOMAIN) - - ngx_memzero(&unix_upstream, sizeof(ngx_unix_domain_upstream_t)); - - unix_upstream.name = value[1]; - unix_upstream.url = value[1]; - - if (!(lcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream))) { - return NGX_CONF_ERROR; - } - -#else - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "the unix domain sockets are not supported " - "on this platform"); - return NGX_CONF_ERROR; - -#endif - - } else { - ngx_memzero(&inet_upstream, sizeof(ngx_inet_upstream_t)); - - inet_upstream.name = value[1]; - inet_upstream.url = value[1]; - - if (!(lcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream))) { - return NGX_CONF_ERROR; - } - } - - clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); - - clcf->handler = ngx_http_fastcgi_handler; - -#if (NGX_PCRE) - lcf->location = clcf->regex ? &ngx_http_fastcgi_uri: &clcf->name; -#else - lcf->location = &clcf->name; -#endif - - if (clcf->name.data[clcf->name.len - 1] == '/') { - clcf->auto_redirect = 1; - } - - return NGX_CONF_OK; -} - - -static char * -ngx_http_fastcgi_set_var(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_http_fastcgi_loc_conf_t *lcf = conf; - - ngx_uint_t i, *index; - ngx_str_t *value; - ngx_http_variable_t *var; - ngx_http_core_main_conf_t *cmcf; - - if (lcf->vars == NULL) { - lcf->vars = ngx_array_create(cf->pool, 4, - sizeof(ngx_http_variable_t *)); - if (lcf->vars == NULL) { - return NGX_CONF_ERROR; - } - } - - cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); - - value = cf->args->elts; - - var = cmcf->variables.elts; - for (i = 0; i < cmcf->variables.nelts; i++) { - if (ngx_strcasecmp(var[i].name.data, value[1].data) == 0) { - - if (!(index = ngx_array_push(lcf->vars))) { - return NGX_CONF_ERROR; - } - - *index = var[i].index; - return NGX_CONF_OK; - } - } - - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "unknown variable name \"%V\"", &value[1]); - return NGX_CONF_ERROR; -} - - -static char * -ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post, void *data) -{ -#if (NGX_FREEBSD) - ssize_t *np = data; - - if (*np >= ngx_freebsd_net_inet_tcp_sendspace) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"fastcgi_send_lowat\" must be less than %d " - "(sysctl net.inet.tcp.sendspace)", - ngx_freebsd_net_inet_tcp_sendspace); - - return NGX_CONF_ERROR; - } - -#elif !(NGX_HAVE_SO_SNDLOWAT) - ssize_t *np = data; - - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "\"fastcgi_send_lowat\" is not supported, ignored"); - - *np = 0; - -#endif - - return NGX_CONF_OK; -} - - -static void * -ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf) -{ - ngx_http_fastcgi_loc_conf_t *conf; - - if (!(conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastcgi_loc_conf_t)))) { - return NGX_CONF_ERROR; - } - - /* - * set by ngx_pcalloc(): - * - * conf->upstream.bufs.num = 0; - * conf->upstream.path = NULL; - * conf->upstream.next_upstream = 0; - * conf->upstream.temp_path = NULL; - * conf->params = 0; - * conf->root.len = 0; - * conf->root.data = NULL; - * conf->index.len = 0; - * conf->index.data = NULL; - * conf->location = NULL; - */ - - conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; - conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; - conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE; - - conf->upstream.header_buffer_size = NGX_CONF_UNSET_SIZE; - conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC; - conf->upstream.busy_buffers_size = NGX_CONF_UNSET_SIZE; - - conf->upstream.max_temp_file_size = NGX_CONF_UNSET_SIZE; - conf->upstream.temp_file_write_size = NGX_CONF_UNSET_SIZE; - - conf->upstream.redirect_errors = NGX_CONF_UNSET; - conf->upstream.x_powered_by = NGX_CONF_UNSET; - - /* "fastcgi_cyclic_temp_file" is disabled */ - conf->upstream.cyclic_temp_file = 0; - - return conf; -} - - -static char * -ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) -{ - ngx_http_fastcgi_loc_conf_t *prev = parent; - ngx_http_fastcgi_loc_conf_t *conf = child; - - size_t size; - - ngx_conf_merge_msec_value(conf->upstream.connect_timeout, - prev->upstream.connect_timeout, 60000); - ngx_conf_merge_msec_value(conf->upstream.send_timeout, - prev->upstream.send_timeout, 60000); - ngx_conf_merge_size_value(conf->upstream.send_lowat, - prev->upstream.send_lowat, 0); - - ngx_conf_merge_msec_value(conf->upstream.read_timeout, - prev->upstream.read_timeout, 60000); - - ngx_conf_merge_msec_value(conf->upstream.redirect_errors, - prev->upstream.redirect_errors, 0); - - ngx_conf_merge_msec_value(conf->upstream.x_powered_by, - prev->upstream.x_powered_by, 1); - - - ngx_conf_merge_size_value(conf->upstream.header_buffer_size, - prev->upstream.header_buffer_size, - (size_t) ngx_pagesize); - - ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs, - 8, ngx_pagesize); - - if (conf->upstream.bufs.num < 2) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "there must be at least 2 \"fastcgi_buffers\""); - return NGX_CONF_ERROR; - } - - - size = conf->upstream.header_buffer_size; - if (size < conf->upstream.bufs.size) { - size = conf->upstream.bufs.size; - } - - - ngx_conf_merge_size_value(conf->upstream.busy_buffers_size, - prev->upstream.busy_buffers_size, - NGX_CONF_UNSET_SIZE); - - if (conf->upstream.busy_buffers_size == NGX_CONF_UNSET_SIZE) { - conf->upstream.busy_buffers_size = 2 * size; - - } else if (conf->upstream.busy_buffers_size < size) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"fastcgi_busy_buffers_size\" must be equal or bigger than " - "maximum of the value of \"fastcgi_header_buffer_size\" and " - "one of the \"fastcgi_buffers\""); - - return NGX_CONF_ERROR; - - } else if (conf->upstream.busy_buffers_size - > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size) - { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"fastcgi_busy_buffers_size\" must be less than " - "the size of all \"fastcgi_buffers\" minus one buffer"); - - return NGX_CONF_ERROR; - } - - - ngx_conf_merge_size_value(conf->upstream.temp_file_write_size, - prev->upstream.temp_file_write_size, - NGX_CONF_UNSET_SIZE); - - if (conf->upstream.temp_file_write_size == NGX_CONF_UNSET_SIZE) { - conf->upstream.temp_file_write_size = 2 * size; - - } else if (conf->upstream.temp_file_write_size < size) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"fastcgi_temp_file_write_size\" must be equal or bigger than " - "maximum of the value of \"fastcgi_header_buffer_size\" and " - "one of the \"fastcgi_buffers\""); - - return NGX_CONF_ERROR; - } - - - ngx_conf_merge_size_value(conf->upstream.max_temp_file_size, - prev->upstream.max_temp_file_size, - NGX_CONF_UNSET_SIZE); - - if (conf->upstream.max_temp_file_size == NGX_CONF_UNSET_SIZE) { - - conf->upstream.max_temp_file_size = 1024 * 1024 * 1024; - - } else if (conf->upstream.max_temp_file_size != 0 - && conf->upstream.max_temp_file_size < size) - { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"fastcgi_max_temp_file_size\" must be equal to zero to disable " - "the temporary files usage or must be equal or bigger than " - "maximum of the value of \"fastcgi_header_buffer_size\" and " - "one of the \"fastcgi_buffers\""); - - return NGX_CONF_ERROR; - } - - - ngx_conf_merge_bitmask_value(conf->upstream.next_upstream, - prev->upstream.next_upstream, - (NGX_CONF_BITMASK_SET - |NGX_HTTP_UPSTREAM_FT_ERROR - |NGX_HTTP_UPSTREAM_FT_TIMEOUT)); - - ngx_conf_merge_path_value(conf->upstream.temp_path, - prev->upstream.temp_path, - NGX_HTTP_FASTCGI_TEMP_PATH, 1, 2, 0, - ngx_garbage_collector_temp_handler, cf); - - - ngx_conf_merge_bitmask_value(conf->params, prev->params, - (NGX_CONF_BITMASK_SET - |NGX_HTTP_FASTCGI_REMOTE_ADDR - |NGX_HTTP_FASTCGI_REMOTE_USER - |NGX_HTTP_FASTCGI_SERVER_NAME - |NGX_HTTP_FASTCGI_SERVER_PORT - |NGX_HTTP_FASTCGI_SCRIPT_NAME - |NGX_HTTP_FASTCGI_AUTH_TYPE - |NGX_HTTP_FASTCGI_REQUEST_URI - |NGX_HTTP_FASTCGI_REDIRECT_STATUS)); - - ngx_conf_merge_str_value(conf->root, prev->root, ""); - - if (conf->root.len && conf->root.data[conf->root.len - 1] == '/') { - conf->root.len--; - } - - ngx_conf_merge_str_value(conf->index, prev->index, ""); - - if (conf->vars == NULL) { - conf->vars = prev->vars; - } - - return NGX_CONF_OK; -} diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -0,0 +1,2292 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include +#include + + +typedef struct { + ngx_http_upstream_conf_t upstream; + + ngx_peers_t *peers; + + ngx_uint_t params; + + ngx_str_t root; + ngx_str_t index; + + ngx_array_t *vars; + + ngx_str_t *location; +} ngx_http_fastcgi_loc_conf_t; + + +typedef struct { + ngx_list_t headers; + + ngx_table_elt_t *status; + + ngx_table_elt_t *content_type; + ngx_table_elt_t *content_length; + ngx_table_elt_t *x_powered_by; + +#if (NGX_HTTP_GZIP) + ngx_table_elt_t *content_encoding; +#endif +} ngx_http_fastcgi_headers_in_t; + + +typedef struct { + ngx_http_fastcgi_headers_in_t headers_in; +} ngx_http_fastcgi_upstream_t; + + +typedef enum { + ngx_http_fastcgi_st_version = 0, + ngx_http_fastcgi_st_type, + ngx_http_fastcgi_st_request_id_hi, + ngx_http_fastcgi_st_request_id_lo, + ngx_http_fastcgi_st_content_length_hi, + ngx_http_fastcgi_st_content_length_lo, + ngx_http_fastcgi_st_padding_length, + ngx_http_fastcgi_st_reserved, + ngx_http_fastcgi_st_data, + ngx_http_fastcgi_st_padding, +} ngx_http_fastcgi_state_e; + + +typedef struct { + ngx_http_fastcgi_state_e state; + u_char *pos; + u_char *last; + ngx_uint_t type; + size_t length; + size_t padding; + + ngx_uint_t header; + + ngx_http_fastcgi_upstream_t *upstream; +} ngx_http_fastcgi_ctx_t; + + +#define NGX_HTTP_FASTCGI_REMOTE_ADDR 0x00000002 +#define NGX_HTTP_FASTCGI_REMOTE_USER 0x00000004 +#define NGX_HTTP_FASTCGI_SERVER_NAME 0x00000008 +#define NGX_HTTP_FASTCGI_SERVER_ADDR 0x00000010 +#define NGX_HTTP_FASTCGI_SERVER_PORT 0x00000020 +#define NGX_HTTP_FASTCGI_SCRIPT_NAME 0x00000040 +#define NGX_HTTP_FASTCGI_AUTH_TYPE 0x00000080 +#define NGX_HTTP_FASTCGI_SERVER_PROTOCOL 0x00000100 +#define NGX_HTTP_FASTCGI_SERVER_SOFTWARE 0x00000200 +#define NGX_HTTP_FASTCGI_GATEWAY_INTERFACE 0x00000400 +#define NGX_HTTP_FASTCGI_REQUEST_URI 0x00000800 +#define NGX_HTTP_FASTCGI_REDIRECT_STATUS 0x00001000 +#define NGX_HTTP_FASTCGI_DOCUMENT_ROOT 0x00002000 +#define NGX_HTTP_FASTCGI_SCRIPT_FILENAME 0x00004000 +#define NGX_HTTP_FASTCGI_REMOTE_PORT 0x00008000 + + +#define NGX_HTTP_FASTCGI_RESPONDER 1 + +#define NGX_HTTP_FASTCGI_BEGIN_REQUEST 1 +#define NGX_HTTP_FASTCGI_ABORT_REQUEST 2 +#define NGX_HTTP_FASTCGI_END_REQUEST 3 +#define NGX_HTTP_FASTCGI_PARAMS 4 +#define NGX_HTTP_FASTCGI_STDIN 5 +#define NGX_HTTP_FASTCGI_STDOUT 6 +#define NGX_HTTP_FASTCGI_STDERR 7 +#define NGX_HTTP_FASTCGI_DATA 8 + + +typedef struct { + u_char version; + u_char type; + u_char request_id_hi; + u_char request_id_lo; + u_char content_length_hi; + u_char content_length_lo; + u_char padding_length; + u_char reserved; +} ngx_http_fastcgi_header_t; + + +typedef struct { + u_char role_hi; + u_char role_lo; + u_char flags; + u_char reserved[5]; +} ngx_http_fastcgi_begin_request_t; + + +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); +static ngx_int_t ngx_http_fastcgi_send_header(ngx_http_request_t *r); +static ngx_int_t ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, + ngx_buf_t *buf); +static ngx_int_t ngx_http_fastcgi_process_record(ngx_http_request_t *r, + ngx_http_fastcgi_ctx_t *f); +static void ngx_http_fastcgi_abort_request(ngx_http_request_t *r); +static void ngx_http_fastcgi_finalize_request(ngx_http_request_t *r, + ngx_int_t rc); + +static char *ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_http_fastcgi_set_var(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post, + void *data); +static void *ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, + void *parent, void *child); + + +static ngx_str_t ngx_http_fastcgi_methods[] = { + ngx_string("GET"), + ngx_string("HEAD"), + ngx_string("POST") +}; + + +static ngx_str_t ngx_http_fastcgi_uri = ngx_string("/"); + + +static ngx_http_header_t ngx_http_fastcgi_headers_in[] = { + { ngx_string("Status"), offsetof(ngx_http_fastcgi_headers_in_t, status) }, + + { ngx_string("Content-Type"), + offsetof(ngx_http_fastcgi_headers_in_t, content_type) }, + + { ngx_string("Content-Length"), + offsetof(ngx_http_fastcgi_headers_in_t, content_length) }, + + { ngx_string("X-Powered-By"), + offsetof(ngx_http_fastcgi_headers_in_t, x_powered_by) }, + +#if (NGX_HTTP_GZIP) + { ngx_string("Content-Encoding"), + offsetof(ngx_http_fastcgi_headers_in_t, content_encoding) }, +#endif + + { ngx_null_string, 0 } +}; + + +static ngx_conf_post_t ngx_http_fastcgi_lowat_post = + { ngx_http_fastcgi_lowat_check }; + +static ngx_conf_bitmask_t ngx_http_fastcgi_next_upstream_masks[] = { + { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR }, + { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT }, + { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER }, + { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 }, + { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 }, + { ngx_null_string, 0 } +}; + + +static ngx_conf_bitmask_t ngx_http_fastcgi_params_masks[] = { + { ngx_string("remote_addr"), NGX_HTTP_FASTCGI_REMOTE_ADDR }, + { ngx_string("server_port"), NGX_HTTP_FASTCGI_SERVER_PORT }, + { ngx_string("server_addr"), NGX_HTTP_FASTCGI_SERVER_ADDR }, + { ngx_string("server_name"), NGX_HTTP_FASTCGI_SERVER_NAME }, + { ngx_string("script_name"), NGX_HTTP_FASTCGI_SCRIPT_NAME }, + + { ngx_string("server_protocol"), NGX_HTTP_FASTCGI_SERVER_PROTOCOL }, + { ngx_string("server_software"), NGX_HTTP_FASTCGI_SERVER_SOFTWARE }, + { ngx_string("gateway_interface"), NGX_HTTP_FASTCGI_GATEWAY_INTERFACE }, + + { ngx_string("redirect_status"), NGX_HTTP_FASTCGI_REDIRECT_STATUS }, + { ngx_string("request_uri"), NGX_HTTP_FASTCGI_REQUEST_URI }, + + { ngx_string("document_root"), NGX_HTTP_FASTCGI_DOCUMENT_ROOT }, + { ngx_string("script_filename"), NGX_HTTP_FASTCGI_SCRIPT_FILENAME }, + { ngx_string("remote_port"), NGX_HTTP_FASTCGI_REMOTE_PORT }, + + { ngx_null_string, 0 } +}; + + +static ngx_command_t ngx_http_fastcgi_commands[] = { + + { ngx_string("fastcgi_pass"), + NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_fastcgi_pass, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("fastcgi_root"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, root), + NULL }, + + { ngx_string("fastcgi_index"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, index), + NULL }, + + { ngx_string("fastcgi_connect_timeout"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.connect_timeout), + NULL }, + + { ngx_string("fastcgi_send_timeout"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.send_timeout), + NULL }, + + { ngx_string("fastcgi_send_lowat"), + 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_fastcgi_loc_conf_t, upstream.send_lowat), + &ngx_http_fastcgi_lowat_post }, + + { ngx_string("fastcgi_header_buffer_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.header_buffer_size), + NULL }, + + { ngx_string("fastcgi_redirect_errors"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.redirect_errors), + NULL }, + + { ngx_string("fastcgi_x_powered_by"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.x_powered_by), + NULL }, + + { ngx_string("fastcgi_read_timeout"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.read_timeout), + NULL }, + + { ngx_string("fastcgi_buffers"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, + ngx_conf_set_bufs_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.bufs), + NULL }, + + { ngx_string("fastcgi_busy_buffers_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.busy_buffers_size), + NULL }, + + { 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 }, + + { ngx_string("fastcgi_max_temp_file_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.max_temp_file_size), + NULL }, + + { ngx_string("fastcgi_temp_file_write_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.temp_file_write_size), + NULL }, + + { ngx_string("fastcgi_next_upstream"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY, + ngx_conf_set_bitmask_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.next_upstream), + &ngx_http_fastcgi_next_upstream_masks }, + + { ngx_string("fastcgi_set_var"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_fastcgi_set_var, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("fastcgi_params"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY, + ngx_conf_set_bitmask_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, params), + &ngx_http_fastcgi_params_masks }, + + ngx_null_command +}; + + +ngx_http_module_t ngx_http_fastcgi_module_ctx = { + NULL, /* pre conf */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_fastcgi_create_loc_conf, /* create location configuration */ + ngx_http_fastcgi_merge_loc_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_fastcgi_module = { + NGX_MODULE, + &ngx_http_fastcgi_module_ctx, /* module context */ + ngx_http_fastcgi_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init module */ + NULL /* init process */ +}; + + +static ngx_int_t +ngx_http_fastcgi_handler(ngx_http_request_t *r) +{ + ngx_int_t rc; + ngx_http_upstream_t *u; + ngx_http_fastcgi_loc_conf_t *flcf; + + flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); + + u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t)); + if (u == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + u->peer.log = r->connection->log; + u->peer.log_error = NGX_ERROR_ERR; + u->peer.peers = flcf->peers; + u->peer.tries = flcf->peers->number; +#if (NGX_THREADS) + u->peer.lock = &r->connection->lock; +#endif + + u->output.tag = (ngx_buf_tag_t) &ngx_http_fastcgi_module; + + u->conf = &flcf->upstream; + + u->location = flcf->location; + + u->create_request = ngx_http_fastcgi_create_request; + u->reinit_request = ngx_http_fastcgi_reinit_request; + u->process_header = ngx_http_fastcgi_process_header; + u->send_header = ngx_http_fastcgi_send_header; + u->abort_request = ngx_http_fastcgi_abort_request; + u->finalize_request = ngx_http_fastcgi_finalize_request; + + u->pipe.input_filter = ngx_http_fastcgi_input_filter; + u->pipe.input_ctx = r; + + u->log_ctx = r->connection->log->data; + u->log_handler = ngx_http_upstream_log_error; + + u->schema.len = sizeof("fastcgi://") - 1; + u->schema.data = (u_char *) "fastcgi://"; + u->uri.len = sizeof("/") - 1; + u->uri.data = (u_char *) "/"; + + r->upstream = u; + + rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init); + + if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { + return rc; + } + + return NGX_DONE; +} + + +static ngx_int_t +ngx_http_fastcgi_create_request(ngx_http_request_t *r) +{ + u_char ch, *pos, addr_text[INET_ADDRSTRLEN], + port_text[sizeof("65535") - 1]; + size_t size, len, index, padding, + addr_len, port_len; + off_t file_pos; + ngx_buf_t *b; + socklen_t slen; + ngx_chain_t *cl, *body; + ngx_uint_t i, n, next, *vindex, port; + ngx_list_part_t *part; + ngx_table_elt_t *header; + struct sockaddr_in sin, *sinp; + ngx_http_variable_t *var; + ngx_http_variable_value_t *value; + ngx_http_core_loc_conf_t *clcf; + ngx_http_core_main_conf_t *cmcf; + ngx_http_fastcgi_header_t *h; + ngx_http_fastcgi_loc_conf_t *flcf; + ngx_http_fastcgi_begin_request_t *br; + + + flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); + + if ((flcf->params & NGX_HTTP_FASTCGI_SERVER_ADDR) && r->in_addr == 0) { + + slen = sizeof(struct sockaddr_in); + if (getsockname(r->connection->fd, + (struct sockaddr *) &sin, &slen) == -1) + { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, + ngx_socket_errno, "getsockname() failed"); + return NGX_ERROR; + } + + r->in_addr = sin.sin_addr.s_addr; + } + + addr_len = ngx_inet_ntop(r->connection->listening->family, &r->in_addr, + addr_text, INET_ADDRSTRLEN); + if (addr_len == 0) { + return NGX_ERROR; + } + +#if (NGX_SUPPRESS_WARN) + clcf = NULL; + var = NULL; + vindex = NULL; +#endif + + + if (r->upstream->method) { + len = 1 + 1 + sizeof("REQUEST_METHOD") - 1 + + ngx_http_fastcgi_methods[r->upstream->method - 1].len; + + } else { + len = 1 + ((r->method_name.len - 1 > 127) ? 4 : 1) + + sizeof("REQUEST_METHOD") - 1 + + r->method_name.len - 1; + } + + + index = (r->uri.data[r->uri.len - 1] == '/') ? flcf->index.len : 0; + + len += 1 + ((flcf->root.len + r->uri.len + index > 127) ? 4 : 1) + + sizeof("PATH_TRANSLATED") - 1 + flcf->root.len + r->uri.len + index; + + if (r->args.len) { + len += 1 + ((r->args.len > 127) ? 4 : 1) + sizeof("QUERY_STRING") - 1 + + r->args.len; + } + + if (r->headers_in.content_length_n > 0) { + len += 1 + ((r->headers_in.content_length->value.len > 127) ? 4 : 1) + + sizeof("CONTENT_LENGTH") - 1 + + r->headers_in.content_length->value.len; + } + + + if (r->headers_in.content_type) { + len += 1 + ((r->headers_in.content_type->value.len > 127) ? 4 : 1) + + sizeof("CONTENT_TYPE") - 1 + + r->headers_in.content_type->value.len; + } + + + if (flcf->params & NGX_HTTP_FASTCGI_REDIRECT_STATUS) { + len += 1 + 1 + sizeof("REDIRECT_STATUS200") - 1; + } + + if (flcf->params & NGX_HTTP_FASTCGI_REQUEST_URI) { + len += 1 + ((r->unparsed_uri.len > 127) ? 4 : 1) + + sizeof("REQUEST_URI") - 1 + r->unparsed_uri.len; + } + + if (flcf->params & NGX_HTTP_FASTCGI_DOCUMENT_ROOT) { + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + len += 1 + ((clcf->root.len > 127) ? 4 : 1) + + sizeof("DOCUMENT_ROOT") - 1 + clcf->root.len; + } + + if (flcf->params & NGX_HTTP_FASTCGI_SCRIPT_FILENAME) { + len += 1 + ((flcf->root.len + r->uri.len + index > 127) ? 4 : 1) + + sizeof("SCRIPT_FILENAME") - 1 + + flcf->root.len + r->uri.len + index; + } + + if (flcf->params & NGX_HTTP_FASTCGI_SCRIPT_NAME) { + len += 1 + ((r->uri.len + index > 127) ? 4 : 1) + + sizeof("SCRIPT_NAME") - 1 + r->uri.len + index ; + } + + if (flcf->params & NGX_HTTP_FASTCGI_REMOTE_ADDR) { + len += 1 + 1 + sizeof("REMOTE_ADDR") - 1 + r->connection->addr_text.len; + } + + port_len = 0; + + if (flcf->params & NGX_HTTP_FASTCGI_REMOTE_PORT) { + + /* AF_INET only */ + + if (r->connection->sockaddr->sa_family == AF_INET) { + sinp = (struct sockaddr_in *) r->connection->sockaddr; + + port = ntohs(sinp->sin_port); + + if (port > 0 && port < 65536) { + port_len = ngx_sprintf(port_text, "%ui", port) - port_text; + } + + len += 1 + 1 + sizeof("REMOTE_PORT") - 1 + port_len; + } + } + + if (flcf->params & NGX_HTTP_FASTCGI_SERVER_NAME) { + len += 1 + 1 + sizeof("SERVER_NAME") - 1 + r->server_name.len; + } + + if (flcf->params & NGX_HTTP_FASTCGI_SERVER_PORT) { + len += 1 + 1 + sizeof("SERVER_PORT") - 1 + r->port_text->len - 1; + } + + if (flcf->params & NGX_HTTP_FASTCGI_SERVER_ADDR) { + len += 1 + 1 + sizeof("SERVER_ADDR") - 1 + addr_len; + } + + if (flcf->params & NGX_HTTP_FASTCGI_SERVER_PROTOCOL + && r->http_protocol.len) + { + len += 1 + ((r->http_protocol.len > 127) ? 4 : 1) + + sizeof("SERVER_PROTOCOL") - 1 + r->http_protocol.len; + } + + if (flcf->params & NGX_HTTP_FASTCGI_SERVER_SOFTWARE) { + len += 1 + 1 + sizeof("SERVER_SOFTWARE") - 1 + sizeof(NGINX_VER) - 1; + } + + if (flcf->params & NGX_HTTP_FASTCGI_GATEWAY_INTERFACE) { + len += 1 + 1 + sizeof("GATEWAY_INTERFACE") - 1 + sizeof("CGI/1.1") - 1; + } + + + if (flcf->vars) { + cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); + + var = cmcf->variables.elts; + vindex = flcf->vars->elts; + + for (i = 0; i < flcf->vars->nelts; i++) { + + value = ngx_http_get_indexed_variable(r, vindex[i]); + if (value == NULL) { + continue; + } + + if (value->text.len) { + len += 1 + 1 + var[vindex[i]].name.len + value->text.len; + } + } + } + + + part = &r->headers_in.headers.part; + header = part->elts; + + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; + } + + len += ((header[i].key.len > 127) ? 4 : 1) + + ((header[i].value.len > 127) ? 4 : 1) + + 5 + header[i].key.len + header[i].value.len; + } + + + if (len > 65535) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "fastcgi: the request record is too big"); + return NGX_ERROR; + } + + + padding = 8 - len % 8; + padding = (padding == 8) ? 0 : padding; + + + size = sizeof(ngx_http_fastcgi_header_t) + + sizeof(ngx_http_fastcgi_begin_request_t) + + + sizeof(ngx_http_fastcgi_header_t) /* NGX_HTTP_FASTCGI_PARAMS */ + + len + padding + + sizeof(ngx_http_fastcgi_header_t) /* NGX_HTTP_FASTCGI_PARAMS */ + + + sizeof(ngx_http_fastcgi_header_t); /* NGX_HTTP_FASTCGI_STDIN */ + + + b = ngx_create_temp_buf(r->pool, size); + if (b == NULL) { + return NGX_ERROR; + } + + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { + return NGX_ERROR; + } + + cl->buf = b; + + h = (ngx_http_fastcgi_header_t *) b->pos; + + h->version = 1; + h->type = NGX_HTTP_FASTCGI_BEGIN_REQUEST; + h->request_id_hi = 0; + h->request_id_lo = 1; + h->content_length_hi = 0; + h->content_length_lo = sizeof(ngx_http_fastcgi_begin_request_t); + h->padding_length = 0; + h->reserved = 0; + + br = (ngx_http_fastcgi_begin_request_t *) + (b->pos + sizeof(ngx_http_fastcgi_header_t)); + br->role_hi = 0; + br->role_lo = NGX_HTTP_FASTCGI_RESPONDER; + br->flags = 0; /* NGX_HTTP_FASTCGI_KEEP_CONN */ + br->reserved[0] = 0; + br->reserved[1] = 0; + br->reserved[2] = 0; + br->reserved[3] = 0; + br->reserved[4] = 0; + + h = (ngx_http_fastcgi_header_t *) + (b->pos + sizeof(ngx_http_fastcgi_header_t) + + sizeof(ngx_http_fastcgi_begin_request_t)); + + h->version = 1; + h->type = NGX_HTTP_FASTCGI_PARAMS; + h->request_id_hi = 0; + h->request_id_lo = 1; + h->content_length_hi = (u_char) ((len >> 8) & 0xff); + h->content_length_lo = (u_char) (len & 0xff); + h->padding_length = (u_char) padding; + h->reserved = 0; + + b->last = b->pos + sizeof(ngx_http_fastcgi_header_t) + + sizeof(ngx_http_fastcgi_begin_request_t) + + sizeof(ngx_http_fastcgi_header_t); + + + *b->last++ = sizeof("PATH_TRANSLATED") - 1; + + len = flcf->root.len + r->uri.len + index; + if (len > 127) { + *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); + *b->last++ = (u_char) ((len >> 16) & 0xff); + *b->last++ = (u_char) ((len >> 8) & 0xff); + *b->last++ = (u_char) (len & 0xff); + + } else { + *b->last++ = (u_char) len; + } + + b->last = ngx_cpymem(b->last, "PATH_TRANSLATED", + sizeof("PATH_TRANSLATED") - 1); + b->last = ngx_cpymem(b->last, flcf->root.data, flcf->root.len); + b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len); + + if (index) { + b->last = ngx_cpymem(b->last, flcf->index.data, index); + } + + + *b->last++ = sizeof("REQUEST_METHOD") - 1; + + if (r->upstream->method) { + *b->last++ = (u_char) + ngx_http_fastcgi_methods[r->upstream->method - 1].len; + + b->last = ngx_cpymem(b->last, "REQUEST_METHOD", + sizeof("REQUEST_METHOD") - 1); + + b->last = ngx_cpymem(b->last, + ngx_http_fastcgi_methods[r->upstream->method - 1].data, + ngx_http_fastcgi_methods[r->upstream->method - 1].len); + + } else { + len = r->method_name.len - 1; + if (len > 127) { + *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); + *b->last++ = (u_char) ((len >> 16) & 0xff); + *b->last++ = (u_char) ((len >> 8) & 0xff); + *b->last++ = (u_char) (len & 0xff); + + } else { + *b->last++ = (u_char) len; + } + + b->last = ngx_cpymem(b->last, "REQUEST_METHOD", + sizeof("REQUEST_METHOD") - 1); + b->last = ngx_cpymem(b->last, r->method_name.data, len); + } + + + if (r->args.len) { + *b->last++ = sizeof("QUERY_STRING") - 1; + + len = r->args.len; + if (len > 127) { + *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); + *b->last++ = (u_char) ((len >> 16) & 0xff); + *b->last++ = (u_char) ((len >> 8) & 0xff); + *b->last++ = (u_char) (len & 0xff); + + } else { + *b->last++ = (u_char) len; + } + + b->last = ngx_cpymem(b->last, "QUERY_STRING", + sizeof("QUERY_STRING") - 1); + b->last = ngx_cpymem(b->last, r->args.data, len); + } + + + if (r->headers_in.content_length_n > 0) { + *b->last++ = sizeof("CONTENT_LENGTH") - 1; + + len = r->headers_in.content_length->value.len; + if (len > 127) { + *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); + *b->last++ = (u_char) ((len >> 16) & 0xff); + *b->last++ = (u_char) ((len >> 8) & 0xff); + *b->last++ = (u_char) (len & 0xff); + + } else { + *b->last++ = (u_char) len; + } + + b->last = ngx_cpymem(b->last, "CONTENT_LENGTH", + sizeof("CONTENT_LENGTH") - 1); + b->last = ngx_cpymem(b->last, r->headers_in.content_length->value.data, + len); + } + + + if (r->headers_in.content_type) { + *b->last++ = sizeof("CONTENT_TYPE") - 1; + + len = r->headers_in.content_type->value.len; + if (len > 127) { + *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); + *b->last++ = (u_char) ((len >> 16) & 0xff); + *b->last++ = (u_char) ((len >> 8) & 0xff); + *b->last++ = (u_char) (len & 0xff); + + } else { + *b->last++ = (u_char) len; + } + + b->last = ngx_cpymem(b->last, "CONTENT_TYPE", + sizeof("CONTENT_TYPE") - 1); + b->last = ngx_cpymem(b->last, r->headers_in.content_type->value.data, + len); + } + + + if (flcf->params & NGX_HTTP_FASTCGI_REDIRECT_STATUS) { + *b->last++ = sizeof("REDIRECT_STATUS") - 1; + *b->last++ = sizeof("200") - 1; + b->last = ngx_cpymem(b->last, "REDIRECT_STATUS200", + sizeof("REDIRECT_STATUS200") - 1); + } + + + if (flcf->params & NGX_HTTP_FASTCGI_REQUEST_URI) { + *b->last++ = sizeof("REQUEST_URI") - 1; + + len = r->unparsed_uri.len; + if (len > 127) { + *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); + *b->last++ = (u_char) ((len >> 16) & 0xff); + *b->last++ = (u_char) ((len >> 8) & 0xff); + *b->last++ = (u_char) (len & 0xff); + + } else { + *b->last++ = (u_char) len; + } + + b->last = ngx_cpymem(b->last, "REQUEST_URI", sizeof("REQUEST_URI") - 1); + b->last = ngx_cpymem(b->last, r->unparsed_uri.data, len); + } + + + if (flcf->params & NGX_HTTP_FASTCGI_DOCUMENT_ROOT) { + *b->last++ = sizeof("DOCUMENT_ROOT") - 1; + + len = clcf->root.len; + if (len > 127) { + *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); + *b->last++ = (u_char) ((len >> 16) & 0xff); + *b->last++ = (u_char) ((len >> 8) & 0xff); + *b->last++ = (u_char) (len & 0xff); + + } else { + *b->last++ = (u_char) len; + } + + b->last = ngx_cpymem(b->last, "DOCUMENT_ROOT", + sizeof("DOCUMENT_ROOT") - 1); + b->last = ngx_cpymem(b->last, clcf->root.data, len); + } + + + if (flcf->params & NGX_HTTP_FASTCGI_SCRIPT_FILENAME) { + *b->last++ = sizeof("SCRIPT_FILENAME") - 1; + + len = flcf->root.len + r->uri.len + index; + if (len > 127) { + *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); + *b->last++ = (u_char) ((len >> 16) & 0xff); + *b->last++ = (u_char) ((len >> 8) & 0xff); + *b->last++ = (u_char) (len & 0xff); + + } else { + *b->last++ = (u_char) len; + } + + b->last = ngx_cpymem(b->last, "SCRIPT_FILENAME", + sizeof("SCRIPT_FILENAME") - 1); + b->last = ngx_cpymem(b->last, flcf->root.data, flcf->root.len); + b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len); + + if (index) { + b->last = ngx_cpymem(b->last, flcf->index.data, index); + } + } + + + if (flcf->params & NGX_HTTP_FASTCGI_SCRIPT_NAME) { + *b->last++ = sizeof("SCRIPT_NAME") - 1; + + len = r->uri.len + index; + if (len > 127) { + *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); + *b->last++ = (u_char) ((len >> 16) & 0xff); + *b->last++ = (u_char) ((len >> 8) & 0xff); + *b->last++ = (u_char) (len & 0xff); + + } else { + *b->last++ = (u_char) len; + } + + b->last = ngx_cpymem(b->last, "SCRIPT_NAME", sizeof("SCRIPT_NAME") - 1); + b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len); + + if (index) { + b->last = ngx_cpymem(b->last, flcf->index.data, index); + } + } + + + if (flcf->params & NGX_HTTP_FASTCGI_REMOTE_ADDR) { + *b->last++ = sizeof("REMOTE_ADDR") - 1; + *b->last++ = (u_char) (r->connection->addr_text.len); + b->last = ngx_cpymem(b->last, "REMOTE_ADDR", sizeof("REMOTE_ADDR") - 1); + b->last = ngx_cpymem(b->last, r->connection->addr_text.data, + r->connection->addr_text.len); + } + + + if (port_len) { + *b->last++ = sizeof("REMOTE_PORT") - 1; + *b->last++ = (u_char) port_len; + b->last = ngx_cpymem(b->last, "REMOTE_PORT", sizeof("REMOTE_PORT") - 1); + b->last = ngx_cpymem(b->last, port_text, port_len); + } + + + if (flcf->params & NGX_HTTP_FASTCGI_SERVER_NAME) { + *b->last++ = sizeof("SERVER_NAME") - 1; + *b->last++ = (u_char) r->server_name.len; + b->last = ngx_cpymem(b->last, "SERVER_NAME", sizeof("SERVER_NAME") - 1); + b->last = ngx_cpymem(b->last, r->server_name.data, r->server_name.len); + } + + + if (flcf->params & NGX_HTTP_FASTCGI_SERVER_PORT) { + *b->last++ = sizeof("SERVER_PORT") - 1; + *b->last++ = (u_char) (r->port_text->len - 1); + b->last = ngx_cpymem(b->last, "SERVER_PORT", sizeof("SERVER_PORT") - 1); + b->last = ngx_cpymem(b->last, r->port_text->data + 1, + r->port_text->len - 1); + } + + + if (flcf->params & NGX_HTTP_FASTCGI_SERVER_ADDR) { + *b->last++ = sizeof("SERVER_ADDR") - 1; + *b->last++ = (u_char) addr_len; + b->last = ngx_cpymem(b->last, "SERVER_ADDR", sizeof("SERVER_ADDR") - 1); + b->last = ngx_cpymem(b->last, addr_text, addr_len); + } + + + if (flcf->params & NGX_HTTP_FASTCGI_SERVER_PROTOCOL + && r->http_protocol.len) + { + *b->last++ = sizeof("SERVER_PROTOCOL") - 1; + + len = r->http_protocol.len; + if (len > 127) { + *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); + *b->last++ = (u_char) ((len >> 16) & 0xff); + *b->last++ = (u_char) ((len >> 8) & 0xff); + *b->last++ = (u_char) (len & 0xff); + + } else { + *b->last++ = (u_char) len; + } + + b->last = ngx_cpymem(b->last, "SERVER_PROTOCOL", + sizeof("SERVER_PROTOCOL") - 1); + b->last = ngx_cpymem(b->last, r->http_protocol.data, len); + } + + + if (flcf->params & NGX_HTTP_FASTCGI_SERVER_SOFTWARE) { + *b->last++ = sizeof("SERVER_SOFTWARE") - 1; + *b->last++ = (u_char) (sizeof(NGINX_VER) - 1); + b->last = ngx_cpymem(b->last, "SERVER_SOFTWARE", + sizeof("SERVER_SOFTWARE") - 1); + b->last = ngx_cpymem(b->last, NGINX_VER, sizeof(NGINX_VER) - 1); + } + + + if (flcf->params & NGX_HTTP_FASTCGI_GATEWAY_INTERFACE) { + *b->last++ = sizeof("GATEWAY_INTERFACE") - 1; + *b->last++ = (u_char) (sizeof("CGI/1.1") - 1); + b->last = ngx_cpymem(b->last, "GATEWAY_INTERFACE", + sizeof("GATEWAY_INTERFACE") - 1); + b->last = ngx_cpymem(b->last, "CGI/1.1", sizeof("CGI/1.1") - 1); + } + + + if (flcf->vars) { + for (i = 0; i < flcf->vars->nelts; i++) { + + value = ngx_http_get_indexed_variable(r, vindex[i]); + if (value == NULL) { + continue; + } + + if (value->text.len == 0) { + continue; + } + + *b->last++ = (u_char) var[vindex[i]].name.len; + *b->last++ = (u_char) value->text.len; + + b->last = ngx_cpymem(b->last, var[vindex[i]].name.data, + var[vindex[i]].name.len); + + b->last = ngx_cpymem(b->last, value->text.data, value->text.len); + } + } + + + part = &r->headers_in.headers.part; + header = part->elts; + + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; + } + + len = 5 + header[i].key.len; + if (len > 127) { + *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); + *b->last++ = (u_char) ((len >> 16) & 0xff); + *b->last++ = (u_char) ((len >> 8) & 0xff); + *b->last++ = (u_char) (len & 0xff); + + } else { + *b->last++ = (u_char) len; + } + + len = header[i].value.len; + if (len > 127) { + *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); + *b->last++ = (u_char) ((len >> 16) & 0xff); + *b->last++ = (u_char) ((len >> 8) & 0xff); + *b->last++ = (u_char) (len & 0xff); + + } else { + *b->last++ = (u_char) len; + } + + b->last = ngx_cpymem(b->last, "HTTP_", sizeof("HTTP_") - 1); + + for (n = 0; n < header[i].key.len; n++) { + ch = header[i].key.data[n]; + + if (ch >= 'a' && ch <= 'z') { + ch &= ~0x20; + + } else if (ch == '-') { + ch = '_'; + } + + *b->last++ = ch; + } + + b->last = ngx_cpymem(b->last, header[i].value.data, + header[i].value.len); + } + + + if (padding) { + ngx_memzero(b->last, padding); + b->last += padding; + } + + + h = (ngx_http_fastcgi_header_t *) b->last; + b->last += sizeof(ngx_http_fastcgi_header_t); + + h->version = 1; + h->type = NGX_HTTP_FASTCGI_PARAMS; + h->request_id_hi = 0; + h->request_id_lo = 1; + h->content_length_hi = 0; + h->content_length_lo = 0; + h->padding_length = 0; + h->reserved = 0; + + h = (ngx_http_fastcgi_header_t *) b->last; + b->last += sizeof(ngx_http_fastcgi_header_t); + + body = r->request_body->bufs; + r->request_body->bufs = cl; + +#if (NGX_SUPPRESS_WARN) + file_pos = 0; + pos = NULL; +#endif + + while (body) { + + if (body->buf->in_file) { + file_pos = body->buf->file_pos; + + } else { + pos = body->buf->pos; + } + + next = 0; + + do { + b = ngx_alloc_buf(r->pool); + if (b == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(b, body->buf, sizeof(ngx_buf_t)); + + if (body->buf->in_file) { + b->file_pos = file_pos; + file_pos += 32 * 1024; + + if (file_pos > body->buf->file_last) { + file_pos = body->buf->file_last; + next = 1; + } + + b->file_last = file_pos; + len = (ngx_uint_t) (file_pos - b->file_pos); + + } else { + b->pos = pos; + pos += 32 * 1024; + + if (pos > body->buf->last) { + pos = body->buf->last; + next = 1; + } + + b->last = pos; + len = (ngx_uint_t) (pos - b->pos); + } + + padding = 8 - len % 8; + padding = (padding == 8) ? 0 : padding; + + h->version = 1; + h->type = NGX_HTTP_FASTCGI_STDIN; + h->request_id_hi = 0; + h->request_id_lo = 1; + h->content_length_hi = (u_char) ((len >> 8) & 0xff); + h->content_length_lo = (u_char) (len & 0xff); + h->padding_length = (u_char) padding; + h->reserved = 0; + + cl->next = ngx_alloc_chain_link(r->pool); + if (cl->next == NULL) { + return NGX_ERROR; + } + + cl = cl->next; + cl->buf = b; + + b = ngx_create_temp_buf(r->pool, sizeof(ngx_http_fastcgi_header_t) + + padding); + if (b == NULL) { + return NGX_ERROR; + } + + if (padding) { + ngx_memzero(b->last, padding); + b->last += padding; + } + + h = (ngx_http_fastcgi_header_t *) b->last; + b->last += sizeof(ngx_http_fastcgi_header_t); + + cl->next = ngx_alloc_chain_link(r->pool); + if (cl->next == NULL) { + return NGX_ERROR; + } + + cl = cl->next; + cl->buf = b; + + } while (!next); + + body = body->next; + } + + h->version = 1; + h->type = NGX_HTTP_FASTCGI_STDIN; + h->request_id_hi = 0; + h->request_id_lo = 1; + h->content_length_hi = 0; + h->content_length_lo = 0; + h->padding_length = 0; + h->reserved = 0; + + cl->next = NULL; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_fastcgi_reinit_request(ngx_http_request_t *r) +{ + ngx_http_fastcgi_ctx_t *f; + + f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module); + + if (f == NULL) { + return NGX_OK; + } + + f->state = ngx_http_fastcgi_st_version; + f->header = 0; + + ngx_memzero(&f->upstream->headers_in, + sizeof(ngx_http_fastcgi_headers_in_t)); + + if (f->upstream->headers_in.headers.part.elts) { + if (ngx_list_init(&f->upstream->headers_in.headers, r->pool, 8, + sizeof(ngx_table_elt_t)) == NGX_ERROR) + { + return NGX_ERROR; + } + } + + return NGX_OK; +} + + +static ngx_int_t ngx_http_fastcgi_process_header(ngx_http_request_t *r) +{ + u_char *start, *last; + ngx_str_t *status_line, line; + ngx_int_t rc, status; + ngx_uint_t i; + ngx_table_elt_t *h; + ngx_http_upstream_t *u; + ngx_http_fastcgi_ctx_t *f; + + f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module); + + if (f == NULL) { + f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t)); + if (f == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + ngx_http_set_ctx(r, f, ngx_http_fastcgi_module); + + f->upstream = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_upstream_t)); + if (f->upstream == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + if (ngx_list_init(&f->upstream->headers_in.headers, r->pool, 8, + sizeof(ngx_table_elt_t)) == NGX_ERROR) + { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + } + + u = r->upstream; + + for ( ;; ) { + + if (f->state < ngx_http_fastcgi_st_data) { + + f->pos = u->header_in.pos; + f->last = u->header_in.last; + + rc = ngx_http_fastcgi_process_record(r, f); + + u->header_in.pos = f->pos; + u->header_in.last = f->last; + + if (rc == NGX_AGAIN) { + return NGX_AGAIN; + } + + if (rc == NGX_ERROR) { + return NGX_HTTP_UPSTREAM_INVALID_HEADER; + } + + if (f->type != NGX_HTTP_FASTCGI_STDOUT + && f->type != NGX_HTTP_FASTCGI_STDERR) + { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream sent unexpected FastCGI record: %d", + f->type); + + return NGX_HTTP_UPSTREAM_INVALID_HEADER; + } + + if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream closed prematurely FastCGI stdout"); + + return NGX_HTTP_UPSTREAM_INVALID_HEADER; + } + } + + if (f->state == ngx_http_fastcgi_st_padding) { + + if (u->header_in.pos + f->padding < u->header_in.last) { + f->state = ngx_http_fastcgi_st_version; + u->header_in.pos += f->padding; + + continue; + } + + if (u->header_in.pos + f->padding == u->header_in.last) { + f->state = ngx_http_fastcgi_st_version; + u->header_in.pos = u->header_in.last; + + return NGX_AGAIN; + } + + f->padding -= u->header_in.last - u->header_in.pos; + u->header_in.pos = u->header_in.last; + + return NGX_AGAIN; + } + + + /* f->state == ngx_http_fastcgi_st_data */ + + if (f->type == NGX_HTTP_FASTCGI_STDERR) { + + if (f->header) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "upstream split a header in FastCGI records"); + + return NGX_HTTP_UPSTREAM_INVALID_HEADER; + } + + if (f->length) { + line.data = u->header_in.pos; + + if (u->header_in.pos + f->length <= u->header_in.last) { + line.len = f->length; + u->header_in.pos += f->length; + f->length = 0; + f->state = ngx_http_fastcgi_st_padding; + + } else { + line.len = u->header_in.last - u->header_in.pos; + f->length -= u->header_in.last - u->header_in.pos; + u->header_in.pos = u->header_in.last; + } + + while (line.data[line.len - 1] == LF + || line.data[line.len - 1] == CR + || line.data[line.len - 1] == '.' + || line.data[line.len - 1] == ' ') + { + line.len--; + } + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "FastCGI sent in stderr: \"%V\"", &line); + + if (u->header_in.pos == u->header_in.last) { + return NGX_AGAIN; + } + + } else { + f->state = ngx_http_fastcgi_st_version; + } + + continue; + } + + + /* f->type == NGX_HTTP_FASTCGI_STDOUT */ + + start = u->header_in.pos; + + if (u->header_in.pos + f->length < u->header_in.last) { + + /* + * set u->header_in.last to the end of the FastCGI record data + * for ngx_http_parse_header_line() + */ + + last = u->header_in.last; + u->header_in.last = u->header_in.pos + f->length; + + } else { + last = NULL; + } + + f->header = 1; + + for ( ;; ) { + + rc = ngx_http_parse_header_line(r, &u->header_in); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http fastcgi parser: %d", rc); + + if (rc == NGX_AGAIN) { + break; + } + + if (rc == NGX_OK) { + + /* a header line has been parsed successfully */ + + h = ngx_list_push(&f->upstream->headers_in.headers); + if (h == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + h->key.len = r->header_name_end - r->header_name_start; + h->value.len = r->header_end - r->header_start; + + h->key.data = ngx_palloc(r->pool, + h->key.len + 1 + h->value.len + 1); + if (h->key.data == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + h->value.data = h->key.data + h->key.len + 1; + + ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1); + ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1); + + for (i = 0; ngx_http_fastcgi_headers_in[i].name.len != 0; i++) { + if (ngx_http_fastcgi_headers_in[i].name.len != h->key.len) { + continue; + } + + if (ngx_strcasecmp(ngx_http_fastcgi_headers_in[i].name.data, + h->key.data) == 0) + { + *((ngx_table_elt_t **) + ((char *) &f->upstream->headers_in + + ngx_http_fastcgi_headers_in[i].offset)) = h; + break; + } + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http fastcgi header: \"%V: %V\"", + &h->key, &h->value); + + continue; + } + + if (rc == NGX_HTTP_PARSE_HEADER_DONE) { + + /* a whole header has been parsed successfully */ + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http fastcgi header done"); + + if (f->upstream->headers_in.status) { + status_line = &f->upstream->headers_in.status->value; + + status = ngx_atoi(status_line->data, 3); + + if (status == NGX_ERROR) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + r->headers_out.status = status; + r->headers_out.status_line = *status_line; + + } else { + r->headers_out.status = 200; + r->headers_out.status_line.len = sizeof("200 OK") - 1; + r->headers_out.status_line.data = (u_char *) "200 OK"; + } + + u->state->status = r->headers_out.status; +#if 0 + if (u->cachable) { + u->cachable = ngx_http_upstream_is_cachable(r); + } +#endif + + break; + } + + /* there was error while a header line parsing */ + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + ngx_http_upstream_header_errors[rc + - NGX_HTTP_PARSE_HEADER_ERROR]); + + return NGX_HTTP_UPSTREAM_INVALID_HEADER; + + } + + if (last) { + u->header_in.last = last; + } + + f->length -= u->header_in.pos - start; + + if (rc == NGX_AGAIN) { + if (u->header_in.pos == u->header_in.last) { + return NGX_AGAIN; + } + + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "upstream split a header in FastCGI records"); + + return NGX_HTTP_UPSTREAM_INVALID_HEADER; + } + + if (f->length == 0) { + if (f->padding) { + f->state = ngx_http_fastcgi_st_padding; + } else { + f->state = ngx_http_fastcgi_st_version; + } + } + + return NGX_OK; + } +} + + +static ngx_int_t +ngx_http_fastcgi_send_header(ngx_http_request_t *r) +{ + ngx_uint_t i; + ngx_list_part_t *part; + ngx_table_elt_t *ho, *h; + ngx_http_fastcgi_ctx_t *f; + ngx_http_fastcgi_headers_in_t *headers_in; + + f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module); + + headers_in = &f->upstream->headers_in; + part = &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; + } + + /* ignore some headers */ + + if (&h[i] == headers_in->status) { + continue; + } + + + if (&h[i] == headers_in->x_powered_by + && !r->upstream->conf->x_powered_by) + { + continue; + } + + + /* "Content-Type" is handled specially */ + + if (&h[i] == headers_in->content_type) { + r->headers_out.content_type = &h[i]; + r->headers_out.content_type->key.len = 0; + continue; + } + + + /* copy some header pointers and set up r->headers_out */ + + ho = ngx_list_push(&r->headers_out.headers); + if (ho == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + *ho = h[i]; + +#if (NGX_HTTP_GZIP) + if (&h[i] == headers_in->content_encoding) { + r->headers_out.content_encoding = ho; + continue; + } +#endif + + if (&h[i] == headers_in->content_length) { + r->headers_out.content_length = ho; + r->headers_out.content_length_n = ngx_atoi(ho->value.data, + ho->value.len); + continue; + } + } + + return ngx_http_send_header(r); +} + + +static ngx_int_t +ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, ngx_buf_t *buf) +{ + ngx_int_t rc; + ngx_buf_t *b, **prev; + ngx_str_t line; + ngx_chain_t *cl; + ngx_http_request_t *r; + ngx_http_fastcgi_ctx_t *f; + + if (buf->pos == buf->last) { + return NGX_OK; + } + + r = p->input_ctx; + f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module); + + b = NULL; + prev = &buf->shadow; + + f->pos = buf->pos; + f->last = buf->last; + + for ( ;; ) { + if (f->state < ngx_http_fastcgi_st_data) { + + rc = ngx_http_fastcgi_process_record(r, f); + + if (rc == NGX_AGAIN) { + break; + } + + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) { + f->state = ngx_http_fastcgi_st_version; + p->upstream_done = 1; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0, + "http fastcgi closed stdout"); + + continue; + } + + if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) { + f->state = ngx_http_fastcgi_st_version; + p->upstream_done = 1; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0, + "http fastcgi sent end request"); + + break; + } + } + + + if (f->state == ngx_http_fastcgi_st_padding) { + + if (f->pos + f->padding < f->last) { + f->state = ngx_http_fastcgi_st_version; + f->pos += f->padding; + + continue; + } + + if (f->pos + f->padding == f->last) { + f->state = ngx_http_fastcgi_st_version; + + break; + } + + f->padding -= f->last - f->pos; + + break; + } + + + /* f->state == ngx_http_fastcgi_st_data */ + + if (f->type == NGX_HTTP_FASTCGI_STDERR) { + + if (f->length) { + line.data = f->pos; + + if (f->pos + f->length <= f->last) { + line.len = f->length; + f->pos += f->length; + f->length = 0; + f->state = ngx_http_fastcgi_st_padding; + + } else { + line.len = f->last - f->pos; + f->length -= f->last - f->pos; + f->pos = f->last; + } + + while (line.data[line.len - 1] == LF + || line.data[line.len - 1] == CR + || line.data[line.len - 1] == '.' + || line.data[line.len - 1] == ' ') + { + line.len--; + } + + ngx_log_error(NGX_LOG_ERR, p->log, 0, + "FastCGI sent in stderr: \"%V\"", &line); + + if (f->pos == f->last) { + break; + } + + } else { + f->state = ngx_http_fastcgi_st_version; + } + + continue; + } + + + /* f->type == NGX_HTTP_FASTCGI_STDOUT */ + + if (p->free) { + b = p->free->buf; + p->free = p->free->next; + + } else { + b = ngx_alloc_buf(p->pool); + if (b == NULL) { + return NGX_ERROR; + } + } + + ngx_memzero(b, sizeof(ngx_buf_t)); + + b->pos = f->pos; + b->start = buf->start; + b->end = buf->end; + b->tag = p->tag; + b->temporary = 1; + b->recycled = 1; + + *prev = b; + prev = &b->shadow; + + cl = ngx_alloc_chain_link(p->pool); + if (cl == NULL) { + return NGX_ERROR; + } + + cl->buf = b; + cl->next = NULL; + + if (p->in) { + *p->last_in = cl; + } else { + p->in = cl; + } + p->last_in = &cl->next; + + + /* STUB */ b->num = buf->num; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d", b->num); + + + if (f->pos + f->length < f->last) { + + if (f->padding) { + f->state = ngx_http_fastcgi_st_padding; + } else { + f->state = ngx_http_fastcgi_st_version; + } + + f->pos += f->length; + b->last = f->pos; + + continue; + } + + if (f->pos + f->length == f->last) { + + if (f->padding) { + f->state = ngx_http_fastcgi_st_padding; + } else { + f->state = ngx_http_fastcgi_st_version; + } + + b->last = f->last; + + break; + } + + f->length -= f->last - f->pos; + + b->last = f->last; + + break; + + } + + if (b) { + b->shadow = buf; + b->last_shadow = 1; + + return NGX_OK; + } + + /* there is no data record in the buf, add it to free chain */ + + if (ngx_event_pipe_add_free_buf(p, buf) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_fastcgi_process_record(ngx_http_request_t *r, + ngx_http_fastcgi_ctx_t *f) +{ + u_char ch, *p; + ngx_http_fastcgi_state_e state; + + state = f->state; + + for (p = f->pos; p < f->last; p++) { + + ch = *p; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http fastcgi record byte: %02Xd", ch); + + switch (state) { + + case ngx_http_fastcgi_st_version: + if (ch != 1) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream sent unsupported FastCGI " + "protocol version: %d", ch); + return NGX_ERROR; + } + state = ngx_http_fastcgi_st_type; + break; + + case ngx_http_fastcgi_st_type: + switch (ch) { + case NGX_HTTP_FASTCGI_STDOUT: + case NGX_HTTP_FASTCGI_STDERR: + case NGX_HTTP_FASTCGI_END_REQUEST: + f->type = (ngx_uint_t) ch; + break; + default: + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream sent invalid FastCGI " + "record type: %d", ch); + return NGX_ERROR; + + } + state = ngx_http_fastcgi_st_request_id_hi; + break; + + /* we support the single request per connection */ + + case ngx_http_fastcgi_st_request_id_hi: + if (ch != 0) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream sent unexpected FastCGI " + "request id high byte: %d", ch); + return NGX_ERROR; + } + state = ngx_http_fastcgi_st_request_id_lo; + break; + + case ngx_http_fastcgi_st_request_id_lo: + if (ch != 1) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream sent unexpected FastCGI " + "request id low byte: %d", ch); + return NGX_ERROR; + } + state = ngx_http_fastcgi_st_content_length_hi; + break; + + case ngx_http_fastcgi_st_content_length_hi: + f->length = ch << 8; + state = ngx_http_fastcgi_st_content_length_lo; + break; + + case ngx_http_fastcgi_st_content_length_lo: + f->length |= (size_t) ch; + state = ngx_http_fastcgi_st_padding_length; + break; + + case ngx_http_fastcgi_st_padding_length: + f->padding = (size_t) ch; + state = ngx_http_fastcgi_st_reserved; + break; + + case ngx_http_fastcgi_st_reserved: + state = ngx_http_fastcgi_st_data; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http fastcgi record length: %z", f->length); + + f->pos = p + 1; + f->state = state; + + return NGX_OK; + + /* suppress warning */ + case ngx_http_fastcgi_st_data: + case ngx_http_fastcgi_st_padding: + break; + } + } + + f->pos = p + 1; + f->state = state; + + return NGX_AGAIN; +} + + +static void +ngx_http_fastcgi_abort_request(ngx_http_request_t *r) +{ + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "abort http fastcgi request"); + + return; +} + + +static void +ngx_http_fastcgi_finalize_request(ngx_http_request_t *r, ngx_int_t rc) +{ + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "finalize http fastcgi request"); + + return; +} + + +static char * +ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_fastcgi_loc_conf_t *lcf = conf; + + ngx_str_t *value; + ngx_inet_upstream_t inet_upstream; + ngx_http_core_loc_conf_t *clcf; +#if (NGX_HAVE_UNIX_DOMAIN) + ngx_unix_domain_upstream_t unix_upstream; +#endif + + value = cf->args->elts; + + if (ngx_strncasecmp(value[1].data, "unix:", 5) == 0) { + +#if (NGX_HAVE_UNIX_DOMAIN) + + ngx_memzero(&unix_upstream, sizeof(ngx_unix_domain_upstream_t)); + + unix_upstream.name = value[1]; + unix_upstream.url = value[1]; + + lcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream); + if (lcf->peers == NULL) { + return NGX_CONF_ERROR; + } + +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the unix domain sockets are not supported " + "on this platform"); + return NGX_CONF_ERROR; + +#endif + + } else { + ngx_memzero(&inet_upstream, sizeof(ngx_inet_upstream_t)); + + inet_upstream.name = value[1]; + inet_upstream.url = value[1]; + + lcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream); + if (lcf->peers == NULL) { + return NGX_CONF_ERROR; + } + } + + clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + + clcf->handler = ngx_http_fastcgi_handler; + +#if (NGX_PCRE) + lcf->location = clcf->regex ? &ngx_http_fastcgi_uri : &clcf->name; +#else + lcf->location = &clcf->name; +#endif + + if (clcf->name.data[clcf->name.len - 1] == '/') { + clcf->auto_redirect = 1; + } + + return NGX_CONF_OK; +} + + +static char * +ngx_http_fastcgi_set_var(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_fastcgi_loc_conf_t *lcf = conf; + + ngx_uint_t i, *index; + ngx_str_t *value; + ngx_http_variable_t *var; + ngx_http_core_main_conf_t *cmcf; + + if (lcf->vars == NULL) { + lcf->vars = ngx_array_create(cf->pool, 4, + sizeof(ngx_http_variable_t *)); + if (lcf->vars == NULL) { + return NGX_CONF_ERROR; + } + } + + cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); + + value = cf->args->elts; + + var = cmcf->variables.elts; + for (i = 0; i < cmcf->variables.nelts; i++) { + if (ngx_strcasecmp(var[i].name.data, value[1].data) == 0) { + + index = ngx_array_push(lcf->vars); + if (index == NULL) { + return NGX_CONF_ERROR; + } + + *index = var[i].index; + return NGX_CONF_OK; + } + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "unknown variable name \"%V\"", &value[1]); + return NGX_CONF_ERROR; +} + + +static char * +ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post, void *data) +{ +#if (NGX_FREEBSD) + ssize_t *np = data; + + if (*np >= ngx_freebsd_net_inet_tcp_sendspace) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"fastcgi_send_lowat\" must be less than %d " + "(sysctl net.inet.tcp.sendspace)", + ngx_freebsd_net_inet_tcp_sendspace); + + return NGX_CONF_ERROR; + } + +#elif !(NGX_HAVE_SO_SNDLOWAT) + ssize_t *np = data; + + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "\"fastcgi_send_lowat\" is not supported, ignored"); + + *np = 0; + +#endif + + return NGX_CONF_OK; +} + + +static void * +ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_fastcgi_loc_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastcgi_loc_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + /* + * set by ngx_pcalloc(): + * + * conf->upstream.bufs.num = 0; + * conf->upstream.path = NULL; + * conf->upstream.next_upstream = 0; + * conf->upstream.temp_path = NULL; + * conf->params = 0; + * conf->root.len = 0; + * conf->root.data = NULL; + * conf->index.len = 0; + * conf->index.data = NULL; + * conf->location = NULL; + */ + + conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; + conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; + conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE; + + conf->upstream.header_buffer_size = NGX_CONF_UNSET_SIZE; + conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC; + conf->upstream.busy_buffers_size = NGX_CONF_UNSET_SIZE; + + conf->upstream.max_temp_file_size = NGX_CONF_UNSET_SIZE; + conf->upstream.temp_file_write_size = NGX_CONF_UNSET_SIZE; + + conf->upstream.redirect_errors = NGX_CONF_UNSET; + conf->upstream.x_powered_by = NGX_CONF_UNSET; + + /* "fastcgi_cyclic_temp_file" is disabled */ + conf->upstream.cyclic_temp_file = 0; + + return conf; +} + + +static char * +ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_fastcgi_loc_conf_t *prev = parent; + ngx_http_fastcgi_loc_conf_t *conf = child; + + size_t size; + + ngx_conf_merge_msec_value(conf->upstream.connect_timeout, + prev->upstream.connect_timeout, 60000); + ngx_conf_merge_msec_value(conf->upstream.send_timeout, + prev->upstream.send_timeout, 60000); + ngx_conf_merge_size_value(conf->upstream.send_lowat, + prev->upstream.send_lowat, 0); + + ngx_conf_merge_msec_value(conf->upstream.read_timeout, + prev->upstream.read_timeout, 60000); + + ngx_conf_merge_msec_value(conf->upstream.redirect_errors, + prev->upstream.redirect_errors, 0); + + ngx_conf_merge_msec_value(conf->upstream.x_powered_by, + prev->upstream.x_powered_by, 1); + + + ngx_conf_merge_size_value(conf->upstream.header_buffer_size, + prev->upstream.header_buffer_size, + (size_t) ngx_pagesize); + + ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs, + 8, ngx_pagesize); + + if (conf->upstream.bufs.num < 2) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "there must be at least 2 \"fastcgi_buffers\""); + return NGX_CONF_ERROR; + } + + + size = conf->upstream.header_buffer_size; + if (size < conf->upstream.bufs.size) { + size = conf->upstream.bufs.size; + } + + + ngx_conf_merge_size_value(conf->upstream.busy_buffers_size, + prev->upstream.busy_buffers_size, + NGX_CONF_UNSET_SIZE); + + if (conf->upstream.busy_buffers_size == NGX_CONF_UNSET_SIZE) { + conf->upstream.busy_buffers_size = 2 * size; + + } else if (conf->upstream.busy_buffers_size < size) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"fastcgi_busy_buffers_size\" must be equal or bigger than " + "maximum of the value of \"fastcgi_header_buffer_size\" and " + "one of the \"fastcgi_buffers\""); + + return NGX_CONF_ERROR; + + } else if (conf->upstream.busy_buffers_size + > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size) + { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"fastcgi_busy_buffers_size\" must be less than " + "the size of all \"fastcgi_buffers\" minus one buffer"); + + return NGX_CONF_ERROR; + } + + + ngx_conf_merge_size_value(conf->upstream.temp_file_write_size, + prev->upstream.temp_file_write_size, + NGX_CONF_UNSET_SIZE); + + if (conf->upstream.temp_file_write_size == NGX_CONF_UNSET_SIZE) { + conf->upstream.temp_file_write_size = 2 * size; + + } else if (conf->upstream.temp_file_write_size < size) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"fastcgi_temp_file_write_size\" must be equal or bigger than " + "maximum of the value of \"fastcgi_header_buffer_size\" and " + "one of the \"fastcgi_buffers\""); + + return NGX_CONF_ERROR; + } + + + ngx_conf_merge_size_value(conf->upstream.max_temp_file_size, + prev->upstream.max_temp_file_size, + NGX_CONF_UNSET_SIZE); + + if (conf->upstream.max_temp_file_size == NGX_CONF_UNSET_SIZE) { + + conf->upstream.max_temp_file_size = 1024 * 1024 * 1024; + + } else if (conf->upstream.max_temp_file_size != 0 + && conf->upstream.max_temp_file_size < size) + { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"fastcgi_max_temp_file_size\" must be equal to zero to disable " + "the temporary files usage or must be equal or bigger than " + "maximum of the value of \"fastcgi_header_buffer_size\" and " + "one of the \"fastcgi_buffers\""); + + return NGX_CONF_ERROR; + } + + + ngx_conf_merge_bitmask_value(conf->upstream.next_upstream, + prev->upstream.next_upstream, + (NGX_CONF_BITMASK_SET + |NGX_HTTP_UPSTREAM_FT_ERROR + |NGX_HTTP_UPSTREAM_FT_TIMEOUT)); + + ngx_conf_merge_path_value(conf->upstream.temp_path, + prev->upstream.temp_path, + NGX_HTTP_FASTCGI_TEMP_PATH, 1, 2, 0, + ngx_garbage_collector_temp_handler, cf); + + + ngx_conf_merge_bitmask_value(conf->params, prev->params, + (NGX_CONF_BITMASK_SET + |NGX_HTTP_FASTCGI_REMOTE_ADDR + |NGX_HTTP_FASTCGI_REMOTE_USER + |NGX_HTTP_FASTCGI_SERVER_NAME + |NGX_HTTP_FASTCGI_SERVER_PORT + |NGX_HTTP_FASTCGI_SCRIPT_NAME + |NGX_HTTP_FASTCGI_AUTH_TYPE + |NGX_HTTP_FASTCGI_REQUEST_URI + |NGX_HTTP_FASTCGI_REDIRECT_STATUS)); + + ngx_conf_merge_str_value(conf->root, prev->root, ""); + + if (conf->root.len && conf->root.data[conf->root.len - 1] == '/') { + conf->root.len--; + } + + ngx_conf_merge_str_value(conf->index, prev->index, ""); + + if (conf->vars == NULL) { + conf->vars = prev->vars; + } + + return NGX_CONF_OK; +} 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 @@ -64,9 +64,9 @@ static ngx_http_variable_value_t ngx_ht /* AF_INET only */ static ngx_http_variable_value_t * -ngx_http_geo_variable(ngx_http_request_t *r, void *data) +ngx_http_geo_variable(ngx_http_request_t *r, uintptr_t data) { - ngx_radix_tree_t *tree = data; + ngx_radix_tree_t *tree = (ngx_radix_tree_t *) data; struct sockaddr_in *sin; ngx_http_variable_value_t *var; @@ -90,33 +90,46 @@ static char * ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *rv; - ngx_str_t *value; + ngx_str_t *value, name; ngx_conf_t save; ngx_pool_t *pool; ngx_radix_tree_t *tree; ngx_http_geo_conf_t geo; ngx_http_variable_t *var; - if (!(var = ngx_http_add_variable(cf))) { + value = cf->args->elts; + + name = value[1]; + + if (name.data[0] != '$') { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "\"%V\" variable name should start with '$'", + &value[1]); + } else { + name.len--; + name.data++; + } + + var = ngx_http_add_variable(cf, &name, 1); + if (var == NULL) { return NGX_CONF_ERROR; } - if (!(tree = ngx_radix_tree_create(cf->pool, -1))) { + tree = ngx_radix_tree_create(cf->pool, -1); + if (tree == NULL) { return NGX_CONF_ERROR; } - value = cf->args->elts; - - var->name = value[1]; var->handler = ngx_http_geo_variable; - var->data = tree; + var->data = (uintptr_t) tree; /* * create the temporary pool of a huge initial size * to process quickly a large number of geo lines */ - if (!(pool = ngx_create_pool(512 * 1024, cf->log))) { + pool = ngx_create_pool(512 * 1024, cf->log); + if (pool == NULL) { return NGX_CONF_ERROR; } @@ -212,7 +225,12 @@ ngx_http_geo(ngx_conf_t *cf, ngx_command if (n == NGX_ERROR) { for (i = 0; i < geo->values.nelts; i++) { - if (ngx_strcmp(value[1].data, v[i]->text.data) == 0) { + if (v[i]->text.len != value[1].len) { + continue; + } + + if (ngx_strncmp(value[1].data, v[i]->text.data, value[1].len) == 0) + { var = v[i]; break; } @@ -227,20 +245,22 @@ ngx_http_geo(ngx_conf_t *cf, ngx_command } } - if (i == geo->values.nelts) { + if (var == NULL) { var = ngx_palloc(geo->pool, sizeof(ngx_http_variable_value_t)); if (var == NULL) { return NGX_CONF_ERROR; } var->text.len = value[1].len; - if (!(var->text.data = ngx_pstrdup(geo->pool, &value[1]))) { + var->text.data = ngx_pstrdup(geo->pool, &value[1]); + if (var->text.data == NULL) { return NGX_CONF_ERROR; } var->value = (n == NGX_ERROR) ? 0 : n; - if (!(v = ngx_array_push(&geo->values))) { + v = ngx_array_push(&geo->values); + if (v == NULL) { return NGX_CONF_ERROR; } diff --git a/src/http/modules/ngx_http_gzip_filter.c b/src/http/modules/ngx_http_gzip_filter.c deleted file mode 100644 --- a/src/http/modules/ngx_http_gzip_filter.c +++ /dev/null @@ -1,1142 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#include -#include -#include - -#include - - -typedef struct { - ngx_flag_t enable; - ngx_flag_t no_buffer; - - ngx_array_t *types; /* array of ngx_http_gzip_type_t */ - - ngx_bufs_t bufs; - - ngx_uint_t http_version; - ngx_uint_t proxied; - - int level; - size_t wbits; - size_t memlevel; - ssize_t min_length; -} ngx_http_gzip_conf_t; - - -typedef struct { - ngx_str_t name; - ngx_uint_t enable; -} ngx_http_gzip_type_t; - - -#define NGX_HTTP_GZIP_PROXIED_OFF 0x0002 -#define NGX_HTTP_GZIP_PROXIED_EXPIRED 0x0004 -#define NGX_HTTP_GZIP_PROXIED_NO_CACHE 0x0008 -#define NGX_HTTP_GZIP_PROXIED_NO_STORE 0x0010 -#define NGX_HTTP_GZIP_PROXIED_PRIVATE 0x0020 -#define NGX_HTTP_GZIP_PROXIED_NO_LM 0x0040 -#define NGX_HTTP_GZIP_PROXIED_NO_ETAG 0x0080 -#define NGX_HTTP_GZIP_PROXIED_AUTH 0x0100 -#define NGX_HTTP_GZIP_PROXIED_ANY 0x0200 - - -typedef struct { - ngx_chain_t *in; - ngx_chain_t *free; - ngx_chain_t *busy; - ngx_chain_t *out; - ngx_chain_t **last_out; - ngx_buf_t *in_buf; - ngx_buf_t *out_buf; - ngx_int_t bufs; - - off_t length; - - void *preallocated; - char *free_mem; - ngx_uint_t allocated; - - unsigned flush:4; - unsigned redo:1; - unsigned done:1; - - size_t zin; - size_t zout; - - uint32_t crc32; - z_stream zstream; - ngx_http_request_t *request; -} ngx_http_gzip_ctx_t; - - -static ngx_int_t ngx_http_gzip_proxied(ngx_http_request_t *r, - ngx_http_gzip_conf_t *conf); -static void *ngx_http_gzip_filter_alloc(void *opaque, u_int items, - u_int size); -static void ngx_http_gzip_filter_free(void *opaque, void *address); -static void ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx); - -static u_char *ngx_http_gzip_log_ratio(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op); - -static ngx_int_t ngx_http_gzip_add_log_formats(ngx_conf_t *cf); - -static ngx_int_t ngx_http_gzip_filter_init(ngx_cycle_t *cycle); -static void *ngx_http_gzip_create_conf(ngx_conf_t *cf); -static char *ngx_http_gzip_merge_conf(ngx_conf_t *cf, - void *parent, void *child); -static char *ngx_http_gzip_set_types(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); -static char *ngx_http_gzip_set_window(ngx_conf_t *cf, void *post, void *data); -static char *ngx_http_gzip_set_hash(ngx_conf_t *cf, void *post, void *data); - - -static ngx_conf_num_bounds_t ngx_http_gzip_comp_level_bounds = { - ngx_conf_check_num_bounds, 1, 9 -}; - -static ngx_conf_post_handler_pt ngx_http_gzip_set_window_p = - ngx_http_gzip_set_window; -static ngx_conf_post_handler_pt ngx_http_gzip_set_hash_p = - ngx_http_gzip_set_hash; - - - -static ngx_conf_enum_t ngx_http_gzip_http_version[] = { - { ngx_string("1.0"), NGX_HTTP_VERSION_10 }, - { ngx_string("1.1"), NGX_HTTP_VERSION_11 }, - { ngx_null_string, 0 } -}; - - -static ngx_conf_bitmask_t ngx_http_gzip_proxied_mask[] = { - { ngx_string("off"), NGX_HTTP_GZIP_PROXIED_OFF }, - { ngx_string("expired"), NGX_HTTP_GZIP_PROXIED_EXPIRED }, - { ngx_string("no-cache"), NGX_HTTP_GZIP_PROXIED_NO_CACHE }, - { ngx_string("no-store"), NGX_HTTP_GZIP_PROXIED_NO_STORE }, - { ngx_string("private"), NGX_HTTP_GZIP_PROXIED_PRIVATE }, - { ngx_string("no_last_modified"), NGX_HTTP_GZIP_PROXIED_NO_LM }, - { ngx_string("no_etag"), NGX_HTTP_GZIP_PROXIED_NO_ETAG }, - { ngx_string("auth"), NGX_HTTP_GZIP_PROXIED_AUTH }, - { ngx_string("any"), NGX_HTTP_GZIP_PROXIED_ANY }, - { ngx_null_string, 0 } -}; - - -static ngx_command_t ngx_http_gzip_filter_commands[] = { - - { ngx_string("gzip"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF - |NGX_CONF_FLAG, - ngx_conf_set_flag_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_gzip_conf_t, enable), - NULL }, - - { ngx_string("gzip_buffers"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, - ngx_conf_set_bufs_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_gzip_conf_t, bufs), - NULL }, - - { ngx_string("gzip_types"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, - ngx_http_gzip_set_types, - NGX_HTTP_LOC_CONF_OFFSET, - 0, - NULL }, - - { ngx_string("gzip_comp_level"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_num_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_gzip_conf_t, level), - &ngx_http_gzip_comp_level_bounds }, - - { ngx_string("gzip_window"), - 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, wbits), - &ngx_http_gzip_set_window_p }, - - { ngx_string("gzip_hash"), - 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, memlevel), - &ngx_http_gzip_set_hash_p }, - - { ngx_string("gzip_no_buffer"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_gzip_conf_t, no_buffer), - NULL }, - - { ngx_string("gzip_http_version"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY, - ngx_conf_set_enum_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_gzip_conf_t, http_version), - &ngx_http_gzip_http_version }, - - { ngx_string("gzip_proxied"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY, - ngx_conf_set_bitmask_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_gzip_conf_t, proxied), - &ngx_http_gzip_proxied_mask }, - - { ngx_string("gzip_min_length"), - 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, min_length), - NULL }, - - ngx_null_command -}; - - -static ngx_http_module_t ngx_http_gzip_filter_module_ctx = { - ngx_http_gzip_add_log_formats, /* pre conf */ - - NULL, /* create main configuration */ - NULL, /* init main configuration */ - - NULL, /* create server configuration */ - NULL, /* merge server configuration */ - - ngx_http_gzip_create_conf, /* create location configuration */ - ngx_http_gzip_merge_conf /* merge location configuration */ -}; - - -ngx_module_t ngx_http_gzip_filter_module = { - NGX_MODULE, - &ngx_http_gzip_filter_module_ctx, /* module context */ - ngx_http_gzip_filter_commands, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - ngx_http_gzip_filter_init, /* init module */ - NULL /* init process */ -}; - - -static ngx_http_log_op_name_t ngx_http_gzip_log_fmt_ops[] = { - { ngx_string("gzip_ratio"), NGX_INT32_LEN + 3, - NULL, NULL, ngx_http_gzip_log_ratio }, - { ngx_null_string, 0, NULL, NULL, NULL } -}; - - - -static u_char gzheader[10] = { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 }; - -#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED) - -struct gztrailer { - uint32_t crc32; - uint32_t zlen; -}; - -#else /* NGX_HAVE_BIG_ENDIAN || !NGX_HAVE_NONALIGNED */ - -struct gztrailer { - u_char crc32[4]; - u_char zlen[4]; -}; - -#endif - - -static ngx_http_output_header_filter_pt ngx_http_next_header_filter; -static ngx_http_output_body_filter_pt ngx_http_next_body_filter; - - -static ngx_int_t -ngx_http_gzip_header_filter(ngx_http_request_t *r) -{ - ngx_uint_t i, found; - ngx_http_gzip_ctx_t *ctx; - ngx_http_gzip_conf_t *conf; - ngx_http_gzip_type_t *type; - - conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module); - - if (!conf->enable - || (r->headers_out.status != NGX_HTTP_OK - && r->headers_out.status != NGX_HTTP_FORBIDDEN - && r->headers_out.status != NGX_HTTP_NOT_FOUND) - || r->header_only - || r->http_version < conf->http_version - || r->headers_out.content_type == NULL - || (r->headers_out.content_encoding - && r->headers_out.content_encoding->value.len) - || r->headers_in.accept_encoding == NULL - || (r->headers_out.content_length_n != -1 - && r->headers_out.content_length_n < conf->min_length) - || ngx_strstr(r->headers_in.accept_encoding->value.data, "gzip") == NULL - ) - { - return ngx_http_next_header_filter(r); - } - - - found = 0; - type = conf->types->elts; - - for (i = 0; i < conf->types->nelts; i++) { - if (r->headers_out.content_type->value.len >= type[i].name.len - && ngx_strncasecmp(r->headers_out.content_type->value.data, - type[i].name.data, type[i].name.len) == 0) - { - found = 1; - break; - } - } - - if (!found) { - return ngx_http_next_header_filter(r); - } - - - if (r->headers_in.via) { - if (conf->proxied & NGX_HTTP_GZIP_PROXIED_OFF) { - return ngx_http_next_header_filter(r); - } - - if (!(conf->proxied & NGX_HTTP_GZIP_PROXIED_ANY) - && ngx_http_gzip_proxied(r, conf) == NGX_DECLINED) - { - return ngx_http_next_header_filter(r); - } - } - - - /* - * if the URL (without the "http://" prefix) is longer than 253 bytes - * then MSIE 4.x can not handle the compressed stream - it waits too long, - * hangs up or crashes - */ - - if (r->headers_in.msie4 && r->unparsed_uri.len > 200) { - return ngx_http_next_header_filter(r); - } - - - ngx_http_create_ctx(r, ctx, ngx_http_gzip_filter_module, - sizeof(ngx_http_gzip_ctx_t), NGX_ERROR); - ctx->request = r; - - r->headers_out.content_encoding = ngx_list_push(&r->headers_out.headers); - if (r->headers_out.content_encoding == NULL) { - return NGX_ERROR; - } - - r->headers_out.content_encoding->key.len = sizeof("Content-Encoding") - 1; - r->headers_out.content_encoding->key.data = (u_char *) "Content-Encoding"; - r->headers_out.content_encoding->value.len = sizeof("gzip") - 1; - r->headers_out.content_encoding->value.data = (u_char *) "gzip"; - - ctx->length = r->headers_out.content_length_n; - r->headers_out.content_length_n = -1; - if (r->headers_out.content_length) { - r->headers_out.content_length->key.len = 0; - r->headers_out.content_length = NULL; - } - r->filter_need_in_memory = 1; - - return ngx_http_next_header_filter(r); -} - - -static ngx_int_t -ngx_http_gzip_proxied(ngx_http_request_t *r, ngx_http_gzip_conf_t *conf) -{ - time_t date, expires; - - if (r->headers_in.authorization - && (conf->proxied & NGX_HTTP_GZIP_PROXIED_AUTH)) - { - return NGX_OK; - } - - if (r->headers_out.expires) { - - if (!(conf->proxied & NGX_HTTP_GZIP_PROXIED_EXPIRED)) { - return NGX_DECLINED; - } - - expires = ngx_http_parse_time(r->headers_out.expires->value.data, - r->headers_out.expires->value.len); - if (expires == NGX_ERROR) { - return NGX_DECLINED; - } - - if (r->headers_out.date) { - date = ngx_http_parse_time(r->headers_out.date->value.data, - r->headers_out.date->value.len); - if (date == NGX_ERROR) { - return NGX_DECLINED; - } - - } else { - date = ngx_time(); - } - - if (expires < date) { - return NGX_OK; - } - - return NGX_DECLINED; - } - - if (r->headers_out.cache_control) { - - if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_NO_CACHE) - && ngx_strstr(r->headers_out.cache_control->value.data, "no-cache")) - { - return NGX_OK; - } - - if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_NO_STORE) - && ngx_strstr(r->headers_out.cache_control->value.data, "no-store")) - { - return NGX_OK; - } - - if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_PRIVATE) - && ngx_strstr(r->headers_out.cache_control->value.data, "private")) - { - return NGX_OK; - } - - return NGX_DECLINED; - } - - if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_NO_LM) - && r->headers_out.last_modified) - { - return NGX_DECLINED; - } - - if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_NO_ETAG) - && r->headers_out.etag) - { - return NGX_DECLINED; - } - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in) -{ - int rc, wbits, memlevel; - ngx_int_t last; - struct gztrailer *trailer; - ngx_buf_t *b; - ngx_chain_t *cl; - ngx_http_gzip_ctx_t *ctx; - ngx_http_gzip_conf_t *conf; - - ctx = ngx_http_get_module_ctx(r, ngx_http_gzip_filter_module); - - if (ctx == NULL || ctx->done) { - return ngx_http_next_body_filter(r, in); - } - - conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module); - - if (ctx->preallocated == NULL) { - wbits = conf->wbits; - memlevel = conf->memlevel; - - if (ctx->length > 0) { - - /* the actual zlib window size is smaller by 262 bytes */ - - while (ctx->length < ((1 << (wbits - 1)) - 262)) { - wbits--; - memlevel--; - } - } - - /* - * We preallocate a memory for zlib in one buffer (200K-400K), this - * decreases a number of malloc() and free() calls and also probably - * decreases a number of syscalls (sbrk() and so on). - * Besides we free this memory as soon as the gzipping will complete - * and do not wait while a whole response will be sent to a client. - * - * 8K is for zlib deflate_state, it takes - * * 5816 bytes on x86 and sparc64 (32-bit mode) - * * 5920 bytes on amd64 and sparc64 - */ - - ctx->allocated = 8192 + (1 << (wbits + 2)) + (1 << (memlevel + 9)); - - if (!(ctx->preallocated = ngx_palloc(r->pool, ctx->allocated))) { - return NGX_ERROR; - } - - ctx->free_mem = ctx->preallocated; - - ctx->zstream.zalloc = ngx_http_gzip_filter_alloc; - ctx->zstream.zfree = ngx_http_gzip_filter_free; - ctx->zstream.opaque = ctx; - - rc = deflateInit2(&ctx->zstream, conf->level, Z_DEFLATED, - -wbits, memlevel, Z_DEFAULT_STRATEGY); - - if (rc != Z_OK) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - "deflateInit2() failed: %d", rc); - ngx_http_gzip_error(ctx); - return NGX_ERROR; - } - - if (!(b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)))) { - ngx_http_gzip_error(ctx); - return NGX_ERROR; - } - - b->memory = 1; - b->pos = gzheader; - b->last = b->pos + 10; - - if (!(cl = ngx_alloc_chain_link(r->pool))) { - ngx_http_gzip_error(ctx); - return NGX_ERROR; - } - cl->buf = b; - cl->next = NULL; - - /* - * We pass the gzheader to the next filter now to avoid its linking - * to the ctx->busy chain. zlib does not usually output the compressed - * data in the initial iterations, so the gzheader that was linked - * to the ctx->busy chain would be flushed by ngx_http_write_filter(). - */ - - if (ngx_http_next_body_filter(r, cl) == NGX_ERROR) { - ngx_http_gzip_error(ctx); - return NGX_ERROR; - } - - ctx->last_out = &ctx->out; - - ctx->crc32 = crc32(0L, Z_NULL, 0); - ctx->flush = Z_NO_FLUSH; - } - - if (in) { - if (ngx_chain_add_copy(r->pool, &ctx->in, in) == NGX_ERROR) { - ngx_http_gzip_error(ctx); - return NGX_ERROR; - } - } - - last = NGX_NONE; - - for ( ;; ) { - - for ( ;; ) { - - /* does zlib need a new data ? */ - - if (ctx->zstream.avail_in == 0 - && ctx->flush == Z_NO_FLUSH - && !ctx->redo) - { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "gzip in: %p", ctx->in); - - if (ctx->in == NULL) { - break; - } - - ctx->in_buf = ctx->in->buf; - ctx->in = ctx->in->next; - - ctx->zstream.next_in = ctx->in_buf->pos; - ctx->zstream.avail_in = ctx->in_buf->last - ctx->in_buf->pos; - - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "gzip in_buf:%p ni:%p ai:%ud", - ctx->in_buf, - ctx->zstream.next_in, ctx->zstream.avail_in); - - /* STUB */ - if (ctx->in_buf->last < ctx->in_buf->pos) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - "zstream.avail_in is huge"); - ctx->done = 1; - return NGX_ERROR; - } - /**/ - - if (ctx->in_buf->last_buf) { - ctx->flush = Z_FINISH; - - } else if (ctx->in_buf->flush) { - ctx->flush = Z_SYNC_FLUSH; - } - - if (ctx->zstream.avail_in == 0) { - if (ctx->flush == Z_NO_FLUSH) { - continue; - } - - } else { - ctx->crc32 = crc32(ctx->crc32, ctx->zstream.next_in, - ctx->zstream.avail_in); - } - } - - - /* is there a space for the gzipped data ? */ - - if (ctx->zstream.avail_out == 0) { - - if (ctx->free) { - ctx->out_buf = ctx->free->buf; - ctx->free = ctx->free->next; - - } else if (ctx->bufs < conf->bufs.num) { - ctx->out_buf = ngx_create_temp_buf(r->pool, - conf->bufs.size); - if (ctx->out_buf == NULL) { - ngx_http_gzip_error(ctx); - return NGX_ERROR; - } - - ctx->out_buf->tag = (ngx_buf_tag_t) - &ngx_http_gzip_filter_module; - ctx->out_buf->recycled = 1; - ctx->bufs++; - - } else { - break; - } - - ctx->zstream.next_out = ctx->out_buf->pos; - ctx->zstream.avail_out = conf->bufs.size; - } - - ngx_log_debug6(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "deflate in: ni:%p no:%p ai:%ud ao:%ud fl:%d redo:%d", - ctx->zstream.next_in, ctx->zstream.next_out, - ctx->zstream.avail_in, ctx->zstream.avail_out, - ctx->flush, ctx->redo); - - rc = deflate(&ctx->zstream, ctx->flush); - - if (rc != Z_OK && rc != Z_STREAM_END) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - "deflate() failed: %d, %d", ctx->flush, rc); - ngx_http_gzip_error(ctx); - return NGX_ERROR; - } - - ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "deflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d", - ctx->zstream.next_in, ctx->zstream.next_out, - ctx->zstream.avail_in, ctx->zstream.avail_out, - rc); - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "gzip in_buf:%p pos:%p", - ctx->in_buf, ctx->in_buf->pos); - - - if (ctx->zstream.next_in) { - ctx->in_buf->pos = ctx->zstream.next_in; - - if (ctx->zstream.avail_in == 0) { - ctx->zstream.next_in = NULL; - } - } - - ctx->out_buf->last = ctx->zstream.next_out; - - if (ctx->zstream.avail_out == 0) { - - /* zlib wants to output some more gzipped data */ - - if (!(cl = ngx_alloc_chain_link(r->pool))) { - ngx_http_gzip_error(ctx); - return NGX_ERROR; - } - cl->buf = ctx->out_buf; - cl->next = NULL; - *ctx->last_out = cl; - ctx->last_out = &cl->next; - - ctx->redo = 1; - - continue; - } - - ctx->redo = 0; - - if (ctx->flush == Z_SYNC_FLUSH) { - - ctx->out_buf->flush = 0; - ctx->flush = Z_NO_FLUSH; - - if (!(cl = ngx_alloc_chain_link(r->pool))) { - ngx_http_gzip_error(ctx); - return NGX_ERROR; - } - cl->buf = ctx->out_buf; - cl->next = NULL; - *ctx->last_out = cl; - ctx->last_out = &cl->next; - - break; - } - - if (rc == Z_STREAM_END) { - - ctx->zin = ctx->zstream.total_in; - ctx->zout = 10 + ctx->zstream.total_out + 8; - - rc = deflateEnd(&ctx->zstream); - - if (rc != Z_OK) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - "deflateEnd() failed: %d", rc); - ngx_http_gzip_error(ctx); - return NGX_ERROR; - } - - ngx_pfree(r->pool, ctx->preallocated); - - if (!(cl = ngx_alloc_chain_link(r->pool))) { - ngx_http_gzip_error(ctx); - return NGX_ERROR; - } - cl->buf = ctx->out_buf; - cl->next = NULL; - *ctx->last_out = cl; - ctx->last_out = &cl->next; - - if (ctx->zstream.avail_out >= 8) { - trailer = (struct gztrailer *) ctx->out_buf->last; - ctx->out_buf->last += 8; - ctx->out_buf->last_buf = 1; - - } else { - if (!(b = ngx_create_temp_buf(r->pool, 8))) { - ngx_http_gzip_error(ctx); - return NGX_ERROR; - } - - b->last_buf = 1; - - if (!(cl = ngx_alloc_chain_link(r->pool))) { - ngx_http_gzip_error(ctx); - return NGX_ERROR; - } - cl->buf = b; - cl->next = NULL; - *ctx->last_out = cl; - ctx->last_out = &cl->next; - trailer = (struct gztrailer *) b->pos; - b->last += 8; - } - -#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED) - - trailer->crc32 = ctx->crc32; - trailer->zlen = ctx->zin; - -#else - trailer->crc32[0] = (u_char) (ctx->crc32 & 0xff); - trailer->crc32[1] = (u_char) ((ctx->crc32 >> 8) & 0xff); - trailer->crc32[2] = (u_char) ((ctx->crc32 >> 16) & 0xff); - trailer->crc32[3] = (u_char) ((ctx->crc32 >> 24) & 0xff); - - trailer->zlen[0] = (u_char) (ctx->zin & 0xff); - trailer->zlen[1] = (u_char) ((ctx->zin >> 8) & 0xff); - trailer->zlen[2] = (u_char) ((ctx->zin >> 16) & 0xff); - trailer->zlen[3] = (u_char) ((ctx->zin >> 24) & 0xff); -#endif - - ctx->zstream.avail_in = 0; - ctx->zstream.avail_out = 0; - - ctx->done = 1; - - break; - } - - if (conf->no_buffer && ctx->in == NULL) { - if (!(cl = ngx_alloc_chain_link(r->pool))) { - ngx_http_gzip_error(ctx); - return NGX_ERROR; - } - cl->buf = ctx->out_buf; - cl->next = NULL; - *ctx->last_out = cl; - ctx->last_out = &cl->next; - - break; - } - } - - if (last == NGX_AGAIN && !ctx->done) { - return NGX_AGAIN; - } - - if (ctx->out == NULL && ctx->busy == NULL) { - return NGX_OK; - } - - last = ngx_http_next_body_filter(r, ctx->out); - - /* - * we do not check NGX_AGAIN here because the downstream filters - * may free some buffers and zlib may compress some data into them - */ - - if (last == NGX_ERROR) { - ngx_http_gzip_error(ctx); - return NGX_ERROR; - } - - ngx_chain_update_chains(&ctx->free, &ctx->busy, &ctx->out, - (ngx_buf_tag_t) &ngx_http_gzip_filter_module); - ctx->last_out = &ctx->out; - - if (ctx->done) { - return last; - } - } -} - - -static void * -ngx_http_gzip_filter_alloc(void *opaque, u_int items, u_int size) -{ - ngx_http_gzip_ctx_t *ctx = opaque; - - void *p; - ngx_uint_t alloc; - - alloc = items * size; - - if (alloc % 512 != 0) { - - /* - * The zlib deflate_state allocation, it takes about 6K, - * we allocate 8K. Other allocations are divisible by 512. - */ - - alloc = (alloc + ngx_pagesize - 1) & ~(ngx_pagesize - 1); - } - - if (alloc <= ctx->allocated) { - p = ctx->free_mem; - ctx->free_mem += alloc; - ctx->allocated -= alloc; - - ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ctx->request->connection->log, 0, - "gzip alloc: n:%ud s:%ud a:%ud p:%p", - items, size, alloc, p); - - return p; - } - - ngx_log_error(NGX_LOG_ALERT, ctx->request->connection->log, 0, - "gzip filter failed to use preallocated memory: %ud of %ud", - items * size, ctx->allocated); - - p = ngx_palloc(ctx->request->pool, items * size); - - return p; -} - - -static void -ngx_http_gzip_filter_free(void *opaque, void *address) -{ -#if 0 - ngx_http_gzip_ctx_t *ctx = opaque; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->request->connection->log, 0, - "gzip free: %p", address); -#endif -} - - -static u_char * -ngx_http_gzip_log_ratio(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op) -{ - ngx_uint_t zint, zfrac; - ngx_http_gzip_ctx_t *ctx; - - ctx = ngx_http_get_module_ctx(r, ngx_http_gzip_filter_module); - - if (ctx == NULL || ctx->zout == 0) { - *buf = '-'; - return buf + 1; - } - - zint = (ngx_uint_t) (ctx->zin / ctx->zout); - zfrac = (ngx_uint_t) ((ctx->zin * 100 / ctx->zout) % 100); - - if ((ctx->zin * 1000 / ctx->zout) % 10 > 4) { - - /* the rounding, e.g., 2.125 to 2.13 */ - - zfrac++; - - if (zfrac > 99) { - zint++; - zfrac = 0; - } - } - - return ngx_sprintf(buf, "%ui.%02ui", zint, zfrac); -} - - -static void -ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx) -{ - deflateEnd(&ctx->zstream); - - if (ctx->preallocated) { - ngx_pfree(ctx->request->pool, ctx->preallocated); - } - - ctx->zstream.avail_in = 0; - ctx->zstream.avail_out = 0; - - ctx->done = 1; - - return; -} - - -static ngx_int_t -ngx_http_gzip_add_log_formats(ngx_conf_t *cf) -{ - ngx_http_log_op_name_t *op; - - for (op = ngx_http_gzip_log_fmt_ops; op->name.len; op++) { /* void */ } - op->run = NULL; - - for (op = ngx_http_log_fmt_ops; op->run; op++) { - if (op->name.len == 0) { - op = (ngx_http_log_op_name_t *) op->run; - } - } - - op->run = (ngx_http_log_op_run_pt) ngx_http_gzip_log_fmt_ops; - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_gzip_filter_init(ngx_cycle_t *cycle) -{ - ngx_http_next_header_filter = ngx_http_top_header_filter; - ngx_http_top_header_filter = ngx_http_gzip_header_filter; - - ngx_http_next_body_filter = ngx_http_top_body_filter; - ngx_http_top_body_filter = ngx_http_gzip_body_filter; - - return NGX_OK; -} - - -static void * -ngx_http_gzip_create_conf(ngx_conf_t *cf) -{ - ngx_http_gzip_conf_t *conf; - - if (!(conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_gzip_conf_t)))) { - return NGX_CONF_ERROR; - } - - /* - * set by ngx_pcalloc(): - * - * conf->bufs.num = 0; - * conf->proxied = 0; - * conf->types = NULL; - */ - - conf->enable = NGX_CONF_UNSET; - conf->no_buffer = NGX_CONF_UNSET; - - conf->http_version = NGX_CONF_UNSET_UINT; - - conf->level = NGX_CONF_UNSET; - conf->wbits = (size_t) NGX_CONF_UNSET; - conf->memlevel = (size_t) NGX_CONF_UNSET; - conf->min_length = NGX_CONF_UNSET; - - return conf; -} - - -static char * -ngx_http_gzip_merge_conf(ngx_conf_t *cf, void *parent, void *child) -{ - ngx_http_gzip_conf_t *prev = parent; - ngx_http_gzip_conf_t *conf = child; - - ngx_http_gzip_type_t *type; - - ngx_conf_merge_value(conf->enable, prev->enable, 0); - - ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, 4, ngx_pagesize); - - ngx_conf_merge_unsigned_value(conf->http_version, prev->http_version, - NGX_HTTP_VERSION_11); - ngx_conf_merge_bitmask_value(conf->proxied, prev->proxied, - (NGX_CONF_BITMASK_SET|NGX_HTTP_GZIP_PROXIED_OFF)); - - 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, 0); - ngx_conf_merge_value(conf->no_buffer, prev->no_buffer, 0); - - if (conf->types == NULL) { - if (prev->types == NULL) { - conf->types = ngx_array_create(cf->pool, 1, - sizeof(ngx_http_gzip_type_t)); - if (conf->types == NULL) { - return NGX_CONF_ERROR; - } - - if (!(type = ngx_array_push(conf->types))) { - return NGX_CONF_ERROR; - } - - type->name.len = sizeof("text/html") - 1; - type->name.data = (u_char *) "text/html"; - type->enable = 1; - - } else { - conf->types = prev->types; - } - } - - return NGX_CONF_OK; -} - - -static char * -ngx_http_gzip_set_types(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_http_gzip_conf_t *gcf = conf; - - ngx_str_t *value; - ngx_uint_t i; - ngx_http_gzip_type_t *type; - - if (gcf->types == NULL) { - gcf->types = ngx_array_create(cf->pool, 4, - sizeof(ngx_http_gzip_type_t)); - if (gcf->types == NULL) { - return NGX_CONF_ERROR; - } - - if (!(type = ngx_array_push(gcf->types))) { - return NGX_CONF_ERROR; - } - - type->name.len = sizeof("text/html") - 1; - type->name.data = (u_char *) "text/html"; - type->enable = 1; - } - - value = cf->args->elts; - - for (i = 1; i < cf->args->nelts; i++) { - - if (ngx_strcmp(value[i].data, "text/html") == 0) { - continue; - } - - if (!(type = ngx_array_push(gcf->types))) { - return NGX_CONF_ERROR; - } - - type->name.len = value[i].len; - - if (!(type->name.data = ngx_palloc(cf->pool, type->name.len + 1))) { - return NGX_CONF_ERROR; - } - - ngx_cpystrn(type->name.data, value[i].data, type->name.len + 1); - } - - return NGX_CONF_OK; -} - - -static char * -ngx_http_gzip_set_window(ngx_conf_t *cf, void *post, void *data) -{ - int *np = data; - - int wbits, wsize; - - wbits = 15; - - for (wsize = 32 * 1024; wsize > 256; wsize >>= 1) { - - if (wsize == *np) { - *np = wbits; - - return NGX_CONF_OK; - } - - wbits--; - } - - return "must be 512, 1k, 2k, 4k, 8k, 16k, or 32k"; -} - - -static char * -ngx_http_gzip_set_hash(ngx_conf_t *cf, void *post, void *data) -{ - int *np = data; - - int memlevel, hsize; - - memlevel = 9; - - for (hsize = 128 * 1024; hsize > 256; hsize >>= 1) { - - if (hsize == *np) { - *np = memlevel; - - return NGX_CONF_OK; - } - - memlevel--; - } - - return "must be 512, 1k, 2k, 4k, 8k, 16k, 32k, 64k, or 128k"; -} diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_gzip_filter_module.c @@ -0,0 +1,1162 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + +#include + + +typedef struct { + ngx_flag_t enable; + ngx_flag_t no_buffer; + + ngx_array_t *types; /* array of ngx_http_gzip_type_t */ + + ngx_bufs_t bufs; + + ngx_uint_t http_version; + ngx_uint_t proxied; + + int level; + size_t wbits; + size_t memlevel; + ssize_t min_length; +} ngx_http_gzip_conf_t; + + +typedef struct { + ngx_str_t name; + ngx_uint_t enable; +} ngx_http_gzip_type_t; + + +#define NGX_HTTP_GZIP_PROXIED_OFF 0x0002 +#define NGX_HTTP_GZIP_PROXIED_EXPIRED 0x0004 +#define NGX_HTTP_GZIP_PROXIED_NO_CACHE 0x0008 +#define NGX_HTTP_GZIP_PROXIED_NO_STORE 0x0010 +#define NGX_HTTP_GZIP_PROXIED_PRIVATE 0x0020 +#define NGX_HTTP_GZIP_PROXIED_NO_LM 0x0040 +#define NGX_HTTP_GZIP_PROXIED_NO_ETAG 0x0080 +#define NGX_HTTP_GZIP_PROXIED_AUTH 0x0100 +#define NGX_HTTP_GZIP_PROXIED_ANY 0x0200 + + +typedef struct { + ngx_chain_t *in; + ngx_chain_t *free; + ngx_chain_t *busy; + ngx_chain_t *out; + ngx_chain_t **last_out; + ngx_buf_t *in_buf; + ngx_buf_t *out_buf; + ngx_int_t bufs; + + off_t length; + + void *preallocated; + char *free_mem; + ngx_uint_t allocated; + + unsigned flush:4; + unsigned redo:1; + unsigned done:1; + + size_t zin; + size_t zout; + + uint32_t crc32; + z_stream zstream; + ngx_http_request_t *request; +} ngx_http_gzip_ctx_t; + + +static ngx_int_t ngx_http_gzip_proxied(ngx_http_request_t *r, + ngx_http_gzip_conf_t *conf); +static void *ngx_http_gzip_filter_alloc(void *opaque, u_int items, + u_int size); +static void ngx_http_gzip_filter_free(void *opaque, void *address); +static void ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx); + +static u_char *ngx_http_gzip_log_ratio(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op); + +static ngx_int_t ngx_http_gzip_add_log_formats(ngx_conf_t *cf); + +static ngx_int_t ngx_http_gzip_filter_init(ngx_cycle_t *cycle); +static void *ngx_http_gzip_create_conf(ngx_conf_t *cf); +static char *ngx_http_gzip_merge_conf(ngx_conf_t *cf, + void *parent, void *child); +static char *ngx_http_gzip_set_types(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_http_gzip_set_window(ngx_conf_t *cf, void *post, void *data); +static char *ngx_http_gzip_set_hash(ngx_conf_t *cf, void *post, void *data); + + +static ngx_conf_num_bounds_t ngx_http_gzip_comp_level_bounds = { + ngx_conf_check_num_bounds, 1, 9 +}; + +static ngx_conf_post_handler_pt ngx_http_gzip_set_window_p = + ngx_http_gzip_set_window; +static ngx_conf_post_handler_pt ngx_http_gzip_set_hash_p = + ngx_http_gzip_set_hash; + + + +static ngx_conf_enum_t ngx_http_gzip_http_version[] = { + { ngx_string("1.0"), NGX_HTTP_VERSION_10 }, + { ngx_string("1.1"), NGX_HTTP_VERSION_11 }, + { ngx_null_string, 0 } +}; + + +static ngx_conf_bitmask_t ngx_http_gzip_proxied_mask[] = { + { ngx_string("off"), NGX_HTTP_GZIP_PROXIED_OFF }, + { ngx_string("expired"), NGX_HTTP_GZIP_PROXIED_EXPIRED }, + { ngx_string("no-cache"), NGX_HTTP_GZIP_PROXIED_NO_CACHE }, + { ngx_string("no-store"), NGX_HTTP_GZIP_PROXIED_NO_STORE }, + { ngx_string("private"), NGX_HTTP_GZIP_PROXIED_PRIVATE }, + { ngx_string("no_last_modified"), NGX_HTTP_GZIP_PROXIED_NO_LM }, + { ngx_string("no_etag"), NGX_HTTP_GZIP_PROXIED_NO_ETAG }, + { ngx_string("auth"), NGX_HTTP_GZIP_PROXIED_AUTH }, + { ngx_string("any"), NGX_HTTP_GZIP_PROXIED_ANY }, + { ngx_null_string, 0 } +}; + + +static ngx_command_t ngx_http_gzip_filter_commands[] = { + + { ngx_string("gzip"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_gzip_conf_t, enable), + NULL }, + + { ngx_string("gzip_buffers"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, + ngx_conf_set_bufs_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_gzip_conf_t, bufs), + NULL }, + + { ngx_string("gzip_types"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_http_gzip_set_types, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("gzip_comp_level"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_gzip_conf_t, level), + &ngx_http_gzip_comp_level_bounds }, + + { ngx_string("gzip_window"), + 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, wbits), + &ngx_http_gzip_set_window_p }, + + { ngx_string("gzip_hash"), + 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, memlevel), + &ngx_http_gzip_set_hash_p }, + + { ngx_string("gzip_no_buffer"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_gzip_conf_t, no_buffer), + NULL }, + + { ngx_string("gzip_http_version"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY, + ngx_conf_set_enum_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_gzip_conf_t, http_version), + &ngx_http_gzip_http_version }, + + { ngx_string("gzip_proxied"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY, + ngx_conf_set_bitmask_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_gzip_conf_t, proxied), + &ngx_http_gzip_proxied_mask }, + + { ngx_string("gzip_min_length"), + 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, min_length), + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_gzip_filter_module_ctx = { + ngx_http_gzip_add_log_formats, /* pre conf */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_gzip_create_conf, /* create location configuration */ + ngx_http_gzip_merge_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_gzip_filter_module = { + NGX_MODULE, + &ngx_http_gzip_filter_module_ctx, /* module context */ + ngx_http_gzip_filter_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + ngx_http_gzip_filter_init, /* init module */ + NULL /* init process */ +}; + + +static ngx_http_log_op_name_t ngx_http_gzip_log_fmt_ops[] = { + { ngx_string("gzip_ratio"), NGX_INT32_LEN + 3, + NULL, NULL, ngx_http_gzip_log_ratio }, + { ngx_null_string, 0, NULL, NULL, NULL } +}; + + + +static u_char gzheader[10] = { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 }; + +#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED) + +struct gztrailer { + uint32_t crc32; + uint32_t zlen; +}; + +#else /* NGX_HAVE_BIG_ENDIAN || !NGX_HAVE_NONALIGNED */ + +struct gztrailer { + u_char crc32[4]; + u_char zlen[4]; +}; + +#endif + + +static ngx_http_output_header_filter_pt ngx_http_next_header_filter; +static ngx_http_output_body_filter_pt ngx_http_next_body_filter; + + +static ngx_int_t +ngx_http_gzip_header_filter(ngx_http_request_t *r) +{ + ngx_uint_t i, found; + ngx_http_gzip_ctx_t *ctx; + ngx_http_gzip_conf_t *conf; + ngx_http_gzip_type_t *type; + + conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module); + + if (!conf->enable + || (r->headers_out.status != NGX_HTTP_OK + && r->headers_out.status != NGX_HTTP_FORBIDDEN + && r->headers_out.status != NGX_HTTP_NOT_FOUND) + || r->header_only + || r->http_version < conf->http_version + || r->headers_out.content_type == NULL + || (r->headers_out.content_encoding + && r->headers_out.content_encoding->value.len) + || r->headers_in.accept_encoding == NULL + || (r->headers_out.content_length_n != -1 + && r->headers_out.content_length_n < conf->min_length) + || ngx_strstr(r->headers_in.accept_encoding->value.data, "gzip") == NULL + ) + { + return ngx_http_next_header_filter(r); + } + + + found = 0; + type = conf->types->elts; + + for (i = 0; i < conf->types->nelts; i++) { + if (r->headers_out.content_type->value.len >= type[i].name.len + && ngx_strncasecmp(r->headers_out.content_type->value.data, + type[i].name.data, type[i].name.len) == 0) + { + found = 1; + break; + } + } + + if (!found) { + return ngx_http_next_header_filter(r); + } + + + if (r->headers_in.via) { + if (conf->proxied & NGX_HTTP_GZIP_PROXIED_OFF) { + return ngx_http_next_header_filter(r); + } + + if (!(conf->proxied & NGX_HTTP_GZIP_PROXIED_ANY) + && ngx_http_gzip_proxied(r, conf) == NGX_DECLINED) + { + return ngx_http_next_header_filter(r); + } + } + + + /* + * if the URL (without the "http://" prefix) is longer than 253 bytes + * then MSIE 4.x can not handle the compressed stream - it waits too long, + * hangs up or crashes + */ + + if (r->headers_in.msie4 && r->unparsed_uri.len > 200) { + return ngx_http_next_header_filter(r); + } + + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_gzip_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_http_set_ctx(r, ctx, ngx_http_gzip_filter_module); + + + ctx->request = r; + + r->headers_out.content_encoding = ngx_list_push(&r->headers_out.headers); + if (r->headers_out.content_encoding == NULL) { + return NGX_ERROR; + } + + r->headers_out.content_encoding->key.len = sizeof("Content-Encoding") - 1; + r->headers_out.content_encoding->key.data = (u_char *) "Content-Encoding"; + r->headers_out.content_encoding->value.len = sizeof("gzip") - 1; + r->headers_out.content_encoding->value.data = (u_char *) "gzip"; + + ctx->length = r->headers_out.content_length_n; + r->headers_out.content_length_n = -1; + if (r->headers_out.content_length) { + r->headers_out.content_length->key.len = 0; + r->headers_out.content_length = NULL; + } + r->filter_need_in_memory = 1; + + return ngx_http_next_header_filter(r); +} + + +static ngx_int_t +ngx_http_gzip_proxied(ngx_http_request_t *r, ngx_http_gzip_conf_t *conf) +{ + time_t date, expires; + + if (r->headers_in.authorization + && (conf->proxied & NGX_HTTP_GZIP_PROXIED_AUTH)) + { + return NGX_OK; + } + + if (r->headers_out.expires) { + + if (!(conf->proxied & NGX_HTTP_GZIP_PROXIED_EXPIRED)) { + return NGX_DECLINED; + } + + expires = ngx_http_parse_time(r->headers_out.expires->value.data, + r->headers_out.expires->value.len); + if (expires == NGX_ERROR) { + return NGX_DECLINED; + } + + if (r->headers_out.date) { + date = ngx_http_parse_time(r->headers_out.date->value.data, + r->headers_out.date->value.len); + if (date == NGX_ERROR) { + return NGX_DECLINED; + } + + } else { + date = ngx_time(); + } + + if (expires < date) { + return NGX_OK; + } + + return NGX_DECLINED; + } + + if (r->headers_out.cache_control) { + + if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_NO_CACHE) + && ngx_strstr(r->headers_out.cache_control->value.data, "no-cache")) + { + return NGX_OK; + } + + if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_NO_STORE) + && ngx_strstr(r->headers_out.cache_control->value.data, "no-store")) + { + return NGX_OK; + } + + if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_PRIVATE) + && ngx_strstr(r->headers_out.cache_control->value.data, "private")) + { + return NGX_OK; + } + + return NGX_DECLINED; + } + + if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_NO_LM) + && r->headers_out.last_modified) + { + return NGX_DECLINED; + } + + if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_NO_ETAG) + && r->headers_out.etag) + { + return NGX_DECLINED; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in) +{ + int rc, wbits, memlevel; + ngx_int_t last; + struct gztrailer *trailer; + ngx_buf_t *b; + ngx_chain_t *cl, out; + ngx_http_gzip_ctx_t *ctx; + ngx_http_gzip_conf_t *conf; + + ctx = ngx_http_get_module_ctx(r, ngx_http_gzip_filter_module); + + if (ctx == NULL || ctx->done) { + return ngx_http_next_body_filter(r, in); + } + + conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module); + + if (ctx->preallocated == NULL) { + wbits = conf->wbits; + memlevel = conf->memlevel; + + if (ctx->length > 0) { + + /* the actual zlib window size is smaller by 262 bytes */ + + while (ctx->length < ((1 << (wbits - 1)) - 262)) { + wbits--; + memlevel--; + } + } + + /* + * We preallocate a memory for zlib in one buffer (200K-400K), this + * decreases a number of malloc() and free() calls and also probably + * decreases a number of syscalls (sbrk() and so on). + * Besides we free this memory as soon as the gzipping will complete + * and do not wait while a whole response will be sent to a client. + * + * 8K is for zlib deflate_state, it takes + * * 5816 bytes on x86 and sparc64 (32-bit mode) + * * 5920 bytes on amd64 and sparc64 + */ + + ctx->allocated = 8192 + (1 << (wbits + 2)) + (1 << (memlevel + 9)); + + ctx->preallocated = ngx_palloc(r->pool, ctx->allocated); + if (ctx->preallocated == NULL) { + return NGX_ERROR; + } + + ctx->free_mem = ctx->preallocated; + + ctx->zstream.zalloc = ngx_http_gzip_filter_alloc; + ctx->zstream.zfree = ngx_http_gzip_filter_free; + ctx->zstream.opaque = ctx; + + rc = deflateInit2(&ctx->zstream, conf->level, Z_DEFLATED, + -wbits, memlevel, Z_DEFAULT_STRATEGY); + + if (rc != Z_OK) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "deflateInit2() failed: %d", rc); + ngx_http_gzip_error(ctx); + return NGX_ERROR; + } + + b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); + if (b == NULL) { + ngx_http_gzip_error(ctx); + return NGX_ERROR; + } + + b->memory = 1; + b->pos = gzheader; + b->last = b->pos + 10; + + out.buf = b; + out.next = NULL; + + /* + * We pass the gzheader to the next filter now to avoid its linking + * to the ctx->busy chain. zlib does not usually output the compressed + * data in the initial iterations, so the gzheader that was linked + * to the ctx->busy chain would be flushed by ngx_http_write_filter(). + */ + + if (ngx_http_next_body_filter(r, &out) == NGX_ERROR) { + ngx_http_gzip_error(ctx); + return NGX_ERROR; + } + + ctx->last_out = &ctx->out; + + ctx->crc32 = crc32(0L, Z_NULL, 0); + ctx->flush = Z_NO_FLUSH; + } + + if (in) { + if (ngx_chain_add_copy(r->pool, &ctx->in, in) == NGX_ERROR) { + ngx_http_gzip_error(ctx); + return NGX_ERROR; + } + } + + last = NGX_NONE; + + for ( ;; ) { + + for ( ;; ) { + + /* does zlib need a new data ? */ + + if (ctx->zstream.avail_in == 0 + && ctx->flush == Z_NO_FLUSH + && !ctx->redo) + { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "gzip in: %p", ctx->in); + + if (ctx->in == NULL) { + break; + } + + ctx->in_buf = ctx->in->buf; + ctx->in = ctx->in->next; + + ctx->zstream.next_in = ctx->in_buf->pos; + ctx->zstream.avail_in = ctx->in_buf->last - ctx->in_buf->pos; + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "gzip in_buf:%p ni:%p ai:%ud", + ctx->in_buf, + ctx->zstream.next_in, ctx->zstream.avail_in); + + /* STUB */ + if (ctx->in_buf->last < ctx->in_buf->pos) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "zstream.avail_in is huge"); + ctx->done = 1; + return NGX_ERROR; + } + /**/ + + if (ctx->in_buf->last_buf) { + ctx->flush = Z_FINISH; + + } else if (ctx->in_buf->flush) { + ctx->flush = Z_SYNC_FLUSH; + } + + if (ctx->zstream.avail_in == 0) { + if (ctx->flush == Z_NO_FLUSH) { + continue; + } + + } else { + ctx->crc32 = crc32(ctx->crc32, ctx->zstream.next_in, + ctx->zstream.avail_in); + } + } + + + /* is there a space for the gzipped data ? */ + + if (ctx->zstream.avail_out == 0) { + + if (ctx->free) { + ctx->out_buf = ctx->free->buf; + ctx->free = ctx->free->next; + + } else if (ctx->bufs < conf->bufs.num) { + ctx->out_buf = ngx_create_temp_buf(r->pool, + conf->bufs.size); + if (ctx->out_buf == NULL) { + ngx_http_gzip_error(ctx); + return NGX_ERROR; + } + + ctx->out_buf->tag = (ngx_buf_tag_t) + &ngx_http_gzip_filter_module; + ctx->out_buf->recycled = 1; + ctx->bufs++; + + } else { + break; + } + + ctx->zstream.next_out = ctx->out_buf->pos; + ctx->zstream.avail_out = conf->bufs.size; + } + + ngx_log_debug6(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "deflate in: ni:%p no:%p ai:%ud ao:%ud fl:%d redo:%d", + ctx->zstream.next_in, ctx->zstream.next_out, + ctx->zstream.avail_in, ctx->zstream.avail_out, + ctx->flush, ctx->redo); + + rc = deflate(&ctx->zstream, ctx->flush); + + if (rc != Z_OK && rc != Z_STREAM_END) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "deflate() failed: %d, %d", ctx->flush, rc); + ngx_http_gzip_error(ctx); + return NGX_ERROR; + } + + ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "deflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d", + ctx->zstream.next_in, ctx->zstream.next_out, + ctx->zstream.avail_in, ctx->zstream.avail_out, + rc); + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "gzip in_buf:%p pos:%p", + ctx->in_buf, ctx->in_buf->pos); + + + if (ctx->zstream.next_in) { + ctx->in_buf->pos = ctx->zstream.next_in; + + if (ctx->zstream.avail_in == 0) { + ctx->zstream.next_in = NULL; + } + } + + ctx->out_buf->last = ctx->zstream.next_out; + + if (ctx->zstream.avail_out == 0) { + + /* zlib wants to output some more gzipped data */ + + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { + ngx_http_gzip_error(ctx); + return NGX_ERROR; + } + + cl->buf = ctx->out_buf; + cl->next = NULL; + *ctx->last_out = cl; + ctx->last_out = &cl->next; + + ctx->redo = 1; + + continue; + } + + ctx->redo = 0; + + if (ctx->flush == Z_SYNC_FLUSH) { + + ctx->out_buf->flush = 0; + ctx->flush = Z_NO_FLUSH; + + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { + ngx_http_gzip_error(ctx); + return NGX_ERROR; + } + + cl->buf = ctx->out_buf; + cl->next = NULL; + *ctx->last_out = cl; + ctx->last_out = &cl->next; + + break; + } + + if (rc == Z_STREAM_END) { + + ctx->zin = ctx->zstream.total_in; + ctx->zout = 10 + ctx->zstream.total_out + 8; + + rc = deflateEnd(&ctx->zstream); + + if (rc != Z_OK) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "deflateEnd() failed: %d", rc); + ngx_http_gzip_error(ctx); + return NGX_ERROR; + } + + ngx_pfree(r->pool, ctx->preallocated); + + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { + ngx_http_gzip_error(ctx); + return NGX_ERROR; + } + + cl->buf = ctx->out_buf; + cl->next = NULL; + *ctx->last_out = cl; + ctx->last_out = &cl->next; + + if (ctx->zstream.avail_out >= 8) { + trailer = (struct gztrailer *) ctx->out_buf->last; + ctx->out_buf->last += 8; + ctx->out_buf->last_buf = 1; + + } else { + b = ngx_create_temp_buf(r->pool, 8); + if (b == NULL) { + ngx_http_gzip_error(ctx); + return NGX_ERROR; + } + + b->last_buf = 1; + + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { + ngx_http_gzip_error(ctx); + return NGX_ERROR; + } + + cl->buf = b; + cl->next = NULL; + *ctx->last_out = cl; + ctx->last_out = &cl->next; + trailer = (struct gztrailer *) b->pos; + b->last += 8; + } + +#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED) + + trailer->crc32 = ctx->crc32; + trailer->zlen = ctx->zin; + +#else + trailer->crc32[0] = (u_char) (ctx->crc32 & 0xff); + trailer->crc32[1] = (u_char) ((ctx->crc32 >> 8) & 0xff); + trailer->crc32[2] = (u_char) ((ctx->crc32 >> 16) & 0xff); + trailer->crc32[3] = (u_char) ((ctx->crc32 >> 24) & 0xff); + + trailer->zlen[0] = (u_char) (ctx->zin & 0xff); + trailer->zlen[1] = (u_char) ((ctx->zin >> 8) & 0xff); + trailer->zlen[2] = (u_char) ((ctx->zin >> 16) & 0xff); + trailer->zlen[3] = (u_char) ((ctx->zin >> 24) & 0xff); +#endif + + ctx->zstream.avail_in = 0; + ctx->zstream.avail_out = 0; + + ctx->done = 1; + + break; + } + + if (conf->no_buffer && ctx->in == NULL) { + + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { + ngx_http_gzip_error(ctx); + return NGX_ERROR; + } + + cl->buf = ctx->out_buf; + cl->next = NULL; + *ctx->last_out = cl; + ctx->last_out = &cl->next; + + break; + } + } + + if (last == NGX_AGAIN && !ctx->done) { + return NGX_AGAIN; + } + + if (ctx->out == NULL && ctx->busy == NULL) { + return NGX_OK; + } + + last = ngx_http_next_body_filter(r, ctx->out); + + /* + * we do not check NGX_AGAIN here because the downstream filters + * may free some buffers and zlib may compress some data into them + */ + + if (last == NGX_ERROR) { + ngx_http_gzip_error(ctx); + return NGX_ERROR; + } + + ngx_chain_update_chains(&ctx->free, &ctx->busy, &ctx->out, + (ngx_buf_tag_t) &ngx_http_gzip_filter_module); + ctx->last_out = &ctx->out; + + if (ctx->done) { + return last; + } + } +} + + +static void * +ngx_http_gzip_filter_alloc(void *opaque, u_int items, u_int size) +{ + ngx_http_gzip_ctx_t *ctx = opaque; + + void *p; + ngx_uint_t alloc; + + alloc = items * size; + + if (alloc % 512 != 0) { + + /* + * The zlib deflate_state allocation, it takes about 6K, + * we allocate 8K. Other allocations are divisible by 512. + */ + + alloc = (alloc + ngx_pagesize - 1) & ~(ngx_pagesize - 1); + } + + if (alloc <= ctx->allocated) { + p = ctx->free_mem; + ctx->free_mem += alloc; + ctx->allocated -= alloc; + + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ctx->request->connection->log, 0, + "gzip alloc: n:%ud s:%ud a:%ud p:%p", + items, size, alloc, p); + + return p; + } + + ngx_log_error(NGX_LOG_ALERT, ctx->request->connection->log, 0, + "gzip filter failed to use preallocated memory: %ud of %ud", + items * size, ctx->allocated); + + p = ngx_palloc(ctx->request->pool, items * size); + + return p; +} + + +static void +ngx_http_gzip_filter_free(void *opaque, void *address) +{ +#if 0 + ngx_http_gzip_ctx_t *ctx = opaque; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->request->connection->log, 0, + "gzip free: %p", address); +#endif +} + + +static u_char * +ngx_http_gzip_log_ratio(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op) +{ + ngx_uint_t zint, zfrac; + ngx_http_gzip_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_gzip_filter_module); + + if (ctx == NULL || ctx->zout == 0) { + *buf = '-'; + return buf + 1; + } + + zint = (ngx_uint_t) (ctx->zin / ctx->zout); + zfrac = (ngx_uint_t) ((ctx->zin * 100 / ctx->zout) % 100); + + if ((ctx->zin * 1000 / ctx->zout) % 10 > 4) { + + /* the rounding, e.g., 2.125 to 2.13 */ + + zfrac++; + + if (zfrac > 99) { + zint++; + zfrac = 0; + } + } + + return ngx_sprintf(buf, "%ui.%02ui", zint, zfrac); +} + + +static void +ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx) +{ + deflateEnd(&ctx->zstream); + + if (ctx->preallocated) { + ngx_pfree(ctx->request->pool, ctx->preallocated); + } + + ctx->zstream.avail_in = 0; + ctx->zstream.avail_out = 0; + + ctx->done = 1; + + return; +} + + +static ngx_int_t +ngx_http_gzip_add_log_formats(ngx_conf_t *cf) +{ + ngx_http_log_op_name_t *op; + + for (op = ngx_http_gzip_log_fmt_ops; op->name.len; op++) { /* void */ } + op->run = NULL; + + for (op = ngx_http_log_fmt_ops; op->run; op++) { + if (op->name.len == 0) { + op = (ngx_http_log_op_name_t *) op->run; + } + } + + op->run = (ngx_http_log_op_run_pt) ngx_http_gzip_log_fmt_ops; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_gzip_filter_init(ngx_cycle_t *cycle) +{ + ngx_http_next_header_filter = ngx_http_top_header_filter; + ngx_http_top_header_filter = ngx_http_gzip_header_filter; + + ngx_http_next_body_filter = ngx_http_top_body_filter; + ngx_http_top_body_filter = ngx_http_gzip_body_filter; + + return NGX_OK; +} + + +static void * +ngx_http_gzip_create_conf(ngx_conf_t *cf) +{ + ngx_http_gzip_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_gzip_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + /* + * set by ngx_pcalloc(): + * + * conf->bufs.num = 0; + * conf->proxied = 0; + * conf->types = NULL; + */ + + conf->enable = NGX_CONF_UNSET; + conf->no_buffer = NGX_CONF_UNSET; + + conf->http_version = NGX_CONF_UNSET_UINT; + + conf->level = NGX_CONF_UNSET; + conf->wbits = (size_t) NGX_CONF_UNSET; + conf->memlevel = (size_t) NGX_CONF_UNSET; + conf->min_length = NGX_CONF_UNSET; + + return conf; +} + + +static char * +ngx_http_gzip_merge_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_gzip_conf_t *prev = parent; + ngx_http_gzip_conf_t *conf = child; + + ngx_http_gzip_type_t *type; + + ngx_conf_merge_value(conf->enable, prev->enable, 0); + + ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, 4, ngx_pagesize); + + ngx_conf_merge_unsigned_value(conf->http_version, prev->http_version, + NGX_HTTP_VERSION_11); + ngx_conf_merge_bitmask_value(conf->proxied, prev->proxied, + (NGX_CONF_BITMASK_SET|NGX_HTTP_GZIP_PROXIED_OFF)); + + 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, 0); + ngx_conf_merge_value(conf->no_buffer, prev->no_buffer, 0); + + if (conf->types == NULL) { + if (prev->types == NULL) { + conf->types = ngx_array_create(cf->pool, 1, + sizeof(ngx_http_gzip_type_t)); + if (conf->types == NULL) { + return NGX_CONF_ERROR; + } + + type = ngx_array_push(conf->types); + if (type == NULL) { + return NGX_CONF_ERROR; + } + + type->name.len = sizeof("text/html") - 1; + type->name.data = (u_char *) "text/html"; + type->enable = 1; + + } else { + conf->types = prev->types; + } + } + + return NGX_CONF_OK; +} + + +static char * +ngx_http_gzip_set_types(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_gzip_conf_t *gcf = conf; + + ngx_str_t *value; + ngx_uint_t i; + ngx_http_gzip_type_t *type; + + if (gcf->types == NULL) { + gcf->types = ngx_array_create(cf->pool, 4, + sizeof(ngx_http_gzip_type_t)); + if (gcf->types == NULL) { + return NGX_CONF_ERROR; + } + + type = ngx_array_push(gcf->types); + if (type == NULL) { + return NGX_CONF_ERROR; + } + + type->name.len = sizeof("text/html") - 1; + type->name.data = (u_char *) "text/html"; + type->enable = 1; + } + + value = cf->args->elts; + + for (i = 1; i < cf->args->nelts; i++) { + + if (ngx_strcmp(value[i].data, "text/html") == 0) { + continue; + } + + type = ngx_array_push(gcf->types); + if (type == NULL) { + return NGX_CONF_ERROR; + } + + type->name.len = value[i].len; + + type->name.data = ngx_palloc(cf->pool, type->name.len + 1); + if (type->name.data == NULL) { + return NGX_CONF_ERROR; + } + + ngx_cpystrn(type->name.data, value[i].data, type->name.len + 1); + } + + return NGX_CONF_OK; +} + + +static char * +ngx_http_gzip_set_window(ngx_conf_t *cf, void *post, void *data) +{ + int *np = data; + + int wbits, wsize; + + wbits = 15; + + for (wsize = 32 * 1024; wsize > 256; wsize >>= 1) { + + if (wsize == *np) { + *np = wbits; + + return NGX_CONF_OK; + } + + wbits--; + } + + return "must be 512, 1k, 2k, 4k, 8k, 16k, or 32k"; +} + + +static char * +ngx_http_gzip_set_hash(ngx_conf_t *cf, void *post, void *data) +{ + int *np = data; + + int memlevel, hsize; + + memlevel = 9; + + for (hsize = 128 * 1024; hsize > 256; hsize >>= 1) { + + if (hsize == *np) { + *np = memlevel; + + return NGX_CONF_OK; + } + + memlevel--; + } + + return "must be 512, 1k, 2k, 4k, 8k, 16k, 32k, 64k, or 128k"; +} diff --git a/src/http/modules/ngx_http_headers_filter.c b/src/http/modules/ngx_http_headers_filter.c deleted file mode 100644 --- a/src/http/modules/ngx_http_headers_filter.c +++ /dev/null @@ -1,239 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#include -#include -#include - - -typedef struct { - time_t expires; -} ngx_http_headers_conf_t; - - -#define NGX_HTTP_EXPIRES_UNSET -2147483647 -#define NGX_HTTP_EXPIRES_OFF -2147483646 -#define NGX_HTTP_EXPIRES_EPOCH -2147483645 - - -static ngx_int_t ngx_http_headers_filter_init(ngx_cycle_t *cycle); -static void *ngx_http_headers_create_conf(ngx_conf_t *cf); -static char *ngx_http_headers_merge_conf(ngx_conf_t *cf, - void *parent, void *child); -char *ngx_http_headers_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); - - -static ngx_command_t ngx_http_headers_filter_commands[] = { - - { ngx_string("expires"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_http_headers_expires, - NGX_HTTP_LOC_CONF_OFFSET, - 0, - NULL}, - - ngx_null_command -}; - - -static ngx_http_module_t ngx_http_headers_filter_module_ctx = { - NULL, /* pre conf */ - - NULL, /* create main configuration */ - NULL, /* init main configuration */ - - NULL, /* create server configuration */ - NULL, /* merge server configuration */ - - ngx_http_headers_create_conf, /* create location configuration */ - ngx_http_headers_merge_conf /* merge location configuration */ -}; - - -ngx_module_t ngx_http_headers_filter_module = { - NGX_MODULE, - &ngx_http_headers_filter_module_ctx, /* module context */ - ngx_http_headers_filter_commands, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - ngx_http_headers_filter_init, /* init module */ - NULL /* init process */ -}; - - -static ngx_http_output_header_filter_pt ngx_http_next_header_filter; - - -static ngx_int_t ngx_http_headers_filter(ngx_http_request_t *r) -{ - size_t len; - ngx_table_elt_t *expires, *cc; - ngx_http_headers_conf_t *conf; - - if (r->headers_out.status != NGX_HTTP_OK) { - return ngx_http_next_header_filter(r); - } - - conf = ngx_http_get_module_loc_conf(r, ngx_http_headers_filter_module); - - if (conf->expires != NGX_HTTP_EXPIRES_OFF) { - - if (!(expires = ngx_list_push(&r->headers_out.headers))) { - return NGX_ERROR; - } - - r->headers_out.expires = expires; - - if (!(cc = ngx_list_push(&r->headers_out.headers))) { - return NGX_ERROR; - } - - r->headers_out.cache_control = cc; - - len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT"); - - expires->key.len = sizeof("Expires") - 1; - expires->key.data = (u_char *) "Expires"; - expires->value.len = len - 1; - - cc->key.len = sizeof("Cache-Control") - 1; - cc->key.data = (u_char *) "Cache-Control"; - - if (conf->expires == NGX_HTTP_EXPIRES_EPOCH) { - expires->value.data = (u_char *) "Thu, 01 Jan 1970 00:00:01 GMT"; - - cc->value.len = sizeof("no-cache") - 1; - cc->value.data = (u_char *) "no-cache"; - - } else { - expires->value.data = ngx_palloc(r->pool, len); - if (expires->value.data == NULL) { - return NGX_ERROR; - } - - if (conf->expires == 0) { - ngx_memcpy(expires->value.data, ngx_cached_http_time.data, - ngx_cached_http_time.len + 1); - - cc->value.len = sizeof("max-age=0") - 1; - cc->value.data = (u_char *) "max-age=0"; - - } else { - ngx_http_time(expires->value.data, ngx_time() + conf->expires); - - if (conf->expires < 0) { - cc->value.len = sizeof("no-cache") - 1; - cc->value.data = (u_char *) "no-cache"; - - } else { - cc->value.data = ngx_palloc(r->pool, sizeof("max-age=") - + NGX_TIME_T_LEN + 1); - if (cc->value.data == NULL) { - return NGX_ERROR; - } - - cc->value.len = ngx_sprintf(cc->value.data, "max-age=%T", - conf->expires) - - cc->value.data; - - } - } - } - } - - return ngx_http_next_header_filter(r); -} - - -static ngx_int_t ngx_http_headers_filter_init(ngx_cycle_t *cycle) -{ - ngx_http_next_header_filter = ngx_http_top_header_filter; - ngx_http_top_header_filter = ngx_http_headers_filter; - - return NGX_OK; -} - - -static void *ngx_http_headers_create_conf(ngx_conf_t *cf) -{ - ngx_http_headers_conf_t *conf; - - if (!(conf = ngx_palloc(cf->pool, sizeof(ngx_http_headers_conf_t)))) { - return NGX_CONF_ERROR; - } - - conf->expires = NGX_HTTP_EXPIRES_UNSET; - - return conf; -} - - -static char *ngx_http_headers_merge_conf(ngx_conf_t *cf, - void *parent, void *child) -{ - ngx_http_headers_conf_t *prev = parent; - ngx_http_headers_conf_t *conf = child; - - if (conf->expires == NGX_HTTP_EXPIRES_UNSET) { - conf->expires = (prev->expires == NGX_HTTP_EXPIRES_UNSET) ? - NGX_HTTP_EXPIRES_OFF : prev->expires; - } - - return NGX_CONF_OK; -} - - -char *ngx_http_headers_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_http_headers_conf_t *hcf = conf; - - ngx_uint_t minus; - ngx_str_t *value; - - if (hcf->expires != NGX_HTTP_EXPIRES_UNSET) { - return "is duplicate"; - } - - value = cf->args->elts; - - if (ngx_strcmp(value[1].data, "epoch") == 0) { - hcf->expires = NGX_HTTP_EXPIRES_EPOCH; - return NGX_CONF_OK; - } - - if (ngx_strcmp(value[1].data, "off") == 0) { - hcf->expires = NGX_HTTP_EXPIRES_OFF; - return NGX_CONF_OK; - } - - if (value[1].data[0] == '+') { - value[1].data++; - value[1].len--; - minus = 0; - - } else if (value[1].data[0] == '-') { - value[1].data++; - value[1].len--; - minus = 1; - - } else { - minus = 0; - } - - hcf->expires = ngx_parse_time(&value[1], 1); - if (hcf->expires == NGX_ERROR) { - return "invalid value"; - } - - if (hcf->expires == NGX_PARSE_LARGE_TIME) { - return "value must be less than 68 years"; - } - - if (minus) { - hcf->expires = - hcf->expires; - } - - return NGX_CONF_OK; -} diff --git a/src/http/modules/ngx_http_headers_filter_module.c b/src/http/modules/ngx_http_headers_filter_module.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_headers_filter_module.c @@ -0,0 +1,248 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +typedef struct { + time_t expires; +} ngx_http_headers_conf_t; + + +#define NGX_HTTP_EXPIRES_UNSET -2147483647 +#define NGX_HTTP_EXPIRES_OFF -2147483646 +#define NGX_HTTP_EXPIRES_EPOCH -2147483645 + + +static ngx_int_t ngx_http_headers_filter_init(ngx_cycle_t *cycle); +static void *ngx_http_headers_create_conf(ngx_conf_t *cf); +static char *ngx_http_headers_merge_conf(ngx_conf_t *cf, + void *parent, void *child); +static char *ngx_http_headers_expires(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + + +static ngx_command_t ngx_http_headers_filter_commands[] = { + + { ngx_string("expires"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_headers_expires, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL}, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_headers_filter_module_ctx = { + NULL, /* pre conf */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_headers_create_conf, /* create location configuration */ + ngx_http_headers_merge_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_headers_filter_module = { + NGX_MODULE, + &ngx_http_headers_filter_module_ctx, /* module context */ + ngx_http_headers_filter_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + ngx_http_headers_filter_init, /* init module */ + NULL /* init process */ +}; + + +static ngx_http_output_header_filter_pt ngx_http_next_header_filter; + + +static ngx_int_t +ngx_http_headers_filter(ngx_http_request_t *r) +{ + size_t len; + ngx_table_elt_t *expires, *cc; + ngx_http_headers_conf_t *conf; + + if (r->headers_out.status != NGX_HTTP_OK) { + return ngx_http_next_header_filter(r); + } + + conf = ngx_http_get_module_loc_conf(r, ngx_http_headers_filter_module); + + if (conf->expires != NGX_HTTP_EXPIRES_OFF) { + + expires = ngx_list_push(&r->headers_out.headers); + if (expires == NULL) { + return NGX_ERROR; + } + + r->headers_out.expires = expires; + + cc = ngx_list_push(&r->headers_out.headers); + if (cc == NULL) { + return NGX_ERROR; + } + + r->headers_out.cache_control = cc; + + len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT"); + + expires->key.len = sizeof("Expires") - 1; + expires->key.data = (u_char *) "Expires"; + expires->value.len = len - 1; + + cc->key.len = sizeof("Cache-Control") - 1; + cc->key.data = (u_char *) "Cache-Control"; + + if (conf->expires == NGX_HTTP_EXPIRES_EPOCH) { + expires->value.data = (u_char *) "Thu, 01 Jan 1970 00:00:01 GMT"; + + cc->value.len = sizeof("no-cache") - 1; + cc->value.data = (u_char *) "no-cache"; + + } else { + expires->value.data = ngx_palloc(r->pool, len); + if (expires->value.data == NULL) { + return NGX_ERROR; + } + + if (conf->expires == 0) { + ngx_memcpy(expires->value.data, ngx_cached_http_time.data, + ngx_cached_http_time.len + 1); + + cc->value.len = sizeof("max-age=0") - 1; + cc->value.data = (u_char *) "max-age=0"; + + } else { + ngx_http_time(expires->value.data, ngx_time() + conf->expires); + + if (conf->expires < 0) { + cc->value.len = sizeof("no-cache") - 1; + cc->value.data = (u_char *) "no-cache"; + + } else { + cc->value.data = ngx_palloc(r->pool, sizeof("max-age=") + + NGX_TIME_T_LEN + 1); + if (cc->value.data == NULL) { + return NGX_ERROR; + } + + cc->value.len = ngx_sprintf(cc->value.data, "max-age=%T", + conf->expires) + - cc->value.data; + + } + } + } + } + + return ngx_http_next_header_filter(r); +} + + +static ngx_int_t +ngx_http_headers_filter_init(ngx_cycle_t *cycle) +{ + ngx_http_next_header_filter = ngx_http_top_header_filter; + ngx_http_top_header_filter = ngx_http_headers_filter; + + return NGX_OK; +} + + +static void * +ngx_http_headers_create_conf(ngx_conf_t *cf) +{ + ngx_http_headers_conf_t *conf; + + conf = ngx_palloc(cf->pool, sizeof(ngx_http_headers_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + conf->expires = NGX_HTTP_EXPIRES_UNSET; + + return conf; +} + + +static char * +ngx_http_headers_merge_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_headers_conf_t *prev = parent; + ngx_http_headers_conf_t *conf = child; + + if (conf->expires == NGX_HTTP_EXPIRES_UNSET) { + conf->expires = (prev->expires == NGX_HTTP_EXPIRES_UNSET) ? + NGX_HTTP_EXPIRES_OFF : prev->expires; + } + + return NGX_CONF_OK; +} + + +static char * +ngx_http_headers_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_headers_conf_t *hcf = conf; + + ngx_uint_t minus; + ngx_str_t *value; + + if (hcf->expires != NGX_HTTP_EXPIRES_UNSET) { + return "is duplicate"; + } + + value = cf->args->elts; + + if (ngx_strcmp(value[1].data, "epoch") == 0) { + hcf->expires = NGX_HTTP_EXPIRES_EPOCH; + return NGX_CONF_OK; + } + + if (ngx_strcmp(value[1].data, "off") == 0) { + hcf->expires = NGX_HTTP_EXPIRES_OFF; + return NGX_CONF_OK; + } + + if (value[1].data[0] == '+') { + value[1].data++; + value[1].len--; + minus = 0; + + } else if (value[1].data[0] == '-') { + value[1].data++; + value[1].len--; + minus = 1; + + } else { + minus = 0; + } + + hcf->expires = ngx_parse_time(&value[1], 1); + + if (hcf->expires == NGX_ERROR) { + return "invalid value"; + } + + if (hcf->expires == NGX_PARSE_LARGE_TIME) { + return "value must be less than 68 years"; + } + + if (minus) { + hcf->expires = - hcf->expires; + } + + return NGX_CONF_OK; +} diff --git a/src/http/modules/ngx_http_index_handler.c b/src/http/modules/ngx_http_index_handler.c deleted file mode 100644 --- a/src/http/modules/ngx_http_index_handler.c +++ /dev/null @@ -1,537 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#include -#include -#include - - -typedef struct { - ngx_array_t indices; - size_t max_index_len; - ngx_http_cache_hash_t *index_cache; -} ngx_http_index_loc_conf_t; - - -typedef struct { - ngx_uint_t index; - u_char *last; - ngx_str_t path; - ngx_str_t redirect; - ngx_http_cache_entry_t *cache; - ngx_uint_t tested; /* unsigned tested:1 */ -} ngx_http_index_ctx_t; - - -#define NGX_HTTP_DEFAULT_INDEX "index.html" - - -static ngx_int_t ngx_http_index_test_dir(ngx_http_request_t *r, - ngx_http_index_ctx_t *ctx); -static ngx_int_t ngx_http_index_error(ngx_http_request_t *r, - ngx_http_index_ctx_t *ctx, ngx_err_t err); - -static ngx_int_t ngx_http_index_init(ngx_cycle_t *cycle); -static void *ngx_http_index_create_loc_conf(ngx_conf_t *cf); -static char *ngx_http_index_merge_loc_conf(ngx_conf_t *cf, - void *parent, void *child); -static char *ngx_http_index_set_index(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); - - -static ngx_command_t ngx_http_index_commands[] = { - - { ngx_string("index"), - NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, - ngx_http_index_set_index, - NGX_HTTP_LOC_CONF_OFFSET, - 0, - NULL }, - -#if (NGX_HTTP_CACHE) - - { ngx_string("index_cache"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE3, - ngx_http_set_cache_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_index_loc_conf_t, index_cache), - NULL }, - -#endif - - ngx_null_command -}; - - -ngx_http_module_t ngx_http_index_module_ctx = { - NULL, /* pre conf */ - - NULL, /* create main configuration */ - NULL, /* init main configuration */ - - NULL, /* create server configuration */ - NULL, /* merge server configuration */ - - ngx_http_index_create_loc_conf, /* create location configration */ - ngx_http_index_merge_loc_conf /* merge location configration */ -}; - - -ngx_module_t ngx_http_index_module = { - NGX_MODULE, - &ngx_http_index_module_ctx, /* module context */ - ngx_http_index_commands, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - ngx_http_index_init, /* init module */ - NULL /* init process */ -}; - - -/* - * Try to open the first index file before the test of the directory existence - * because the valid requests should be many more than invalid ones. - * If open() failed then stat() should be more quickly because some data - * is already cached in the kernel. - * Besides Win32 has ERROR_PATH_NOT_FOUND (NGX_ENOTDIR). - * Unix has ENOTDIR error, although it less helpfull - it shows only - * that path contains the usual file in place of the directory. - */ - -static ngx_int_t ngx_http_index_handler(ngx_http_request_t *r) -{ - u_char *name; - ngx_fd_t fd; - ngx_int_t rc; - ngx_str_t *index; - ngx_err_t err; - ngx_log_t *log; - ngx_http_index_ctx_t *ctx; - ngx_http_core_loc_conf_t *clcf; - ngx_http_index_loc_conf_t *ilcf; -#if (NGX_HTTP_CACHE0) - /* crc must be in ctx !! */ - uint32_t crc; -#endif - - if (r->uri.data[r->uri.len - 1] != '/') { - return NGX_DECLINED; - } - - /* TODO: Win32 */ - if (r->zero_in_uri) { - return NGX_DECLINED; - } - - log = r->connection->log; - - /* - * we use context because the handler supports an async file opening - * and thus can be called several times - */ - - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - ilcf = ngx_http_get_module_loc_conf(r, ngx_http_index_module); - - ctx = ngx_http_get_module_ctx(r, ngx_http_index_module); - if (ctx == NULL) { - ngx_http_create_ctx(r, ctx, ngx_http_index_module, - sizeof(ngx_http_index_ctx_t), - NGX_HTTP_INTERNAL_SERVER_ERROR); - -#if (NGX_HTTP_CACHE) - - if (ilcf->index_cache) { - ctx->cache = ngx_http_cache_get(ilcf->index_cache, NULL, - &r->uri, &crc); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, - "http index cache get: %p", ctx->cache); - - if (ctx->cache && !ctx->cache->expired) { - - ctx->cache->accessed = ngx_cached_time; - - ctx->redirect.len = ctx->cache->data.value.len; - ctx->redirect.data = ngx_palloc(r->pool, ctx->redirect.len + 1); - if (ctx->redirect.data == NULL) { - ngx_http_cache_unlock(ilcf->index_cache, ctx->cache, log); - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - ngx_memcpy(ctx->redirect.data, ctx->cache->data.value.data, - ctx->redirect.len + 1); - ngx_http_cache_unlock(ilcf->index_cache, ctx->cache, log); - - return ngx_http_internal_redirect(r, &ctx->redirect, NULL); - } - } - -#endif - -#if 0 - ctx->path.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len - + ilcf->max_index_len - - clcf->alias * clcf->name.len); - if (ctx->path.data == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - ctx->redirect.data = ngx_cpymem(ctx->path.data, clcf->root.data, - clcf->root.len); -#endif - - if (clcf->alias) { - ctx->path.data = ngx_palloc(r->pool, clcf->root.len - + r->uri.len + 1 - clcf->name.len - + ilcf->max_index_len); - if (ctx->path.data == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - ctx->redirect.data = ngx_palloc(r->pool, r->uri.len - + ilcf->max_index_len); - if (ctx->redirect.data == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - ngx_memcpy(ctx->path.data, clcf->root.data, clcf->root.len); - - ctx->last = ngx_cpystrn(ctx->path.data + clcf->root.len, - r->uri.data + clcf->name.len, - r->uri.len + 1 - clcf->name.len); - -#if 0 - /* - * aliases usually have trailling "/", - * set it in the start of the possible redirect - */ - - if (*ctx->redirect.data != '/') { - ctx->redirect.data--; - } -#endif - - } else { - ctx->path.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len - + ilcf->max_index_len); - if (ctx->path.data == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - ctx->redirect.data = ngx_cpymem(ctx->path.data, clcf->root.data, - clcf->root.len); - - ctx->last = ngx_cpystrn(ctx->redirect.data, r->uri.data, - r->uri.len + 1); - } - } - - ctx->path.len = ctx->last - ctx->path.data; - - index = ilcf->indices.elts; - for (/* void */; ctx->index < ilcf->indices.nelts; ctx->index++) { - - if (index[ctx->index].data[0] == '/') { - name = index[ctx->index].data; - - } else { - ngx_memcpy(ctx->last, index[ctx->index].data, - index[ctx->index].len + 1); - name = ctx->path.data; - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, - "open index \"%s\"", name); - - fd = ngx_open_file(name, NGX_FILE_RDONLY, NGX_FILE_OPEN); - - if (fd == (ngx_fd_t) NGX_AGAIN) { - return NGX_AGAIN; - } - - if (fd == NGX_INVALID_FILE) { - err = ngx_errno; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, err, - ngx_open_file_n " \"%s\" failed", name); - - if (err == NGX_ENOTDIR) { - return ngx_http_index_error(r, ctx, err); - - } else if (err == NGX_EACCES) { - return ngx_http_index_error(r, ctx, err); - } - - if (!ctx->tested) { - rc = ngx_http_index_test_dir(r, ctx); - - if (rc != NGX_OK) { - return rc; - } - - ctx->tested = 1; - } - - if (err == NGX_ENOENT) { - continue; - } - - ngx_log_error(NGX_LOG_ERR, log, err, - ngx_open_file_n " \"%s\" failed", name); - - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - - /* STUB: open file cache */ - - r->file.name.data = name; - r->file.fd = fd; - - if (index[ctx->index].data[0] == '/') { - r->file.name.len = index[ctx->index].len; - ctx->redirect.len = index[ctx->index].len; - ctx->redirect.data = index[ctx->index].data; - - } else { - if (clcf->alias) { - name = ngx_cpymem(ctx->redirect.data, r->uri.data, r->uri.len); - ngx_memcpy(name, index[ctx->index].data, - index[ctx->index].len + 1); - } - - ctx->redirect.len = r->uri.len + index[ctx->index].len; - r->file.name.len = clcf->root.len + r->uri.len - - clcf->alias * clcf->name.len - + index[ctx->index].len; - } - - /**/ - - -#if (NGX_HTTP_CACHE) - - if (ilcf->index_cache) { - - if (ctx->cache) { - if (ctx->redirect.len == ctx->cache->data.value.len - && ngx_memcmp(ctx->cache->data.value.data, - ctx->redirect.data, ctx->redirect.len) == 0) - { - ctx->cache->accessed = ngx_cached_time; - ctx->cache->updated = ngx_cached_time; - ngx_http_cache_unlock(ilcf->index_cache, ctx->cache, log); - - return ngx_http_internal_redirect(r, &ctx->redirect, NULL); - } - } - - ctx->redirect.len++; - ctx->cache = ngx_http_cache_alloc(ilcf->index_cache, ctx->cache, - NULL, &r->uri, crc, - &ctx->redirect, log); - ctx->redirect.len--; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, - "http index cache alloc: %p", ctx->cache); - - if (ctx->cache) { - ctx->cache->fd = NGX_INVALID_FILE; - ctx->cache->accessed = ngx_cached_time; - ctx->cache->last_modified = 0; - ctx->cache->updated = ngx_cached_time; - ctx->cache->memory = 1; - ngx_http_cache_unlock(ilcf->index_cache, ctx->cache, log); - } - } - -#endif - - return ngx_http_internal_redirect(r, &ctx->redirect, NULL); - } - - return NGX_DECLINED; -} - - -static ngx_int_t ngx_http_index_test_dir(ngx_http_request_t *r, - ngx_http_index_ctx_t *ctx) -{ - ngx_err_t err; - - ctx->path.data[ctx->path.len - 1] = '\0'; - ctx->path.data[ctx->path.len] = '\0'; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http check dir: \"%s\"", ctx->path.data); - - if (ngx_file_info(ctx->path.data, &r->file.info) == -1) { - - err = ngx_errno; - - if (err == NGX_ENOENT) { - ctx->path.data[ctx->path.len - 1] = '/'; - return ngx_http_index_error(r, ctx, err); - } - - ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, - ngx_file_info_n " \"%s\" failed", ctx->path.data); - - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - ctx->path.data[ctx->path.len - 1] = '/'; - - if (ngx_is_dir(&r->file.info)) { - return NGX_OK; - } - - /* THINK: not reached ??? */ - return ngx_http_index_error(r, ctx, 0); -} - - -static ngx_int_t ngx_http_index_error(ngx_http_request_t *r, - ngx_http_index_ctx_t *ctx, ngx_err_t err) -{ - if (err == NGX_EACCES) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, err, - "\"%s\" is forbidden", ctx->path.data); - - return NGX_HTTP_FORBIDDEN; - } - - ngx_log_error(NGX_LOG_ERR, r->connection->log, err, - "\"%s\" is not found", ctx->path.data); - return NGX_HTTP_NOT_FOUND; -} - - -static ngx_int_t ngx_http_index_init(ngx_cycle_t *cycle) -{ - ngx_http_handler_pt *h; - ngx_http_core_main_conf_t *cmcf; - - cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module); - - h = ngx_push_array(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers); - if (h == NULL) { - return NGX_ERROR; - } - - *h = ngx_http_index_handler; - - return NGX_OK; -} - - -static void *ngx_http_index_create_loc_conf(ngx_conf_t *cf) -{ - ngx_http_index_loc_conf_t *conf; - - ngx_test_null(conf, ngx_palloc(cf->pool, sizeof(ngx_http_index_loc_conf_t)), - NGX_CONF_ERROR); - - ngx_init_array(conf->indices, cf->pool, 3, sizeof(ngx_str_t), - NGX_CONF_ERROR); - conf->max_index_len = 0; - - conf->index_cache = NULL; - - return conf; -} - - -/* TODO: remove duplicate indices */ - -static char *ngx_http_index_merge_loc_conf(ngx_conf_t *cf, - void *parent, void *child) -{ - ngx_http_index_loc_conf_t *prev = parent; - ngx_http_index_loc_conf_t *conf = child; - - ngx_str_t *index; - - if (conf->max_index_len == 0) { - if (prev->max_index_len != 0) { - ngx_memcpy(conf, prev, sizeof(ngx_http_index_loc_conf_t)); - return NGX_CONF_OK; - } - - ngx_test_null(index, ngx_push_array(&conf->indices), NGX_CONF_ERROR); - index->len = sizeof(NGX_HTTP_DEFAULT_INDEX) - 1; - index->data = (u_char *) NGX_HTTP_DEFAULT_INDEX; - conf->max_index_len = sizeof(NGX_HTTP_DEFAULT_INDEX); - - return NGX_CONF_OK; - } - -#if 0 - - if (prev->max_index_len != 0) { - - prev_index = prev->indices.elts; - for (i = 0; i < prev->indices.nelts; i++) { - ngx_test_null(index, ngx_push_array(&conf->indices), - NGX_CONF_ERROR); - index->len = prev_index[i].len; - index->data = prev_index[i].data; - } - } - - if (conf->max_index_len < prev->max_index_len) { - conf->max_index_len = prev->max_index_len; - } - -#endif - - if (conf->index_cache == NULL) { - conf->index_cache = prev->index_cache; - } - - return NGX_CONF_OK; -} - - -/* TODO: warn about duplicate indices */ - -static char *ngx_http_index_set_index(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf) -{ - ngx_http_index_loc_conf_t *ilcf = conf; - - ngx_uint_t i; - ngx_str_t *index, *value; - - value = cf->args->elts; - - if (value[1].data[0] == '/' && ilcf->indices.nelts == 0) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "first index \"%V\" in \"%V\" directive " - "must not be absolute", - &value[1], &cmd->name); - return NGX_CONF_ERROR; - } - - for (i = 1; i < cf->args->nelts; i++) { - if (value[i].len == 0) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "index \"%V\" in \"%V\" directive is invalid", - &value[1], &cmd->name); - return NGX_CONF_ERROR; - } - - ngx_test_null(index, ngx_push_array(&ilcf->indices), NGX_CONF_ERROR); - index->len = value[i].len; - index->data = value[i].data; - - if (ilcf->max_index_len < index->len + 1) { - ilcf->max_index_len = index->len + 1; - } - } - - return NGX_CONF_OK; -} diff --git a/src/http/modules/ngx_http_index_module.c b/src/http/modules/ngx_http_index_module.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_index_module.c @@ -0,0 +1,558 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +typedef struct { + ngx_array_t indices; + size_t max_index_len; + ngx_http_cache_hash_t *index_cache; +} ngx_http_index_loc_conf_t; + + +typedef struct { + ngx_uint_t index; + u_char *last; + ngx_str_t path; + ngx_str_t redirect; + ngx_http_cache_entry_t *cache; + ngx_uint_t tested; /* unsigned tested:1 */ +} ngx_http_index_ctx_t; + + +#define NGX_HTTP_DEFAULT_INDEX "index.html" + + +static ngx_int_t ngx_http_index_test_dir(ngx_http_request_t *r, + ngx_http_index_ctx_t *ctx); +static ngx_int_t ngx_http_index_error(ngx_http_request_t *r, + ngx_http_index_ctx_t *ctx, ngx_err_t err); + +static ngx_int_t ngx_http_index_init(ngx_cycle_t *cycle); +static void *ngx_http_index_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_index_merge_loc_conf(ngx_conf_t *cf, + void *parent, void *child); +static char *ngx_http_index_set_index(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + + +static ngx_command_t ngx_http_index_commands[] = { + + { ngx_string("index"), + NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_http_index_set_index, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + +#if (NGX_HTTP_CACHE) + + { ngx_string("index_cache"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE3, + ngx_http_set_cache_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_index_loc_conf_t, index_cache), + NULL }, + +#endif + + ngx_null_command +}; + + +ngx_http_module_t ngx_http_index_module_ctx = { + NULL, /* pre conf */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_index_create_loc_conf, /* create location configration */ + ngx_http_index_merge_loc_conf /* merge location configration */ +}; + + +ngx_module_t ngx_http_index_module = { + NGX_MODULE, + &ngx_http_index_module_ctx, /* module context */ + ngx_http_index_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + ngx_http_index_init, /* init module */ + NULL /* init process */ +}; + + +/* + * Try to open the first index file before the test of the directory existence + * because the valid requests should be many more than invalid ones. + * If open() would fail, then stat() should be more quickly because some data + * is already cached in the kernel. + * Besides, Win32 has ERROR_PATH_NOT_FOUND (NGX_ENOTDIR). + * Unix has ENOTDIR error, although it less helpfull - it points only + * that path contains the usual file in place of the directory. + */ + +static ngx_int_t ngx_http_index_handler(ngx_http_request_t *r) +{ + u_char *name; + ngx_fd_t fd; + ngx_int_t rc; + ngx_str_t *index; + ngx_err_t err; + ngx_log_t *log; + ngx_http_index_ctx_t *ctx; + ngx_http_core_loc_conf_t *clcf; + ngx_http_index_loc_conf_t *ilcf; +#if (NGX_HTTP_CACHE0) + /* crc must be in ctx !! */ + uint32_t crc; +#endif + + if (r->uri.data[r->uri.len - 1] != '/') { + return NGX_DECLINED; + } + + /* TODO: Win32 */ + if (r->zero_in_uri) { + return NGX_DECLINED; + } + + log = r->connection->log; + + /* + * we use context because the handler supports an async file opening + * and thus can be called several times + */ + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + ilcf = ngx_http_get_module_loc_conf(r, ngx_http_index_module); + + ctx = ngx_http_get_module_ctx(r, ngx_http_index_module); + if (ctx == NULL) { + + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_index_ctx_t)); + if (ctx == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + ngx_http_set_ctx(r, ctx, ngx_http_index_module); + +#if (NGX_HTTP_CACHE) + + if (ilcf->index_cache) { + ctx->cache = ngx_http_cache_get(ilcf->index_cache, NULL, + &r->uri, &crc); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, + "http index cache get: %p", ctx->cache); + + if (ctx->cache && !ctx->cache->expired) { + + ctx->cache->accessed = ngx_cached_time; + + ctx->redirect.len = ctx->cache->data.value.len; + ctx->redirect.data = ngx_palloc(r->pool, ctx->redirect.len + 1); + if (ctx->redirect.data == NULL) { + ngx_http_cache_unlock(ilcf->index_cache, ctx->cache, log); + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + ngx_memcpy(ctx->redirect.data, ctx->cache->data.value.data, + ctx->redirect.len + 1); + ngx_http_cache_unlock(ilcf->index_cache, ctx->cache, log); + + return ngx_http_internal_redirect(r, &ctx->redirect, NULL); + } + } + +#endif + +#if 0 + ctx->path.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len + + ilcf->max_index_len + - clcf->alias * clcf->name.len); + if (ctx->path.data == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + ctx->redirect.data = ngx_cpymem(ctx->path.data, clcf->root.data, + clcf->root.len); +#endif + + if (clcf->alias) { + ctx->path.data = ngx_palloc(r->pool, clcf->root.len + + r->uri.len + 1 - clcf->name.len + + ilcf->max_index_len); + if (ctx->path.data == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + ctx->redirect.data = ngx_palloc(r->pool, r->uri.len + + ilcf->max_index_len); + if (ctx->redirect.data == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + ngx_memcpy(ctx->path.data, clcf->root.data, clcf->root.len); + + ctx->last = ngx_cpystrn(ctx->path.data + clcf->root.len, + r->uri.data + clcf->name.len, + r->uri.len + 1 - clcf->name.len); + +#if 0 + /* + * aliases usually have trailling "/", + * set it in the start of the possible redirect + */ + + if (*ctx->redirect.data != '/') { + ctx->redirect.data--; + } +#endif + + } else { + ctx->path.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len + + ilcf->max_index_len); + if (ctx->path.data == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + ctx->redirect.data = ngx_cpymem(ctx->path.data, clcf->root.data, + clcf->root.len); + + ctx->last = ngx_cpystrn(ctx->redirect.data, r->uri.data, + r->uri.len + 1); + } + } + + ctx->path.len = ctx->last - ctx->path.data; + + index = ilcf->indices.elts; + for (/* void */; ctx->index < ilcf->indices.nelts; ctx->index++) { + + if (index[ctx->index].data[0] == '/') { + name = index[ctx->index].data; + + } else { + ngx_memcpy(ctx->last, index[ctx->index].data, + index[ctx->index].len + 1); + name = ctx->path.data; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, + "open index \"%s\"", name); + + fd = ngx_open_file(name, NGX_FILE_RDONLY, NGX_FILE_OPEN); + + if (fd == (ngx_fd_t) NGX_AGAIN) { + return NGX_AGAIN; + } + + if (fd == NGX_INVALID_FILE) { + err = ngx_errno; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, err, + ngx_open_file_n " \"%s\" failed", name); + + if (err == NGX_ENOTDIR) { + return ngx_http_index_error(r, ctx, err); + + } else if (err == NGX_EACCES) { + return ngx_http_index_error(r, ctx, err); + } + + if (!ctx->tested) { + rc = ngx_http_index_test_dir(r, ctx); + + if (rc != NGX_OK) { + return rc; + } + + ctx->tested = 1; + } + + if (err == NGX_ENOENT) { + continue; + } + + ngx_log_error(NGX_LOG_ERR, log, err, + ngx_open_file_n " \"%s\" failed", name); + + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + + /* STUB: open file cache */ + + r->file.name.data = name; + r->file.fd = fd; + + if (index[ctx->index].data[0] == '/') { + r->file.name.len = index[ctx->index].len; + ctx->redirect.len = index[ctx->index].len; + ctx->redirect.data = index[ctx->index].data; + + } else { + if (clcf->alias) { + name = ngx_cpymem(ctx->redirect.data, r->uri.data, r->uri.len); + ngx_memcpy(name, index[ctx->index].data, + index[ctx->index].len + 1); + } + + ctx->redirect.len = r->uri.len + index[ctx->index].len; + r->file.name.len = clcf->root.len + r->uri.len + - clcf->alias * clcf->name.len + + index[ctx->index].len; + } + + /**/ + + +#if (NGX_HTTP_CACHE) + + if (ilcf->index_cache) { + + if (ctx->cache) { + if (ctx->redirect.len == ctx->cache->data.value.len + && ngx_memcmp(ctx->cache->data.value.data, + ctx->redirect.data, ctx->redirect.len) == 0) + { + ctx->cache->accessed = ngx_cached_time; + ctx->cache->updated = ngx_cached_time; + ngx_http_cache_unlock(ilcf->index_cache, ctx->cache, log); + + return ngx_http_internal_redirect(r, &ctx->redirect, NULL); + } + } + + ctx->redirect.len++; + ctx->cache = ngx_http_cache_alloc(ilcf->index_cache, ctx->cache, + NULL, &r->uri, crc, + &ctx->redirect, log); + ctx->redirect.len--; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, + "http index cache alloc: %p", ctx->cache); + + if (ctx->cache) { + ctx->cache->fd = NGX_INVALID_FILE; + ctx->cache->accessed = ngx_cached_time; + ctx->cache->last_modified = 0; + ctx->cache->updated = ngx_cached_time; + ctx->cache->memory = 1; + ngx_http_cache_unlock(ilcf->index_cache, ctx->cache, log); + } + } + +#endif + + return ngx_http_internal_redirect(r, &ctx->redirect, NULL); + } + + return NGX_DECLINED; +} + + +static ngx_int_t ngx_http_index_test_dir(ngx_http_request_t *r, + ngx_http_index_ctx_t *ctx) +{ + ngx_err_t err; + + ctx->path.data[ctx->path.len - 1] = '\0'; + ctx->path.data[ctx->path.len] = '\0'; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http check dir: \"%s\"", ctx->path.data); + + if (ngx_file_info(ctx->path.data, &r->file.info) == -1) { + + err = ngx_errno; + + if (err == NGX_ENOENT) { + ctx->path.data[ctx->path.len - 1] = '/'; + return ngx_http_index_error(r, ctx, err); + } + + ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, + ngx_file_info_n " \"%s\" failed", ctx->path.data); + + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + ctx->path.data[ctx->path.len - 1] = '/'; + + if (ngx_is_dir(&r->file.info)) { + return NGX_OK; + } + + /* THINK: not reached ??? */ + return ngx_http_index_error(r, ctx, 0); +} + + +static ngx_int_t ngx_http_index_error(ngx_http_request_t *r, + ngx_http_index_ctx_t *ctx, ngx_err_t err) +{ + if (err == NGX_EACCES) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, err, + "\"%s\" is forbidden", ctx->path.data); + + return NGX_HTTP_FORBIDDEN; + } + + ngx_log_error(NGX_LOG_ERR, r->connection->log, err, + "\"%s\" is not found", ctx->path.data); + return NGX_HTTP_NOT_FOUND; +} + + +static ngx_int_t ngx_http_index_init(ngx_cycle_t *cycle) +{ + ngx_http_handler_pt *h; + ngx_http_core_main_conf_t *cmcf; + + cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module); + + h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_index_handler; + + return NGX_OK; +} + + +static void *ngx_http_index_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_index_loc_conf_t *conf; + + conf = ngx_palloc(cf->pool, sizeof(ngx_http_index_loc_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + if (ngx_array_init(&conf->indices, cf->pool, 2, sizeof(ngx_str_t)) + == NGX_ERROR) + { + return NGX_CONF_ERROR; + } + + conf->max_index_len = 0; + + conf->index_cache = NULL; + + return conf; +} + + +/* TODO: remove duplicate indices */ + +static char *ngx_http_index_merge_loc_conf(ngx_conf_t *cf, + void *parent, void *child) +{ + ngx_http_index_loc_conf_t *prev = parent; + ngx_http_index_loc_conf_t *conf = child; + + ngx_str_t *index; + + if (conf->max_index_len == 0) { + if (prev->max_index_len != 0) { + ngx_memcpy(conf, prev, sizeof(ngx_http_index_loc_conf_t)); + return NGX_CONF_OK; + } + + index = ngx_array_push(&conf->indices); + if (index == NULL) { + return NGX_CONF_ERROR; + } + + index->len = sizeof(NGX_HTTP_DEFAULT_INDEX) - 1; + index->data = (u_char *) NGX_HTTP_DEFAULT_INDEX; + conf->max_index_len = sizeof(NGX_HTTP_DEFAULT_INDEX); + + return NGX_CONF_OK; + } + +#if 0 + + if (prev->max_index_len != 0) { + + prev_index = prev->indices.elts; + for (i = 0; i < prev->indices.nelts; i++) { + index = ngx_array_push(&conf->indices); + if (index == NULL) { + return NGX_CONF_ERROR; + } + + index->len = prev_index[i].len; + index->data = prev_index[i].data; + } + } + + if (conf->max_index_len < prev->max_index_len) { + conf->max_index_len = prev->max_index_len; + } + +#endif + + if (conf->index_cache == NULL) { + conf->index_cache = prev->index_cache; + } + + return NGX_CONF_OK; +} + + +/* TODO: warn about duplicate indices */ + +static char *ngx_http_index_set_index(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + ngx_http_index_loc_conf_t *ilcf = conf; + + ngx_uint_t i; + ngx_str_t *index, *value; + + value = cf->args->elts; + + if (value[1].data[0] == '/' && ilcf->indices.nelts == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "first index \"%V\" in \"%V\" directive " + "must not be absolute", + &value[1], &cmd->name); + return NGX_CONF_ERROR; + } + + for (i = 1; i < cf->args->nelts; i++) { + if (value[i].len == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "index \"%V\" in \"%V\" directive is invalid", + &value[1], &cmd->name); + return NGX_CONF_ERROR; + } + + index = ngx_array_push(&ilcf->indices); + if (index == NULL) { + return NGX_CONF_ERROR; + } + + index->len = value[i].len; + index->data = value[i].data; + + if (ilcf->max_index_len < index->len + 1) { + ilcf->max_index_len = index->len + 1; + } + } + + return NGX_CONF_OK; +} diff --git a/src/http/modules/ngx_http_not_modified_filter.c b/src/http/modules/ngx_http_not_modified_filter_module.c rename from src/http/modules/ngx_http_not_modified_filter.c rename to src/http/modules/ngx_http_not_modified_filter_module.c diff --git a/src/http/modules/ngx_http_range_filter.c b/src/http/modules/ngx_http_range_filter.c deleted file mode 100644 --- a/src/http/modules/ngx_http_range_filter.c +++ /dev/null @@ -1,578 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#include -#include -#include - - -/* - * the single part format: - * - * "HTTP/1.0 206 Partial Content" CRLF - * ... header ... - * "Content-Type: image/jpeg" CRLF - * "Content-Length: SIZE" CRLF - * "Content-Range: bytes START-END/SIZE" CRLF - * CRLF - * ... data ... - * - * - * the mutlipart format: - * - * "HTTP/1.0 206 Partial Content" CRLF - * ... header ... - * "Content-Type: multipart/byteranges; boundary=0123456789" CRLF - * CRLF - * CRLF - * "--0123456789" CRLF - * "Content-Type: image/jpeg" CRLF - * "Content-Range: bytes START0-END0/SIZE" CRLF - * CRLF - * ... data ... - * CRLF - * "--0123456789" CRLF - * "Content-Type: image/jpeg" CRLF - * "Content-Range: bytes START1-END1/SIZE" CRLF - * CRLF - * ... data ... - * CRLF - * "--0123456789--" CRLF - */ - - -typedef struct { - ngx_str_t boundary_header; -} ngx_http_range_filter_ctx_t; - - -static ngx_int_t ngx_http_range_header_filter_init(ngx_cycle_t *cycle); -static ngx_int_t ngx_http_range_body_filter_init(ngx_cycle_t *cycle); - - -static ngx_http_module_t ngx_http_range_header_filter_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_range_header_filter_module = { - NGX_MODULE, - &ngx_http_range_header_filter_module_ctx, /* module context */ - NULL, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - ngx_http_range_header_filter_init, /* init module */ - NULL /* init process */ -}; - - -static ngx_http_module_t ngx_http_range_body_filter_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_range_body_filter_module = { - NGX_MODULE, - &ngx_http_range_body_filter_module_ctx, /* module context */ - NULL, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - ngx_http_range_body_filter_init, /* init module */ - NULL /* init process */ -}; - - -static ngx_http_output_header_filter_pt ngx_http_next_header_filter; -static ngx_http_output_body_filter_pt ngx_http_next_body_filter; - - -static ngx_int_t -ngx_http_range_header_filter(ngx_http_request_t *r) -{ - u_char *p; - size_t len; - off_t start, end; - ngx_int_t rc; - ngx_uint_t suffix, i; - ngx_atomic_uint_t boundary; - ngx_table_elt_t *content_range; - ngx_http_range_t *range; - ngx_http_range_filter_ctx_t *ctx; - - if (r->http_version < NGX_HTTP_VERSION_10 - || r->headers_out.status != NGX_HTTP_OK - || r->headers_out.content_length_n == -1 - || !r->filter_allow_ranges) - { - return ngx_http_next_header_filter(r); - } - - if (r->headers_in.range == NULL - || r->headers_in.range->value.len < 7 - || ngx_strncasecmp(r->headers_in.range->value.data, "bytes=", 6) != 0) - { - - r->headers_out.accept_ranges = ngx_list_push(&r->headers_out.headers); - if (r->headers_out.accept_ranges == NULL) { - return NGX_ERROR; - } - - r->headers_out.accept_ranges->key.len = sizeof("Accept-Ranges") - 1; - r->headers_out.accept_ranges->key.data = (u_char *) "Accept-Ranges"; - r->headers_out.accept_ranges->value.len = sizeof("bytes") - 1; - r->headers_out.accept_ranges->value.data = (u_char *) "bytes"; - - return ngx_http_next_header_filter(r); - } - - if (ngx_array_init(&r->headers_out.ranges, r->pool, 2, - sizeof(ngx_http_range_t)) == NGX_ERROR) - { - return NGX_ERROR; - } - - rc = 0; - range = NULL; - p = r->headers_in.range->value.data + 6; - - for ( ;; ) { - start = 0; - end = 0; - suffix = 0; - - while (*p == ' ') { p++; } - - if (*p != '-') { - if (*p < '0' || *p > '9') { - rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; - break; - } - - while (*p >= '0' && *p <= '9') { - start = start * 10 + *p++ - '0'; - } - - while (*p == ' ') { p++; } - - if (*p++ != '-') { - rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; - break; - } - - if (start >= r->headers_out.content_length_n) { - rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; - break; - } - - while (*p == ' ') { p++; } - - if (*p == ',' || *p == '\0') { - if (!(range = ngx_array_push(&r->headers_out.ranges))) { - return NGX_ERROR; - } - - range->start = start; - range->end = r->headers_out.content_length_n; - - if (*p++ != ',') { - break; - } - - continue; - } - - } else { - suffix = 1; - p++; - } - - if (*p < '0' || *p > '9') { - rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; - break; - } - - while (*p >= '0' && *p <= '9') { - end = end * 10 + *p++ - '0'; - } - - while (*p == ' ') { p++; } - - if (*p != ',' && *p != '\0') { - rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; - break; - } - - if (suffix) { - start = r->headers_out.content_length_n - end; - end = r->headers_out.content_length_n - 1; - } - - if (start > end) { - rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; - break; - } - - if (!(range = ngx_array_push(&r->headers_out.ranges))) { - return NGX_ERROR; - } - - range->start = start; - - if (end >= r->headers_out.content_length_n) { - /* - * Download Accelerator sends the last byte position - * that equals to the file length - */ - range->end = r->headers_out.content_length_n; - - } else { - range->end = end + 1; - } - - if (*p++ != ',') { - break; - } - } - - if (rc) { - - /* rc == NGX_HTTP_RANGE_NOT_SATISFIABLE */ - - r->headers_out.status = rc; - r->headers_out.ranges.nelts = 0; - - if (!(content_range = ngx_list_push(&r->headers_out.headers))) { - return NGX_ERROR; - } - - r->headers_out.content_range = content_range; - - content_range->key.len = sizeof("Content-Range") - 1; - content_range->key.data = (u_char *) "Content-Range"; - - content_range->value.data = - ngx_palloc(r->pool, sizeof("bytes */") - 1 + NGX_OFF_T_LEN); - - if (content_range->value.data == NULL) { - return NGX_ERROR; - } - - content_range->value.len = ngx_sprintf(content_range->value.data, - "bytes */%O", - r->headers_out.content_length_n) - - content_range->value.data; - - r->headers_out.content_length_n = -1; - if (r->headers_out.content_length) { - r->headers_out.content_length->key.len = 0; - r->headers_out.content_length = NULL; - } - - return rc; - } - - r->headers_out.status = NGX_HTTP_PARTIAL_CONTENT; - - if (r->headers_out.ranges.nelts == 1) { - - if (!(content_range = ngx_list_push(&r->headers_out.headers))) { - return NGX_ERROR; - } - - r->headers_out.content_range = content_range; - - content_range->key.len = sizeof("Content-Range") - 1; - content_range->key.data = (u_char *) "Content-Range"; - - content_range->value.data = - ngx_palloc(r->pool, sizeof("bytes -/") - 1 + 3 * NGX_OFF_T_LEN); - if (content_range->value.data == NULL) { - return NGX_ERROR; - } - - /* "Content-Range: bytes SSSS-EEEE/TTTT" header */ - - content_range->value.len = ngx_sprintf(content_range->value.data, - "bytes %O-%O/%O", - range->start, range->end - 1, - r->headers_out.content_length_n) - - content_range->value.data; - - r->headers_out.content_length_n = range->end - range->start; - - return ngx_http_next_header_filter(r); - } - - - /* TODO: what if no content_type ?? */ - - ngx_http_create_ctx(r, ctx, ngx_http_range_body_filter_module, - sizeof(ngx_http_range_filter_ctx_t), NGX_ERROR); - - - len = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN - + sizeof(CRLF "Content-Type: ") - 1 - + r->headers_out.content_type->value.len - + sizeof(CRLF "Content-Range: bytes ") - 1; - - if (r->headers_out.charset.len) { - len += sizeof("; charset=") - 1 + r->headers_out.charset.len; - } - - if (!(ctx->boundary_header.data = ngx_palloc(r->pool, len))) { - return NGX_ERROR; - } - - boundary = ngx_next_temp_number(0); - - /* - * The boundary header of the range: - * CRLF - * "--0123456789" CRLF - * "Content-Type: image/jpeg" CRLF - * "Content-Range: bytes " - */ - - if (r->headers_out.charset.len) { - ctx->boundary_header.len = ngx_sprintf(ctx->boundary_header.data, - CRLF "--%0muA" CRLF - "Content-Type: %V; charset=%V" CRLF - "Content-Range: bytes ", - boundary, - &r->headers_out.content_type->value, - &r->headers_out.charset) - - ctx->boundary_header.data; - - r->headers_out.charset.len = 0; - - } else { - ctx->boundary_header.len = ngx_sprintf(ctx->boundary_header.data, - CRLF "--%0muA" CRLF - "Content-Type: %V" CRLF - "Content-Range: bytes ", - boundary, - &r->headers_out.content_type->value) - - ctx->boundary_header.data; - } - - r->headers_out.content_type->value.data = - ngx_palloc(r->pool, - sizeof("Content-Type: multipart/byteranges; boundary=") - 1 - + NGX_ATOMIC_T_LEN); - - if (r->headers_out.content_type->value.data == NULL) { - return NGX_ERROR; - } - - /* "Content-Type: multipart/byteranges; boundary=0123456789" */ - - r->headers_out.content_type->value.len = - ngx_sprintf(r->headers_out.content_type->value.data, - "multipart/byteranges; boundary=%0muA", - boundary) - - r->headers_out.content_type->value.data; - - - /* the size of the last boundary CRLF "--0123456789--" CRLF */ - - len = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN + sizeof("--" CRLF) - 1; - - range = r->headers_out.ranges.elts; - for (i = 0; i < r->headers_out.ranges.nelts; i++) { - - /* the size of the range: "SSSS-EEEE/TTTT" CRLF CRLF */ - - range[i].content_range.data = - ngx_palloc(r->pool, 3 * NGX_OFF_T_LEN + 2 + 4); - - if (range[i].content_range.data == NULL) { - return NGX_ERROR; - } - - range[i].content_range.len = ngx_sprintf(range[i].content_range.data, - "%O-%O/%O" CRLF CRLF, - range[i].start, range[i].end - 1, - r->headers_out.content_length_n) - - range[i].content_range.data; - - len += ctx->boundary_header.len + range[i].content_range.len - + (size_t) (range[i].end - range[i].start); - } - - r->headers_out.content_length_n = len; - r->headers_out.content_length = NULL; - - return ngx_http_next_header_filter(r); -} - - -static ngx_int_t -ngx_http_range_body_filter(ngx_http_request_t *r, ngx_chain_t *in) -{ - ngx_uint_t i; - ngx_buf_t *b; - ngx_chain_t *out, *hcl, *rcl, *dcl, **ll; - ngx_http_range_t *range; - ngx_http_range_filter_ctx_t *ctx; - - if (r->headers_out.ranges.nelts == 0) { - return ngx_http_next_body_filter(r, in); - } - - /* - * the optimized version for the static files only - * that are passed in the single file buf - */ - - if (in && in->buf->in_file && in->buf->last_buf) { - range = r->headers_out.ranges.elts; - - if (r->headers_out.ranges.nelts == 1) { - in->buf->file_pos = range->start; - in->buf->file_last = range->end; - - return ngx_http_next_body_filter(r, in); - } - - ctx = ngx_http_get_module_ctx(r, ngx_http_range_body_filter_module); - ll = &out; - - for (i = 0; i < r->headers_out.ranges.nelts; i++) { - - /* - * The boundary header of the range: - * CRLF - * "--0123456789" CRLF - * "Content-Type: image/jpeg" CRLF - * "Content-Range: bytes " - */ - - if (!(b = ngx_calloc_buf(r->pool))) { - return NGX_ERROR; - } - - b->memory = 1; - b->pos = ctx->boundary_header.data; - b->last = ctx->boundary_header.data + ctx->boundary_header.len; - - if (!(hcl = ngx_alloc_chain_link(r->pool))) { - return NGX_ERROR; - } - - hcl->buf = b; - - - /* "SSSS-EEEE/TTTT" CRLF CRLF */ - - if (!(b = ngx_calloc_buf(r->pool))) { - return NGX_ERROR; - } - - b->temporary = 1; - b->pos = range[i].content_range.data; - b->last = range[i].content_range.data + range[i].content_range.len; - - if (!(rcl = ngx_alloc_chain_link(r->pool))) { - return NGX_ERROR; - } - - rcl->buf = b; - - - /* the range data */ - - if (!(b = ngx_calloc_buf(r->pool))) { - return NGX_ERROR; - } - - b->in_file = 1; - b->file_pos = range[i].start; - b->file_last = range[i].end; - b->file = in->buf->file; - - if (!(dcl = ngx_alloc_chain_link(r->pool))) { - return NGX_ERROR; - } - - dcl->buf = b; - - *ll = hcl; - hcl->next = rcl; - rcl->next = dcl; - ll = &dcl->next; - } - - /* the last boundary CRLF "--0123456789--" CRLF */ - - if (!(b = ngx_calloc_buf(r->pool))) { - return NGX_ERROR; - } - - b->temporary = 1; - b->last_buf = 1; - - b->pos = ngx_palloc(r->pool, sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN - + sizeof("--" CRLF) - 1); - if (b->pos == NULL) { - return NGX_ERROR; - } - - b->last = ngx_cpymem(b->pos, ctx->boundary_header.data, 4 + 10); - *b->last++ = '-'; *b->last++ = '-'; - *b->last++ = CR; *b->last++ = LF; - - if (!(hcl = ngx_alloc_chain_link(r->pool))) { - return NGX_ERROR; - } - - hcl->buf = b; - hcl->next = NULL; - - *ll = hcl; - - return ngx_http_next_body_filter(r, out); - } - - /* TODO: alert */ - - return ngx_http_next_body_filter(r, in); -} - - -static ngx_int_t -ngx_http_range_header_filter_init(ngx_cycle_t *cycle) -{ - ngx_http_next_header_filter = ngx_http_top_header_filter; - ngx_http_top_header_filter = ngx_http_range_header_filter; - - return NGX_OK; -} - - -static ngx_int_t -ngx_http_range_body_filter_init(ngx_cycle_t *cycle) -{ - ngx_http_next_body_filter = ngx_http_top_body_filter; - ngx_http_top_body_filter = ngx_http_range_body_filter; - - 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 new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_range_filter_module.c @@ -0,0 +1,594 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +/* + * the single part format: + * + * "HTTP/1.0 206 Partial Content" CRLF + * ... header ... + * "Content-Type: image/jpeg" CRLF + * "Content-Length: SIZE" CRLF + * "Content-Range: bytes START-END/SIZE" CRLF + * CRLF + * ... data ... + * + * + * the mutlipart format: + * + * "HTTP/1.0 206 Partial Content" CRLF + * ... header ... + * "Content-Type: multipart/byteranges; boundary=0123456789" CRLF + * CRLF + * CRLF + * "--0123456789" CRLF + * "Content-Type: image/jpeg" CRLF + * "Content-Range: bytes START0-END0/SIZE" CRLF + * CRLF + * ... data ... + * CRLF + * "--0123456789" CRLF + * "Content-Type: image/jpeg" CRLF + * "Content-Range: bytes START1-END1/SIZE" CRLF + * CRLF + * ... data ... + * CRLF + * "--0123456789--" CRLF + */ + + +typedef struct { + ngx_str_t boundary_header; +} ngx_http_range_filter_ctx_t; + + +static ngx_int_t ngx_http_range_header_filter_init(ngx_cycle_t *cycle); +static ngx_int_t ngx_http_range_body_filter_init(ngx_cycle_t *cycle); + + +static ngx_http_module_t ngx_http_range_header_filter_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_range_header_filter_module = { + NGX_MODULE, + &ngx_http_range_header_filter_module_ctx, /* module context */ + NULL, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + ngx_http_range_header_filter_init, /* init module */ + NULL /* init process */ +}; + + +static ngx_http_module_t ngx_http_range_body_filter_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_range_body_filter_module = { + NGX_MODULE, + &ngx_http_range_body_filter_module_ctx, /* module context */ + NULL, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + ngx_http_range_body_filter_init, /* init module */ + NULL /* init process */ +}; + + +static ngx_http_output_header_filter_pt ngx_http_next_header_filter; +static ngx_http_output_body_filter_pt ngx_http_next_body_filter; + + +static ngx_int_t +ngx_http_range_header_filter(ngx_http_request_t *r) +{ + u_char *p; + size_t len; + off_t start, end; + ngx_int_t rc; + ngx_uint_t suffix, i; + ngx_atomic_uint_t boundary; + ngx_table_elt_t *content_range; + ngx_http_range_t *range; + ngx_http_range_filter_ctx_t *ctx; + + if (r->http_version < NGX_HTTP_VERSION_10 + || r->headers_out.status != NGX_HTTP_OK + || r->headers_out.content_length_n == -1 + || !r->filter_allow_ranges) + { + return ngx_http_next_header_filter(r); + } + + if (r->headers_in.range == NULL + || r->headers_in.range->value.len < 7 + || ngx_strncasecmp(r->headers_in.range->value.data, "bytes=", 6) != 0) + { + + r->headers_out.accept_ranges = ngx_list_push(&r->headers_out.headers); + if (r->headers_out.accept_ranges == NULL) { + return NGX_ERROR; + } + + r->headers_out.accept_ranges->key.len = sizeof("Accept-Ranges") - 1; + r->headers_out.accept_ranges->key.data = (u_char *) "Accept-Ranges"; + r->headers_out.accept_ranges->value.len = sizeof("bytes") - 1; + r->headers_out.accept_ranges->value.data = (u_char *) "bytes"; + + return ngx_http_next_header_filter(r); + } + + if (ngx_array_init(&r->headers_out.ranges, r->pool, 2, + sizeof(ngx_http_range_t)) == NGX_ERROR) + { + return NGX_ERROR; + } + + rc = 0; + range = NULL; + p = r->headers_in.range->value.data + 6; + + for ( ;; ) { + start = 0; + end = 0; + suffix = 0; + + while (*p == ' ') { p++; } + + if (*p != '-') { + if (*p < '0' || *p > '9') { + rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; + break; + } + + while (*p >= '0' && *p <= '9') { + start = start * 10 + *p++ - '0'; + } + + while (*p == ' ') { p++; } + + if (*p++ != '-') { + rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; + break; + } + + if (start >= r->headers_out.content_length_n) { + rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; + break; + } + + while (*p == ' ') { p++; } + + if (*p == ',' || *p == '\0') { + range = ngx_array_push(&r->headers_out.ranges); + if (range == NULL) { + return NGX_ERROR; + } + + range->start = start; + range->end = r->headers_out.content_length_n; + + if (*p++ != ',') { + break; + } + + continue; + } + + } else { + suffix = 1; + p++; + } + + if (*p < '0' || *p > '9') { + rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; + break; + } + + while (*p >= '0' && *p <= '9') { + end = end * 10 + *p++ - '0'; + } + + while (*p == ' ') { p++; } + + if (*p != ',' && *p != '\0') { + rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; + break; + } + + if (suffix) { + start = r->headers_out.content_length_n - end; + end = r->headers_out.content_length_n - 1; + } + + if (start > end) { + rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; + break; + } + + range = ngx_array_push(&r->headers_out.ranges); + if (range == NULL) { + return NGX_ERROR; + } + + range->start = start; + + if (end >= r->headers_out.content_length_n) { + /* + * Download Accelerator sends the last byte position + * that equals to the file length + */ + range->end = r->headers_out.content_length_n; + + } else { + range->end = end + 1; + } + + if (*p++ != ',') { + break; + } + } + + if (rc) { + + /* rc == NGX_HTTP_RANGE_NOT_SATISFIABLE */ + + r->headers_out.status = rc; + r->headers_out.ranges.nelts = 0; + + content_range = ngx_list_push(&r->headers_out.headers); + if (content_range == NULL) { + return NGX_ERROR; + } + + r->headers_out.content_range = content_range; + + content_range->key.len = sizeof("Content-Range") - 1; + content_range->key.data = (u_char *) "Content-Range"; + + content_range->value.data = ngx_palloc(r->pool, + sizeof("bytes */") - 1 + NGX_OFF_T_LEN); + if (content_range->value.data == NULL) { + return NGX_ERROR; + } + + content_range->value.len = ngx_sprintf(content_range->value.data, + "bytes */%O", + r->headers_out.content_length_n) + - content_range->value.data; + + r->headers_out.content_length_n = -1; + if (r->headers_out.content_length) { + r->headers_out.content_length->key.len = 0; + r->headers_out.content_length = NULL; + } + + return rc; + } + + r->headers_out.status = NGX_HTTP_PARTIAL_CONTENT; + + if (r->headers_out.ranges.nelts == 1) { + + content_range = ngx_list_push(&r->headers_out.headers); + if (content_range == NULL) { + return NGX_ERROR; + } + + r->headers_out.content_range = content_range; + + content_range->key.len = sizeof("Content-Range") - 1; + content_range->key.data = (u_char *) "Content-Range"; + + content_range->value.data = + ngx_palloc(r->pool, sizeof("bytes -/") - 1 + 3 * NGX_OFF_T_LEN); + if (content_range->value.data == NULL) { + return NGX_ERROR; + } + + /* "Content-Range: bytes SSSS-EEEE/TTTT" header */ + + content_range->value.len = ngx_sprintf(content_range->value.data, + "bytes %O-%O/%O", + range->start, range->end - 1, + r->headers_out.content_length_n) + - content_range->value.data; + + r->headers_out.content_length_n = range->end - range->start; + + return ngx_http_next_header_filter(r); + } + + + /* TODO: what if no content_type ?? */ + + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_range_filter_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module); + + + len = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN + + sizeof(CRLF "Content-Type: ") - 1 + + r->headers_out.content_type->value.len + + sizeof(CRLF "Content-Range: bytes ") - 1; + + if (r->headers_out.charset.len) { + len += sizeof("; charset=") - 1 + r->headers_out.charset.len; + } + + ctx->boundary_header.data = ngx_palloc(r->pool, len); + if (ctx->boundary_header.data == NULL) { + return NGX_ERROR; + } + + boundary = ngx_next_temp_number(0); + + /* + * The boundary header of the range: + * CRLF + * "--0123456789" CRLF + * "Content-Type: image/jpeg" CRLF + * "Content-Range: bytes " + */ + + if (r->headers_out.charset.len) { + ctx->boundary_header.len = ngx_sprintf(ctx->boundary_header.data, + CRLF "--%0muA" CRLF + "Content-Type: %V; charset=%V" CRLF + "Content-Range: bytes ", + boundary, + &r->headers_out.content_type->value, + &r->headers_out.charset) + - ctx->boundary_header.data; + + r->headers_out.charset.len = 0; + + } else { + ctx->boundary_header.len = ngx_sprintf(ctx->boundary_header.data, + CRLF "--%0muA" CRLF + "Content-Type: %V" CRLF + "Content-Range: bytes ", + boundary, + &r->headers_out.content_type->value) + - ctx->boundary_header.data; + } + + r->headers_out.content_type->value.data = + ngx_palloc(r->pool, + sizeof("Content-Type: multipart/byteranges; boundary=") - 1 + + NGX_ATOMIC_T_LEN); + + if (r->headers_out.content_type->value.data == NULL) { + return NGX_ERROR; + } + + /* "Content-Type: multipart/byteranges; boundary=0123456789" */ + + r->headers_out.content_type->value.len = + ngx_sprintf(r->headers_out.content_type->value.data, + "multipart/byteranges; boundary=%0muA", + boundary) + - r->headers_out.content_type->value.data; + + + /* the size of the last boundary CRLF "--0123456789--" CRLF */ + + len = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN + sizeof("--" CRLF) - 1; + + range = r->headers_out.ranges.elts; + for (i = 0; i < r->headers_out.ranges.nelts; i++) { + + /* the size of the range: "SSSS-EEEE/TTTT" CRLF CRLF */ + + range[i].content_range.data = + ngx_palloc(r->pool, 3 * NGX_OFF_T_LEN + 2 + 4); + + if (range[i].content_range.data == NULL) { + return NGX_ERROR; + } + + range[i].content_range.len = ngx_sprintf(range[i].content_range.data, + "%O-%O/%O" CRLF CRLF, + range[i].start, range[i].end - 1, + r->headers_out.content_length_n) + - range[i].content_range.data; + + len += ctx->boundary_header.len + range[i].content_range.len + + (size_t) (range[i].end - range[i].start); + } + + r->headers_out.content_length_n = len; + r->headers_out.content_length = NULL; + + return ngx_http_next_header_filter(r); +} + + +static ngx_int_t +ngx_http_range_body_filter(ngx_http_request_t *r, ngx_chain_t *in) +{ + ngx_uint_t i; + ngx_buf_t *b; + ngx_chain_t *out, *hcl, *rcl, *dcl, **ll; + ngx_http_range_t *range; + ngx_http_range_filter_ctx_t *ctx; + + if (r->headers_out.ranges.nelts == 0) { + return ngx_http_next_body_filter(r, in); + } + + /* + * the optimized version for the static files only + * that are passed in the single file buf + */ + + if (in && in->buf->in_file && in->buf->last_buf) { + range = r->headers_out.ranges.elts; + + if (r->headers_out.ranges.nelts == 1) { + in->buf->file_pos = range->start; + in->buf->file_last = range->end; + + return ngx_http_next_body_filter(r, in); + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_range_body_filter_module); + ll = &out; + + for (i = 0; i < r->headers_out.ranges.nelts; i++) { + + /* + * The boundary header of the range: + * CRLF + * "--0123456789" CRLF + * "Content-Type: image/jpeg" CRLF + * "Content-Range: bytes " + */ + + b = ngx_calloc_buf(r->pool); + if (b == NULL) { + return NGX_ERROR; + } + + b->memory = 1; + b->pos = ctx->boundary_header.data; + b->last = ctx->boundary_header.data + ctx->boundary_header.len; + + hcl = ngx_alloc_chain_link(r->pool); + if (hcl == NULL) { + return NGX_ERROR; + } + + hcl->buf = b; + + + /* "SSSS-EEEE/TTTT" CRLF CRLF */ + + b = ngx_calloc_buf(r->pool); + if (b == NULL) { + return NGX_ERROR; + } + + b->temporary = 1; + b->pos = range[i].content_range.data; + b->last = range[i].content_range.data + range[i].content_range.len; + + rcl = ngx_alloc_chain_link(r->pool); + if (rcl == NULL) { + return NGX_ERROR; + } + + rcl->buf = b; + + + /* the range data */ + + b = ngx_calloc_buf(r->pool); + if (b == NULL) { + return NGX_ERROR; + } + + b->in_file = 1; + b->file_pos = range[i].start; + b->file_last = range[i].end; + b->file = in->buf->file; + + dcl = ngx_alloc_chain_link(r->pool); + if (dcl == NULL) { + return NGX_ERROR; + } + + dcl->buf = b; + + *ll = hcl; + hcl->next = rcl; + rcl->next = dcl; + ll = &dcl->next; + } + + /* the last boundary CRLF "--0123456789--" CRLF */ + + b = ngx_calloc_buf(r->pool); + if (b == NULL) { + return NGX_ERROR; + } + + b->temporary = 1; + b->last_buf = 1; + + b->pos = ngx_palloc(r->pool, sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN + + sizeof("--" CRLF) - 1); + if (b->pos == NULL) { + return NGX_ERROR; + } + + b->last = ngx_cpymem(b->pos, ctx->boundary_header.data, 4 + 10); + *b->last++ = '-'; *b->last++ = '-'; + *b->last++ = CR; *b->last++ = LF; + + hcl = ngx_alloc_chain_link(r->pool); + if (hcl == NULL) { + return NGX_ERROR; + } + + hcl->buf = b; + hcl->next = NULL; + + *ll = hcl; + + return ngx_http_next_body_filter(r, out); + } + + /* TODO: alert */ + + return ngx_http_next_body_filter(r, in); +} + + +static ngx_int_t +ngx_http_range_header_filter_init(ngx_cycle_t *cycle) +{ + ngx_http_next_header_filter = ngx_http_top_header_filter; + ngx_http_top_header_filter = ngx_http_range_header_filter; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_range_body_filter_init(ngx_cycle_t *cycle) +{ + ngx_http_next_body_filter = ngx_http_top_body_filter; + ngx_http_top_body_filter = ngx_http_range_body_filter; + + return NGX_OK; +} diff --git a/src/http/modules/ngx_http_rewrite_handler.c b/src/http/modules/ngx_http_rewrite_handler.c deleted file mode 100644 --- a/src/http/modules/ngx_http_rewrite_handler.c +++ /dev/null @@ -1,1313 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#include -#include -#include - - -typedef struct ngx_http_rewrite_engine_s ngx_http_rewrite_engine_t; - -typedef void (*ngx_http_rewrite_code_pt) (ngx_http_rewrite_engine_t *e); - - -typedef struct { - ngx_str_t name; - ngx_uint_t wildcard; -} ngx_http_rewrite_referer_t; - - -typedef struct { - ngx_array_t *codes; /* uintptr_t */ - ngx_array_t *referers; /* ngx_http_rewrite_referer_t */ - - ngx_uint_t max_captures; - ngx_uint_t stack_size; - - ngx_flag_t log; - - ngx_flag_t no_referer; -} ngx_http_rewrite_loc_conf_t; - - -typedef struct { - ngx_http_rewrite_code_pt code; - ngx_regex_t *regex; - uintptr_t size; - uintptr_t ncaptures; - uintptr_t status; - uintptr_t next; - - uintptr_t uri:1; - - /* add the r->args to the new arguments */ - uintptr_t args:1; - - uintptr_t redirect:1; - uintptr_t break_cycle:1; - - ngx_str_t name; -} ngx_http_rewrite_regex_code_t; - - -typedef struct { - ngx_http_rewrite_code_pt code; - - uintptr_t uri:1; - - /* add the r->args to the new arguments */ - uintptr_t args:1; - - uintptr_t redirect:1; -} ngx_http_rewrite_regex_end_code_t; - -typedef struct { - ngx_http_rewrite_code_pt code; - uintptr_t n; -} ngx_http_rewrite_copy_capture_code_t; - - -typedef struct { - ngx_http_rewrite_code_pt code; - uintptr_t len; -} ngx_http_rewrite_copy_code_t; - - -typedef struct { - ngx_http_rewrite_code_pt code; - uintptr_t status; - uintptr_t null; -} ngx_http_rewrite_return_code_t; - - -typedef struct { - ngx_http_rewrite_code_pt code; - uintptr_t next; - void **loc_conf; -} ngx_http_rewrite_if_code_t; - - -typedef struct { - ngx_http_rewrite_code_pt code; - uintptr_t index; -} ngx_http_rewrite_var_code_t; - - -struct ngx_http_rewrite_engine_s { - u_char *ip; - uintptr_t *sp; - - ngx_str_t buf; - ngx_str_t *line; - - u_char *pos; - - /* the start of the rewritten arguments */ - u_char *args; - - unsigned quote:1; - - ngx_int_t status; - - int *captures; - - ngx_http_request_t *request; - ngx_http_rewrite_loc_conf_t *conf; -}; - - -static ngx_int_t ngx_http_rewrite_init(ngx_cycle_t *cycle); -static void *ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf); -static char *ngx_http_rewrite_merge_loc_conf(ngx_conf_t *cf, - void *parent, void *child); -static char *ngx_http_rewrite(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -static char *ngx_http_rewrite_return(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); -static char *ngx_http_rewrite_if(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); -static char *ngx_http_rewrite_valid_referers(ngx_conf_t *cf, - ngx_command_t *cmd, void *conf); -static void *ngx_http_rewrite_start_code(ngx_pool_t *pool, - ngx_array_t **codes, size_t size); -static void *ngx_http_rewrite_add_code(ngx_array_t *codes, size_t size, - void *code); - - -static ngx_command_t ngx_http_rewrite_commands[] = { - - { ngx_string("rewrite"), - NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF - |NGX_CONF_TAKE23, - ngx_http_rewrite, - NGX_HTTP_LOC_CONF_OFFSET, - 0, - NULL }, - - { ngx_string("return"), - NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF - |NGX_CONF_TAKE1, - ngx_http_rewrite_return, - NGX_HTTP_LOC_CONF_OFFSET, - 0, - NULL }, - - { ngx_string("if"), - NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_BLOCK|NGX_CONF_1MORE, - ngx_http_rewrite_if, - NGX_HTTP_LOC_CONF_OFFSET, - 0, - NULL }, - - { ngx_string("valid_referers"), - NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, - ngx_http_rewrite_valid_referers, - NGX_HTTP_LOC_CONF_OFFSET, - 0, - NULL }, - - { ngx_string("rewrite_log"), - NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF - |NGX_CONF_TAKE1, - ngx_conf_set_flag_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_rewrite_loc_conf_t, log), - NULL }, - - ngx_null_command -}; - - -ngx_http_module_t ngx_http_rewrite_module_ctx = { - NULL, /* pre conf */ - - NULL, /* create main configuration */ - NULL, /* init main configuration */ - - NULL, /* create server configuration */ - NULL, /* merge server configuration */ - - ngx_http_rewrite_create_loc_conf, /* create location configration */ - ngx_http_rewrite_merge_loc_conf /* merge location configration */ -}; - - -ngx_module_t ngx_http_rewrite_module = { - NGX_MODULE, - &ngx_http_rewrite_module_ctx, /* module context */ - ngx_http_rewrite_commands, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - ngx_http_rewrite_init, /* init module */ - NULL /* init process */ -}; - - -#define ngx_http_rewrite_exit (u_char *) &ngx_http_rewrite_exit_code - -uintptr_t ngx_http_rewrite_exit_code = (uintptr_t) NULL; - - -static ngx_int_t -ngx_http_rewrite_handler(ngx_http_request_t *r) -{ - ngx_http_rewrite_code_pt code; - ngx_http_rewrite_engine_t *e; - ngx_http_rewrite_loc_conf_t *cf; - - cf = ngx_http_get_module_loc_conf(r, ngx_http_rewrite_module); - - if (cf->codes == NULL) { - return NGX_DECLINED; - } - - if (!(e = ngx_palloc(r->pool, sizeof(ngx_http_rewrite_engine_t)))) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - e->sp = ngx_palloc(r->pool, cf->stack_size * sizeof(ngx_int_t)); - if (e->sp == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - if (cf->max_captures) { - e->captures = ngx_palloc(r->pool, cf->max_captures * sizeof(int)); - if (e->captures == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - } else { - e->captures = NULL; - } - - e->ip = cf->codes->elts; - e->buf.len = 0; - e->buf.data = NULL; - e->line = NULL; - e->pos = NULL; - e->args = NULL; - e->quote = 1; - e->status = NGX_DECLINED; - e->request = r; - e->conf = cf; - - while (*(uintptr_t *) e->ip) { - code = *(ngx_http_rewrite_code_pt *) e->ip; - code(e); - } - - return e->status; -} - - -static void -ngx_http_rewrite_regex_start_code(ngx_http_rewrite_engine_t *e) -{ - ngx_int_t rc; - ngx_uint_t n; - ngx_http_request_t *r; - ngx_http_rewrite_regex_code_t *code; - - code = (ngx_http_rewrite_regex_code_t *) e->ip; - - r = e->request; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http rewrite start: \"%V\"", &code->name); - - if (code->uri) { - e->line = &r->uri; - } else { - e->line = *(ngx_str_t **) e->sp--; - } - - rc = ngx_regex_exec(code->regex, e->line, e->captures, code->ncaptures); - - if (rc == NGX_REGEX_NO_MATCHED) { - if (e->conf->log) { - ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0, - "\"%V\" does not match \"%V\"", &code->name, e->line); - } - - e->ip += code->next; - return; - } - - if (rc < 0) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - ngx_regex_exec_n " failed: %d on \"%V\" using \"%V\"", - rc, e->line, &code->name); - - e->ip = ngx_http_rewrite_exit; - e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; - return; - } - - if (e->conf->log) { - ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0, - "\"%V\" matches \"%V\"", &code->name, e->line); - } - - if (code->status) { - e->status = code->status; - - if (!code->redirect) { - e->ip = ngx_http_rewrite_exit; - return; - } - } - - e->buf.len = code->size; - - if (code->uri) { - if (!code->break_cycle) { - r->uri_changed = 1; - } - - if (rc && (r->quoted_uri || r->plus_in_uri)) { - e->buf.len += 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len, - NGX_ESCAPE_ARGS); - } - } - - for (n = 1; n < (ngx_uint_t) rc; n++) { - e->buf.len += e->captures[2 * n + 1] - e->captures[2 * n]; - } - - if (code->args && r->args.len) { - e->buf.len += r->args.len + 1; - } - - if (!(e->buf.data = ngx_palloc(r->pool, e->buf.len))) { - e->ip = ngx_http_rewrite_exit; - e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; - return; - } - - e->quote = code->redirect; - - e->pos = e->buf.data; - - e->ip += sizeof(ngx_http_rewrite_regex_code_t); -} - - -static void -ngx_http_rewrite_regex_end_code(ngx_http_rewrite_engine_t *e) -{ - ngx_http_request_t *r; - ngx_http_rewrite_regex_end_code_t *code; - - code = (ngx_http_rewrite_regex_end_code_t *) e->ip; - - r = e->request; - - e->quote = 0; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http rewrite end"); - - if (e->args) { - e->buf.len = e->args - e->buf.data; - - if (code->args && r->args.len) { - *e->pos++ = '&'; - e->pos = ngx_cpymem(e->pos, r->args.data, r->args.len); - } - - r->args.len = e->pos - e->args; - r->args.data = e->args; - - e->args = NULL; - - } else { - if (code->args && r->args.len) { - *e->pos++ = '?'; - e->pos = ngx_cpymem(e->pos, r->args.data, r->args.len); - } - - e->buf.len = e->pos - e->buf.data; - } - - if (!code->redirect) { - if (e->conf->log) { - ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0, - "rewritten data: \"%V\", args: \"%V\"", - &e->buf, &r->args); - } - - if (code->uri) { - r->uri = e->buf; - - if (ngx_http_set_exten(r) != NGX_OK) { - e->ip = ngx_http_rewrite_exit; - e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; - return; - } - } - - e->ip += sizeof(ngx_http_rewrite_regex_end_code_t); - return; - } - - ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0, - "rewritten redirect: \"%V\"", &e->buf); - - if (!(r->headers_out.location = ngx_list_push(&r->headers_out.headers))) { - e->ip = ngx_http_rewrite_exit; - e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; - return; - } - - if (e->buf.data[0] != '/') { - r->headers_out.location->key.len = sizeof("Location") - 1; - r->headers_out.location->key.data = (u_char *) "Location"; - } - - r->headers_out.location->value = e->buf; - - e->ip += sizeof(ngx_http_rewrite_regex_end_code_t); -} - - -static void -ngx_http_rewrite_copy_capture_code(ngx_http_rewrite_engine_t *e) -{ - ngx_http_rewrite_copy_capture_code_t *code; - - code = (ngx_http_rewrite_copy_capture_code_t *) e->ip; - - e->ip += sizeof(ngx_http_rewrite_copy_capture_code_t); - - if ((e->args || e->quote) - && (e->request->quoted_uri || e->request->plus_in_uri)) - { - e->pos = (u_char *) ngx_escape_uri(e->pos, - &e->line->data[e->captures[code->n]], - e->captures[code->n + 1] - e->captures[code->n], - NGX_ESCAPE_ARGS); - } else { - e->pos = ngx_cpymem(e->pos, &e->line->data[e->captures[code->n]], - e->captures[code->n + 1] - e->captures[code->n]); - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, - "http rewrite capture: \"%V\"", &e->buf); -} - - -static void -ngx_http_rewrite_copy_code(ngx_http_rewrite_engine_t *e) -{ - ngx_http_rewrite_copy_code_t *code; - - code = (ngx_http_rewrite_copy_code_t *) e->ip; - - e->pos = ngx_cpymem(e->pos, e->ip + sizeof(ngx_http_rewrite_copy_code_t), - code->len); - - e->ip += sizeof(ngx_http_rewrite_copy_code_t) - + ((code->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1)); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, - "http rewrite copy: \"%V\"", &e->buf); -} - - -static void -ngx_http_rewrite_start_args_code(ngx_http_rewrite_engine_t *e) -{ - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, - "http rewrite args"); - - e->args = e->pos; - e->ip += sizeof(uintptr_t); -} - - -static void -ngx_http_rewrite_return_code(ngx_http_rewrite_engine_t *e) -{ - ngx_http_rewrite_return_code_t *code; - - code = (ngx_http_rewrite_return_code_t *) e->ip; - - e->status = code->status; - - e->ip += sizeof(ngx_http_rewrite_return_code_t) - sizeof(uintptr_t); -} - - -static void -ngx_http_rewrite_if_code(ngx_http_rewrite_engine_t *e) -{ - ngx_http_rewrite_if_code_t *code; - - code = (ngx_http_rewrite_if_code_t *) e->ip; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, - "http rewrite if"); - - if (*e->sp--) { - if (code->loc_conf) { - e->request->loc_conf = code->loc_conf; - } - - e->ip += sizeof(ngx_http_rewrite_if_code_t); - return; - } - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, - "http rewrite if false"); - - e->ip += code->next; -} - - -static void -ngx_http_rewrite_var_code(ngx_http_rewrite_engine_t *e) -{ - ngx_http_variable_value_t *value; - ngx_http_rewrite_var_code_t *code; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, - "http rewrite var"); - - code = (ngx_http_rewrite_var_code_t *) e->ip; - - e->sp++; - - e->ip += sizeof(ngx_http_rewrite_var_code_t); - - if (!(value = ngx_http_get_indexed_variable(e->request, code->index))) { - *e->sp = (uintptr_t) 0; - return; - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, - "http rewrite var: %p", value->value); - - *e->sp = value->value; -} - - -static void -ngx_http_rewrite_invalid_referer_code(ngx_http_rewrite_engine_t *e) -{ - u_char *ref; - size_t len; - ngx_uint_t i, n; - ngx_http_request_t *r; - ngx_http_rewrite_referer_t *refs; - ngx_http_rewrite_loc_conf_t *cf; - - r = e->request; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http rewrite invalid referer"); - - cf = ngx_http_get_module_loc_conf(r, ngx_http_rewrite_module); - - e->sp++; - e->ip += sizeof(uintptr_t); - - if (cf->referers == NULL) { - *e->sp = (uintptr_t) 0; - return; - } - - if (r->headers_in.referer == NULL) { - if (cf->no_referer) { - *e->sp = (uintptr_t) 0; - return; - } else { - *e->sp = (uintptr_t) 1; - return; - } - } - - len = r->headers_in.referer->value.len; - ref = r->headers_in.referer->value.data; - - if (len < sizeof("http://i.ru") - 1 - || (ngx_strncasecmp(ref, "http://", 7) != 0)) - { - *e->sp = (uintptr_t) 1; - return; - } - - len -= 7; - ref += 7; - - refs = cf->referers->elts; - for (i = 0; i < cf->referers->nelts; i++ ){ - - if (refs[i].name.len > len) { - continue; - } - - if (refs[i].wildcard) { - for (n = 0; n < len; n++) { - if (ref[n] == '/' || ref[n] == ':') { - break; - } - - if (ref[n] != '.') { - continue; - } - - if (ngx_strncmp(&ref[n], refs[i].name.data, - refs[i].name.len) == 0) - { - *e->sp = (uintptr_t) 0; - return; - } - } - - } else { - if (ngx_strncasecmp(refs[i].name.data, ref, refs[i].name.len) == 0) - { - *e->sp = (uintptr_t) 0; - return; - } - } - } - - *e->sp = (uintptr_t) 1; -} - - -static void -ngx_http_rewrite_nop_code(ngx_http_rewrite_engine_t *e) -{ - e->ip += sizeof(uintptr_t); -} - - -static ngx_int_t -ngx_http_rewrite_init(ngx_cycle_t *cycle) -{ - ngx_http_handler_pt *h; - ngx_http_core_main_conf_t *cmcf; - - cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module); - - h = ngx_push_array(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers); - if (h == NULL) { - return NGX_ERROR; - } - - *h = ngx_http_rewrite_handler; - - return NGX_OK; -} - - -static void * -ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf) -{ - ngx_http_rewrite_loc_conf_t *conf; - - if (!(conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_rewrite_loc_conf_t)))) { - return NGX_CONF_ERROR; - } - - conf->stack_size = NGX_CONF_UNSET_UINT; - conf->log = NGX_CONF_UNSET; - conf->no_referer = NGX_CONF_UNSET; - - return conf; -} - - -static char * -ngx_http_rewrite_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) -{ - ngx_http_rewrite_loc_conf_t *prev = parent; - ngx_http_rewrite_loc_conf_t *conf = child; - - uintptr_t *code, *last; - ngx_http_rewrite_regex_code_t *regex; - - ngx_conf_merge_value(conf->log, prev->log, 0); - ngx_conf_merge_unsigned_value(conf->stack_size, prev->stack_size, 10); - - if (conf->referers == NULL) { - conf->referers = prev->referers; - ngx_conf_merge_value(conf->no_referer, prev->no_referer, 0); - } - - if (conf->no_referer == NGX_CONF_UNSET) { - conf->no_referer = 0; - } - - if (conf->codes == NULL) { - return NGX_CONF_OK; - } - - if (conf->codes == prev->codes) { - return NGX_CONF_OK; - } - - code = conf->codes->elts; - last = (uintptr_t *) ((u_char *) code + conf->codes->nelts); - - while (code < last) { - if (*code == (uintptr_t) NULL) { - return NGX_CONF_OK; - } - - if (*code == (uintptr_t) &ngx_http_rewrite_regex_start_code) { - regex = (ngx_http_rewrite_regex_code_t *) code; - if (conf->max_captures < regex->ncaptures) { - conf->max_captures = regex->ncaptures; - } - code = (uintptr_t *) ((u_char *) code + regex->next); - } - - if (*code == (uintptr_t) &ngx_http_rewrite_if_code) { - code += sizeof(ngx_http_rewrite_if_code_t) / sizeof(uintptr_t); - } - - if (*code == (uintptr_t) &ngx_http_rewrite_return_code) { - code += sizeof(ngx_http_rewrite_return_code_t) / sizeof(uintptr_t); - } - - if (*code == (uintptr_t) &ngx_http_rewrite_var_code) { - code += sizeof(ngx_http_rewrite_var_code_t) / sizeof(uintptr_t); - } - - if (*code == (uintptr_t) &ngx_http_rewrite_invalid_referer_code) { - code++; - } - - if (*code == (uintptr_t) &ngx_http_rewrite_nop_code) { - code++; - } - } - - if (!(code = ngx_array_push_n(conf->codes, sizeof(uintptr_t)))) { - return NGX_CONF_ERROR; - } - - *code = (uintptr_t) NULL; - - return NGX_CONF_OK; -} - - -static char * -ngx_http_rewrite(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_http_rewrite_loc_conf_t *lcf = conf; - - u_char *data; - size_t len, size; - ngx_str_t *value, err; - ngx_uint_t i, n, last; - ngx_http_rewrite_code_pt *code; - ngx_http_rewrite_copy_code_t *copy; - ngx_http_rewrite_regex_code_t *regex; - ngx_http_rewrite_regex_end_code_t *regex_end; - ngx_http_rewrite_copy_capture_code_t *copy_capture; - u_char errstr[NGX_MAX_CONF_ERRSTR]; - - regex = ngx_http_rewrite_start_code(cf->pool, &lcf->codes, - sizeof(ngx_http_rewrite_regex_code_t)); - if (regex == NULL) { - return NGX_CONF_ERROR; - } - - value = cf->args->elts; - - err.len = NGX_MAX_CONF_ERRSTR; - err.data = errstr; - - /* TODO: NGX_REGEX_CASELESS */ - - regex->regex = ngx_regex_compile(&value[1], 0, cf->pool, &err); - - if (regex->regex == NULL) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data); - return NGX_CONF_ERROR; - } - - regex->code = ngx_http_rewrite_regex_start_code; - regex->size = 0; - regex->ncaptures = 0; - regex->status = 0; - regex->uri = 1; - regex->args = 1; - regex->redirect = 0; - regex->name = value[1]; - - last = 0; - - if (ngx_strncmp(value[2].data, "http://", sizeof("http://") - 1) == 0) { - regex->status = NGX_HTTP_MOVED_TEMPORARILY; - regex->redirect = 1; - last = 1; - } - - if (cf->args->nelts == 4) { - if (ngx_strcmp(value[3].data, "last") == 0) { - last = 1; - - } else if (ngx_strcmp(value[3].data, "break") == 0) { - regex->break_cycle = 1; - last = 1; - - } else if (ngx_strcmp(value[3].data, "redirect") == 0) { - regex->status = NGX_HTTP_MOVED_TEMPORARILY; - regex->redirect = 1; - last = 1; - - } else if (ngx_strcmp(value[3].data, "permanent") == 0) { - regex->status = NGX_HTTP_MOVED_PERMANENTLY; - regex->redirect = 1; - last = 1; - - } else { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid parameter \"%V\"", &value[3]); - return NGX_CONF_ERROR; - } - } - - i = 0; - - while (i < value[2].len) { - - data = &value[2].data[i]; - - if (value[2].data[i] == '$' && i < value[2].len - && value[2].data[i + 1] >= '1' && value[2].data[i + 1] <= '9') - { - - /* the "$1" - "$9" captures */ - - copy_capture = ngx_http_rewrite_add_code(lcf->codes, - sizeof(ngx_http_rewrite_copy_capture_code_t), - ®ex); - if (copy_capture == NULL) { - return NGX_CONF_ERROR; - } - - i++; - - copy_capture->code = ngx_http_rewrite_copy_capture_code; - copy_capture->n = value[2].data[i] - '0'; - - if (regex->ncaptures < copy_capture->n) { - regex->ncaptures = copy_capture->n; - } - - copy_capture->n *= 2; - - i++; - - continue; - } - - if (value[2].data[i] == '?') { - - /* the arguments */ - - if (i == value[2].len - 1) { - /* the last "?" drops the original arguments */ - regex->args = 0; - break; - } - - if (!regex->redirect) { - code = ngx_http_rewrite_add_code(lcf->codes, sizeof(uintptr_t), - ®ex); - if (code == NULL) { - return NGX_CONF_ERROR; - } - - *code = ngx_http_rewrite_start_args_code; - - i++; - - continue; - } - } - - i++; - - /* the substituion strings */ - - while (i < value[2].len && value[2].data[i] != '$') { - - if (value[2].data[i] == '?') { - - if (i == value[2].len - 1) { - /* - * the last "?" drops the original arguments, - * and it should not be copied to a substituion - */ - regex->args = 0; - break; - } - - if (!regex->redirect) { - break; - } - } - - i++; - } - - len = &value[2].data[i] - data; - - if (len == 0) { - continue; - } - - regex->size += len; - - size = (len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1); - - copy = ngx_http_rewrite_add_code(lcf->codes, - sizeof(ngx_http_rewrite_copy_code_t) + size, - ®ex); - if (copy == NULL) { - return NGX_CONF_ERROR; - } - - copy->code = ngx_http_rewrite_copy_code; - copy->len = len; - - ngx_memcpy((u_char *) copy + sizeof(ngx_http_rewrite_copy_code_t), - data, len); - } - - n = ngx_regex_capture_count(regex->regex); - - if (regex->ncaptures > n) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "pattern \"%V\" has less captures " - "than referrenced in substitution \"%V\"", - &value[1], &value[2]); - return NGX_CONF_ERROR; - } - - if (regex->ncaptures < n) { - regex->ncaptures = n; - } - - if (regex->ncaptures) { - regex->ncaptures = (regex->ncaptures + 1) * 3; - } - - regex_end = ngx_http_rewrite_add_code(lcf->codes, - sizeof(ngx_http_rewrite_regex_end_code_t), - ®ex); - if (regex_end == NULL) { - return NGX_CONF_ERROR; - } - - regex_end->code = ngx_http_rewrite_regex_end_code; - regex_end->uri = regex->uri; - regex_end->args = regex->args; - regex_end->redirect = regex->redirect; - - if (last) { - code = ngx_http_rewrite_add_code(lcf->codes, sizeof(uintptr_t), - ®ex); - if (code == NULL) { - return NGX_CONF_ERROR; - } - - *code = (uintptr_t) NULL; - } - - regex->next = (u_char *) lcf->codes->elts + lcf->codes->nelts - - (u_char *) regex; - - return NGX_CONF_OK; -} - - -static char * -ngx_http_rewrite_return(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_http_rewrite_loc_conf_t *lcf = conf; - - ngx_str_t *value; - ngx_http_rewrite_return_code_t *ret; - - ret = ngx_http_rewrite_start_code(cf->pool, &lcf->codes, - sizeof(ngx_http_rewrite_return_code_t)); - if (ret == NULL) { - return NGX_CONF_ERROR; - } - - value = cf->args->elts; - - ret->code = ngx_http_rewrite_return_code; - ret->null = (uintptr_t) NULL; - - ret->status = ngx_atoi(value[1].data, value[1].len); - - if (ret->status == (uintptr_t) NGX_ERROR) { - return NGX_CONF_ERROR; - } - - return NGX_CONF_OK; -} - - -static char * -ngx_http_rewrite_if(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_http_rewrite_loc_conf_t *lcf = conf; - - void *mconf; - char *rv; - u_char *elts; - ngx_str_t *value; - ngx_int_t index; - ngx_uint_t i; - ngx_conf_t save; - ngx_http_rewrite_code_pt *code; - ngx_http_module_t *module; - ngx_http_conf_ctx_t *ctx, *pctx; - ngx_http_core_loc_conf_t *clcf, *pclcf, **clcfp; - ngx_http_core_main_conf_t *cmcf; - ngx_http_rewrite_if_code_t *if_code; - ngx_http_rewrite_var_code_t *var_code; - ngx_http_rewrite_loc_conf_t *nlcf; - - if (!(ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)))) { - return NGX_CONF_ERROR; - } - - pctx = cf->ctx; - ctx->main_conf = pctx->main_conf; - ctx->srv_conf = pctx->srv_conf; - - ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module); - if (ctx->loc_conf == NULL) { - return NGX_CONF_ERROR; - } - - for (i = 0; ngx_modules[i]; i++) { - if (ngx_modules[i]->type != NGX_HTTP_MODULE) { - continue; - } - - module = ngx_modules[i]->ctx; - - if (module->create_loc_conf) { - - if (!(mconf = module->create_loc_conf(cf))) { - return NGX_CONF_ERROR; - } - - ctx->loc_conf[ngx_modules[i]->ctx_index] = mconf; - } - } - - pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index]; - - clcf = ctx->loc_conf[ngx_http_core_module.ctx_index]; - clcf->loc_conf = ctx->loc_conf; - clcf->name = pclcf->name; - clcf->noname = 1; - - if (pclcf->locations.elts == NULL) { - if (ngx_array_init(&pclcf->locations, cf->pool, 4, sizeof(void *)) - == NGX_ERROR) - { - return NGX_CONF_ERROR; - } - } - - if (!(clcfp = ngx_push_array(&pclcf->locations))) { - return NGX_CONF_ERROR; - } - - *clcfp = clcf; - - - /* STUB: "if ($var)" */ - - value = cf->args->elts; - - if (value[1].len < 2 - || value[1].data[0] != '(' - || value[1].data[1] != '$' - || value[1].data[value[1].len - 1] != ')') - { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid condition \"%V\"", &value[1]); - return NGX_CONF_ERROR; - } - - value[1].len -= 3; - value[1].data += 2; - - if (value[1].len == sizeof("invalid_referer") - 1 - && ngx_strncmp(value[1].data, "invalid_referer", - sizeof("invalid_referer") - 1) == 0) - { - code = ngx_http_rewrite_start_code(cf->pool, &lcf->codes, - sizeof(ngx_http_rewrite_code_pt)); - if (code == NULL) { - return NGX_CONF_ERROR; - } - - *code = ngx_http_rewrite_invalid_referer_code; - - } else { - cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); - - index = ngx_http_get_variable_index(cmcf, &value[1]); - - if (index == -1) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "unknown variable name \"%V\"", &value[1]); - return NGX_CONF_ERROR; - } - - var_code = ngx_http_rewrite_start_code(cf->pool, &lcf->codes, - sizeof(ngx_http_rewrite_var_code_t)); - if (var_code == NULL) { - return NGX_CONF_ERROR; - } - - var_code->code = ngx_http_rewrite_var_code; - var_code->index = index; - } - - if_code = ngx_array_push_n(lcf->codes, sizeof(ngx_http_rewrite_if_code_t)); - if (if_code == NULL) { - return NULL; - } - - if_code->code = ngx_http_rewrite_if_code; - - elts = lcf->codes->elts; - - - /* the inside directives must compile to the same code array */ - - nlcf = ctx->loc_conf[ngx_http_rewrite_module.ctx_index]; - nlcf->codes = lcf->codes; - - - save = *cf; - cf->ctx = ctx; - - if (pclcf->name.len == 0) { - if_code->loc_conf = NULL; - cf->cmd_type = NGX_HTTP_SIF_CONF; - - } else { - if_code->loc_conf = ctx->loc_conf; - cf->cmd_type = NGX_HTTP_LIF_CONF; - } - - rv = ngx_conf_parse(cf, NULL); - - *cf = save; - - if (rv != NGX_CONF_OK) { - return rv; - } - - - if (elts != lcf->codes->elts) { - if_code = (ngx_http_rewrite_if_code_t *) - ((u_char *) if_code + ((u_char *) lcf->codes->elts - elts)); - } - - if_code->next = (u_char *) lcf->codes->elts + lcf->codes->nelts - - (u_char *) if_code; - - return NGX_CONF_OK; -} - - -static char * -ngx_http_rewrite_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_http_rewrite_loc_conf_t *lcf = conf; - - ngx_uint_t i, server_names; - ngx_str_t *value; - ngx_http_server_name_t *sn; - ngx_http_core_srv_conf_t *cscf; - ngx_http_rewrite_referer_t *ref; - - cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module); - - if (lcf->referers == NULL) { - lcf->referers = ngx_array_create(cf->pool, - cf->args->nelts + cscf->server_names.nelts, - sizeof(ngx_http_rewrite_referer_t)); - if (lcf->referers == NULL) { - return NGX_CONF_ERROR; - } - } - - value = cf->args->elts; - server_names = 0; - - for (i = 1; i < cf->args->nelts; i++) { - if (value[i].len == 0) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid referer \"%V\"", &value[i]); - return NGX_CONF_ERROR; - } - - if (ngx_strcmp(value[i].data, "none") == 0) { - lcf->no_referer = 1; - continue; - } - - if (ngx_strcmp(value[i].data, "server_names") == 0) { - server_names = 1; - continue; - } - - if (!(ref = ngx_array_push(lcf->referers))) { - return NGX_CONF_ERROR; - } - - if (value[i].data[0] != '*') { - ref->name = value[i]; - ref->wildcard = 0; - continue; - } - - if (value[i].data[1] != '.') { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid wildcard referer \"%V\"", &value[i]); - return NGX_CONF_ERROR; - } - - ref->name.len = value[i].len - 1; - ref->name.data = value[i].data + 1; - ref->wildcard = 1; - } - - if (!server_names) { - return NGX_CONF_OK; - } - - sn = cscf->server_names.elts; - for (i = 0; i < cscf->server_names.nelts; i++) { - if (!(ref = ngx_array_push(lcf->referers))) { - return NGX_CONF_ERROR; - } - - ref->name.len = sn[i].name.len + 1; - if (!(ref->name.data = ngx_palloc(cf->pool, ref->name.len))) { - return NGX_CONF_ERROR; - } - - ngx_memcpy(ref->name.data, sn[i].name.data, sn[i].name.len); - ref->name.data[sn[i].name.len] = '/'; - ref->wildcard = sn[i].wildcard; - } - - return NGX_CONF_OK; -} - - -static void * -ngx_http_rewrite_start_code(ngx_pool_t *pool, ngx_array_t **codes, size_t size) -{ - if (*codes == NULL) { - if (!(*codes = ngx_array_create(pool, 256, 1))) { - return NULL; - } - } - - return ngx_array_push_n(*codes, size); -} - - -static void * -ngx_http_rewrite_add_code(ngx_array_t *codes, size_t size, void *code) -{ - u_char *elts, **p; - void *new; - - elts = codes->elts; - - if (!(new = ngx_array_push_n(codes, size))) { - return NGX_CONF_ERROR; - } - - if (elts != codes->elts) { - p = code; - *p += (u_char *) codes->elts - elts; - } - - return new; -} diff --git a/src/http/modules/ngx_http_rewrite_module.c b/src/http/modules/ngx_http_rewrite_module.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_rewrite_module.c @@ -0,0 +1,1689 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +typedef struct ngx_http_rewrite_engine_s ngx_http_rewrite_engine_t; + +typedef void (*ngx_http_rewrite_code_pt) (ngx_http_rewrite_engine_t *e); + + +typedef struct { + ngx_str_t name; + ngx_uint_t wildcard; +} ngx_http_rewrite_referer_t; + + +typedef struct { + ngx_str_t *name; + ngx_http_variable_value_t *value; +} ngx_http_rewrite_variable_t; + + +typedef struct { + ngx_array_t *codes; /* uintptr_t */ + ngx_array_t *referers; /* ngx_http_rewrite_referer_t */ + + ngx_uint_t max_captures; + ngx_uint_t stack_size; + + ngx_flag_t log; + + ngx_flag_t no_referer; +} ngx_http_rewrite_loc_conf_t; + + +typedef struct { + ngx_http_rewrite_code_pt code; + ngx_regex_t *regex; + uintptr_t size; + uintptr_t ncaptures; + uintptr_t status; + uintptr_t next; + + uintptr_t test:1; + uintptr_t uri:1; + + /* add the r->args to the new arguments */ + uintptr_t args:1; + + uintptr_t redirect:1; + uintptr_t break_cycle:1; + + ngx_str_t name; +} ngx_http_rewrite_regex_code_t; + + +typedef struct { + ngx_http_rewrite_code_pt code; + + uintptr_t uri:1; + + /* add the r->args to the new arguments */ + uintptr_t args:1; + + uintptr_t redirect:1; +} ngx_http_rewrite_regex_end_code_t; + +typedef struct { + ngx_http_rewrite_code_pt code; + uintptr_t n; +} ngx_http_rewrite_copy_capture_code_t; + + +typedef struct { + ngx_http_rewrite_code_pt code; + uintptr_t len; +} ngx_http_rewrite_copy_code_t; + + +typedef struct { + ngx_http_rewrite_code_pt code; + uintptr_t status; + uintptr_t null; +} ngx_http_rewrite_return_code_t; + + +typedef struct { + ngx_http_rewrite_code_pt code; + uintptr_t next; + void **loc_conf; +} ngx_http_rewrite_if_code_t; + + +typedef struct { + ngx_http_rewrite_code_pt code; + uintptr_t value; + uintptr_t text_len; + uintptr_t text_data; +} ngx_http_rewrite_value_code_t; + + +typedef struct { + ngx_http_rewrite_code_pt code; + uintptr_t index; +} ngx_http_rewrite_var_code_t; + + +struct ngx_http_rewrite_engine_s { + u_char *ip; + ngx_http_variable_value_t *sp; + + ngx_str_t buf; + ngx_str_t *line; + + u_char *pos; + + /* the start of the rewritten arguments */ + u_char *args; + + unsigned quote:1; + + ngx_int_t status; + + int *captures; + + ngx_http_request_t *request; + ngx_http_rewrite_loc_conf_t *conf; +}; + + +static ngx_int_t ngx_http_rewrite_init(ngx_cycle_t *cycle); +static void *ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_rewrite_merge_loc_conf(ngx_conf_t *cf, + void *parent, void *child); +static char *ngx_http_rewrite(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_http_rewrite_return(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_http_rewrite_if(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char * ngx_http_rewrite_if_condition(ngx_conf_t *cf, + ngx_http_rewrite_loc_conf_t *lcf); +static char *ngx_http_rewrite_variable(ngx_conf_t *cf, + ngx_http_rewrite_loc_conf_t *lcf, ngx_str_t *value); +static char *ngx_http_rewrite_valid_referers(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +static char * ngx_http_rewrite_set(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static void *ngx_http_rewrite_start_code(ngx_pool_t *pool, + ngx_array_t **codes, size_t size); +static void *ngx_http_rewrite_add_code(ngx_array_t *codes, size_t size, + void *code); + + +static ngx_command_t ngx_http_rewrite_commands[] = { + + { ngx_string("rewrite"), + NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_TAKE23, + ngx_http_rewrite, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("return"), + NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_TAKE1, + ngx_http_rewrite_return, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("if"), + NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_BLOCK|NGX_CONF_1MORE, + ngx_http_rewrite_if, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("valid_referers"), + NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_http_rewrite_valid_referers, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("set"), + NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_TAKE2, + ngx_http_rewrite_set, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("rewrite_log"), + NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_rewrite_loc_conf_t, log), + NULL }, + + ngx_null_command +}; + + +ngx_http_module_t ngx_http_rewrite_module_ctx = { + NULL, /* pre conf */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_rewrite_create_loc_conf, /* create location configration */ + ngx_http_rewrite_merge_loc_conf /* merge location configration */ +}; + + +ngx_module_t ngx_http_rewrite_module = { + NGX_MODULE, + &ngx_http_rewrite_module_ctx, /* module context */ + ngx_http_rewrite_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + ngx_http_rewrite_init, /* init module */ + NULL /* init process */ +}; + + +#define ngx_http_rewrite_exit (u_char *) &ngx_http_rewrite_exit_code + +uintptr_t ngx_http_rewrite_exit_code = (uintptr_t) NULL; + +static ngx_http_variable_value_t ngx_http_rewrite_null_value = + { 0, ngx_string("") }; + + +static ngx_int_t +ngx_http_rewrite_handler(ngx_http_request_t *r) +{ + ngx_http_rewrite_code_pt code; + ngx_http_rewrite_engine_t *e; + ngx_http_rewrite_loc_conf_t *cf; + + cf = ngx_http_get_module_loc_conf(r, ngx_http_rewrite_module); + + if (cf->codes == NULL) { + return NGX_DECLINED; + } + + e = ngx_palloc(r->pool, sizeof(ngx_http_rewrite_engine_t)); + if (e == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + e->sp = ngx_palloc(r->pool, + cf->stack_size * sizeof(ngx_http_variable_value_t)); + if (e->sp == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + if (cf->max_captures) { + e->captures = ngx_palloc(r->pool, cf->max_captures * sizeof(int)); + if (e->captures == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + } else { + e->captures = NULL; + } + + e->ip = cf->codes->elts; + e->buf.len = 0; + e->buf.data = NULL; + e->line = NULL; + e->pos = NULL; + e->args = NULL; + e->quote = 1; + e->status = NGX_DECLINED; + e->request = r; + e->conf = cf; + + while (*(uintptr_t *) e->ip) { + code = *(ngx_http_rewrite_code_pt *) e->ip; + code(e); + } + + return e->status; +} + + +static void +ngx_http_rewrite_regex_start_code(ngx_http_rewrite_engine_t *e) +{ + ngx_int_t rc; + ngx_uint_t n; + ngx_http_request_t *r; + ngx_http_rewrite_regex_code_t *code; + + code = (ngx_http_rewrite_regex_code_t *) e->ip; + + r = e->request; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http rewrite regex: \"%V\"", &code->name); + + if (code->uri) { + e->line = &r->uri; + } else { + e->sp--; + e->line = &e->sp->text; + } + + rc = ngx_regex_exec(code->regex, e->line, e->captures, code->ncaptures); + + if (rc == NGX_REGEX_NO_MATCHED) { + if (e->conf->log) { + ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0, + "\"%V\" does not match \"%V\"", &code->name, e->line); + } + + if (code->test) { + e->sp->value = 0; + e->sp->text.len = 0; + e->sp->text.data = (u_char *) ""; + e->sp++; + + e->ip += sizeof(ngx_http_rewrite_regex_code_t); + return; + } + + e->ip += code->next; + return; + } + + if (rc < 0) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + ngx_regex_exec_n " failed: %d on \"%V\" using \"%V\"", + rc, e->line, &code->name); + + e->ip = ngx_http_rewrite_exit; + e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; + return; + } + + if (e->conf->log) { + ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0, + "\"%V\" matches \"%V\"", &code->name, e->line); + } + + if (code->test) { + e->sp->value = 1; + e->sp->text.len = 1; + e->sp->text.data = (u_char *) "1"; + e->sp++; + + e->ip += sizeof(ngx_http_rewrite_regex_code_t); + return; + } + + if (code->status) { + e->status = code->status; + + if (!code->redirect) { + e->ip = ngx_http_rewrite_exit; + return; + } + } + + e->buf.len = code->size; + + if (code->uri) { + if (!code->break_cycle) { + r->uri_changed = 1; + } + + if (rc && (r->quoted_uri || r->plus_in_uri)) { + e->buf.len += 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len, + NGX_ESCAPE_ARGS); + } + } + + for (n = 1; n < (ngx_uint_t) rc; n++) { + e->buf.len += e->captures[2 * n + 1] - e->captures[2 * n]; + } + + if (code->args && r->args.len) { + e->buf.len += r->args.len + 1; + } + + e->buf.data = ngx_palloc(r->pool, e->buf.len); + if (e->buf.data == NULL) { + e->ip = ngx_http_rewrite_exit; + e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; + return; + } + + e->quote = code->redirect; + + e->pos = e->buf.data; + + e->ip += sizeof(ngx_http_rewrite_regex_code_t); +} + + +static void +ngx_http_rewrite_regex_end_code(ngx_http_rewrite_engine_t *e) +{ + ngx_http_request_t *r; + ngx_http_rewrite_regex_end_code_t *code; + + code = (ngx_http_rewrite_regex_end_code_t *) e->ip; + + r = e->request; + + e->quote = 0; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http rewrite regex end"); + + if (e->args) { + e->buf.len = e->args - e->buf.data; + + if (code->args && r->args.len) { + *e->pos++ = '&'; + e->pos = ngx_cpymem(e->pos, r->args.data, r->args.len); + } + + r->args.len = e->pos - e->args; + r->args.data = e->args; + + e->args = NULL; + + } else { + if (code->args && r->args.len) { + *e->pos++ = '?'; + e->pos = ngx_cpymem(e->pos, r->args.data, r->args.len); + } + + e->buf.len = e->pos - e->buf.data; + } + + if (!code->redirect) { + if (e->conf->log) { + ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0, + "rewritten data: \"%V\", args: \"%V\"", + &e->buf, &r->args); + } + + if (code->uri) { + r->uri = e->buf; + + if (ngx_http_set_exten(r) != NGX_OK) { + e->ip = ngx_http_rewrite_exit; + e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; + return; + } + } + + e->ip += sizeof(ngx_http_rewrite_regex_end_code_t); + return; + } + + ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0, + "rewritten redirect: \"%V\"", &e->buf); + + r->headers_out.location = ngx_list_push(&r->headers_out.headers); + if (r->headers_out.location == NULL) { + e->ip = ngx_http_rewrite_exit; + e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; + return; + } + + if (e->buf.data[0] != '/') { + r->headers_out.location->key.len = sizeof("Location") - 1; + r->headers_out.location->key.data = (u_char *) "Location"; + } + + r->headers_out.location->value = e->buf; + + e->ip += sizeof(ngx_http_rewrite_regex_end_code_t); +} + + +static void +ngx_http_rewrite_copy_capture_code(ngx_http_rewrite_engine_t *e) +{ + ngx_http_rewrite_copy_capture_code_t *code; + + code = (ngx_http_rewrite_copy_capture_code_t *) e->ip; + + e->ip += sizeof(ngx_http_rewrite_copy_capture_code_t); + + if ((e->args || e->quote) + && (e->request->quoted_uri || e->request->plus_in_uri)) + { + e->pos = (u_char *) ngx_escape_uri(e->pos, + &e->line->data[e->captures[code->n]], + e->captures[code->n + 1] - e->captures[code->n], + NGX_ESCAPE_ARGS); + } else { + e->pos = ngx_cpymem(e->pos, &e->line->data[e->captures[code->n]], + e->captures[code->n + 1] - e->captures[code->n]); + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + "http rewrite capture: \"%V\"", &e->buf); +} + + +static void +ngx_http_rewrite_copy_code(ngx_http_rewrite_engine_t *e) +{ + ngx_http_rewrite_copy_code_t *code; + + code = (ngx_http_rewrite_copy_code_t *) e->ip; + + e->pos = ngx_cpymem(e->pos, e->ip + sizeof(ngx_http_rewrite_copy_code_t), + code->len); + + e->ip += sizeof(ngx_http_rewrite_copy_code_t) + + ((code->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1)); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + "http rewrite copy: \"%V\"", &e->buf); +} + + +static void +ngx_http_rewrite_start_args_code(ngx_http_rewrite_engine_t *e) +{ + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + "http rewrite args"); + + e->args = e->pos; + e->ip += sizeof(uintptr_t); +} + + +static void +ngx_http_rewrite_return_code(ngx_http_rewrite_engine_t *e) +{ + ngx_http_rewrite_return_code_t *code; + + code = (ngx_http_rewrite_return_code_t *) e->ip; + + e->status = code->status; + + e->ip += sizeof(ngx_http_rewrite_return_code_t) - sizeof(uintptr_t); +} + + +static void +ngx_http_rewrite_if_code(ngx_http_rewrite_engine_t *e) +{ + ngx_http_rewrite_if_code_t *code; + + code = (ngx_http_rewrite_if_code_t *) e->ip; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + "http rewrite if"); + + e->sp--; + + if (e->sp->value) { + if (code->loc_conf) { + e->request->loc_conf = code->loc_conf; + } + + e->ip += sizeof(ngx_http_rewrite_if_code_t); + return; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + "http rewrite if false"); + + e->ip += code->next; +} + + +static void +ngx_http_rewrite_value_code(ngx_http_rewrite_engine_t *e) +{ + ngx_http_rewrite_value_code_t *code; + + code = (ngx_http_rewrite_value_code_t *) e->ip; + + e->ip += sizeof(ngx_http_rewrite_value_code_t); + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + "http rewrite value"); + + e->sp->value = (ngx_uint_t) code->value; + e->sp->text.len = (size_t) code->text_len; + e->sp->text.data = (u_char *) code->text_data; + e->sp++; +} + + +static void +ngx_http_rewrite_set_var_code(ngx_http_rewrite_engine_t *e) +{ + ngx_http_request_t *r; + ngx_http_variable_value_t *value; + ngx_http_core_main_conf_t *cmcf; + ngx_http_rewrite_var_code_t *code; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + "http rewrite set var"); + + code = (ngx_http_rewrite_var_code_t *) e->ip; + + e->ip += sizeof(ngx_http_rewrite_var_code_t); + + r = e->request; + + if (r->variables == NULL) { + cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); + + r->variables = ngx_pcalloc(r->pool, cmcf->variables.nelts + * sizeof(ngx_http_variable_value_t *)); + if (r->variables == NULL) { + e->ip = ngx_http_rewrite_exit; + e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; + return; + } + } + + value = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); + if (value == NULL) { + e->ip = ngx_http_rewrite_exit; + e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; + return; + } + + e->sp--; + + *value = *e->sp; + + r->variables[code->index] = value; +} + + +static void +ngx_http_rewrite_var_code(ngx_http_rewrite_engine_t *e) +{ + ngx_http_variable_value_t *value; + ngx_http_rewrite_var_code_t *code; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + "http rewrite var"); + + code = (ngx_http_rewrite_var_code_t *) e->ip; + + e->ip += sizeof(ngx_http_rewrite_var_code_t); + + value = ngx_http_get_indexed_variable(e->request, code->index); + + if (value == NULL || value == NGX_HTTP_VARIABLE_NOT_FOUND) { + e->sp->value = 0; + e->sp->text.len = 0; + e->sp->text.data = (u_char *) ""; + e->sp++; + + return; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + "http rewrite var: %ui, \"%V\"", value->value, &value->text); + + *e->sp = *value; + e->sp++; +} + + +static void +ngx_http_rewrite_invalid_referer_code(ngx_http_rewrite_engine_t *e) +{ + u_char *ref; + size_t len; + ngx_uint_t i, n; + ngx_http_request_t *r; + ngx_http_rewrite_referer_t *refs; + ngx_http_rewrite_loc_conf_t *cf; + + r = e->request; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http rewrite invalid referer"); + + cf = ngx_http_get_module_loc_conf(r, ngx_http_rewrite_module); + + e->ip += sizeof(uintptr_t); + + if (cf->referers == NULL) { + e->sp->value = 0; + e->sp->text.len = 0; + e->sp->text.data = (u_char *) ""; + e->sp++; + + return; + } + + if (r->headers_in.referer == NULL) { + if (cf->no_referer) { + e->sp->value = 0; + e->sp->text.len = 0; + e->sp->text.data = (u_char *) ""; + e->sp++; + + return; + } else { + e->sp->value = 1; + e->sp->text.len = 1; + e->sp->text.data = (u_char *) "1"; + e->sp++; + + return; + } + } + + len = r->headers_in.referer->value.len; + ref = r->headers_in.referer->value.data; + + if (len < sizeof("http://i.ru") - 1 + || (ngx_strncasecmp(ref, "http://", 7) != 0)) + { + e->sp->value = 1; + e->sp->text.len = 1; + e->sp->text.data = (u_char *) "1"; + e->sp++; + + return; + } + + len -= 7; + ref += 7; + + refs = cf->referers->elts; + for (i = 0; i < cf->referers->nelts; i++ ){ + + if (refs[i].name.len > len) { + continue; + } + + if (refs[i].wildcard) { + for (n = 0; n < len; n++) { + if (ref[n] == '/' || ref[n] == ':') { + break; + } + + if (ref[n] != '.') { + continue; + } + + if (ngx_strncmp(&ref[n], refs[i].name.data, + refs[i].name.len) == 0) + { + e->sp->value = 0; + e->sp->text.len = 0; + e->sp->text.data = (u_char *) ""; + e->sp++; + + return; + } + } + + } else { + if (ngx_strncasecmp(refs[i].name.data, ref, refs[i].name.len) == 0) + { + e->sp->value = 0; + e->sp->text.len = 0; + e->sp->text.data = (u_char *) ""; + e->sp++; + + return; + } + } + } + + e->sp->value = 1; + e->sp->text.len = 1; + e->sp->text.data = (u_char *) "1"; + e->sp++; +} + + +static void +ngx_http_rewrite_nop_code(ngx_http_rewrite_engine_t *e) +{ + e->ip += sizeof(uintptr_t); +} + + +static ngx_http_variable_value_t * +ngx_http_rewrite_var(ngx_http_request_t *r, uintptr_t data) +{ + ngx_http_variable_t *var; + ngx_http_core_main_conf_t *cmcf; + + cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); + + var = cmcf->variables.elts; + + /* + * the ngx_http_rewrite_module sets variables directly in r->variables, + * and they should be handle by ngx_http_get_indexed_variable(), + * so the handler is called only if the variable is not initialized + */ + + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "using uninitialized \"%V\" variable", &var[data].name); + + return &ngx_http_rewrite_null_value; +} + + +static ngx_int_t +ngx_http_rewrite_init(ngx_cycle_t *cycle) +{ + ngx_http_handler_pt *h; + ngx_http_core_main_conf_t *cmcf; + + cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module); + + h = ngx_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_rewrite_handler; + + return NGX_OK; +} + + +static void * +ngx_http_rewrite_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_rewrite_loc_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_rewrite_loc_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + conf->stack_size = NGX_CONF_UNSET_UINT; + conf->log = NGX_CONF_UNSET; + conf->no_referer = NGX_CONF_UNSET; + + return conf; +} + + +static char * +ngx_http_rewrite_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_rewrite_loc_conf_t *prev = parent; + ngx_http_rewrite_loc_conf_t *conf = child; + + uintptr_t *code, *last; + ngx_http_rewrite_regex_code_t *regex; + + ngx_conf_merge_value(conf->log, prev->log, 0); + ngx_conf_merge_unsigned_value(conf->stack_size, prev->stack_size, 10); + + if (conf->referers == NULL) { + conf->referers = prev->referers; + ngx_conf_merge_value(conf->no_referer, prev->no_referer, 0); + } + + if (conf->no_referer == NGX_CONF_UNSET) { + conf->no_referer = 0; + } + + if (conf->codes == NULL) { + return NGX_CONF_OK; + } + + if (conf->codes == prev->codes) { + return NGX_CONF_OK; + } + + code = conf->codes->elts; + last = (uintptr_t *) ((u_char *) code + conf->codes->nelts); + + while (code < last) { + if (*code == (uintptr_t) NULL) { + return NGX_CONF_OK; + } + + if (*code == (uintptr_t) &ngx_http_rewrite_regex_start_code) { + regex = (ngx_http_rewrite_regex_code_t *) code; + if (conf->max_captures < regex->ncaptures) { + conf->max_captures = regex->ncaptures; + } + code = (uintptr_t *) ((u_char *) code + regex->next); + continue; + } + + if (*code == (uintptr_t) &ngx_http_rewrite_if_code) { + code += sizeof(ngx_http_rewrite_if_code_t) / sizeof(uintptr_t); + continue; + } + + if (*code == (uintptr_t) &ngx_http_rewrite_return_code) { + code += sizeof(ngx_http_rewrite_return_code_t) / sizeof(uintptr_t); + continue; + } + + if (*code == (uintptr_t) &ngx_http_rewrite_set_var_code) { + code += sizeof(ngx_http_rewrite_var_code_t) / sizeof(uintptr_t); + continue; + } + + if (*code == (uintptr_t) &ngx_http_rewrite_var_code) { + code += sizeof(ngx_http_rewrite_var_code_t) / sizeof(uintptr_t); + continue; + } + + if (*code == (uintptr_t) &ngx_http_rewrite_value_code) { + code += sizeof(ngx_http_rewrite_value_code_t) / sizeof(uintptr_t); + continue; + } + + if (*code == (uintptr_t) &ngx_http_rewrite_invalid_referer_code) { + code++; + continue; + } + + if (*code == (uintptr_t) &ngx_http_rewrite_nop_code) { + code++; + continue; + } + +#if (NGX_DEBUG) + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "unknown rewrite code: %p", *code); + return NGX_CONF_ERROR; +#endif + } + + code = ngx_array_push_n(conf->codes, sizeof(uintptr_t)); + if (code == NULL) { + return NGX_CONF_ERROR; + } + + *code = (uintptr_t) NULL; + + return NGX_CONF_OK; +} + + +static char * +ngx_http_rewrite(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_rewrite_loc_conf_t *lcf = conf; + + u_char *data; + size_t len, size; + ngx_str_t *value, err; + ngx_int_t n; + ngx_uint_t i, last; + ngx_http_rewrite_code_pt *code; + ngx_http_rewrite_copy_code_t *copy; + ngx_http_rewrite_regex_code_t *regex; + ngx_http_rewrite_regex_end_code_t *regex_end; + ngx_http_rewrite_copy_capture_code_t *copy_capture; + u_char errstr[NGX_MAX_CONF_ERRSTR]; + + regex = ngx_http_rewrite_start_code(cf->pool, &lcf->codes, + sizeof(ngx_http_rewrite_regex_code_t)); + if (regex == NULL) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + + err.len = NGX_MAX_CONF_ERRSTR; + err.data = errstr; + + /* TODO: NGX_REGEX_CASELESS */ + + regex->regex = ngx_regex_compile(&value[1], 0, cf->pool, &err); + + if (regex->regex == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data); + return NGX_CONF_ERROR; + } + + regex->code = ngx_http_rewrite_regex_start_code; + regex->size = 0; + regex->ncaptures = 0; + regex->status = 0; + regex->test = 0; + regex->uri = 1; + regex->args = 1; + regex->redirect = 0; + regex->name = value[1]; + + last = 0; + + if (ngx_strncmp(value[2].data, "http://", sizeof("http://") - 1) == 0) { + regex->status = NGX_HTTP_MOVED_TEMPORARILY; + regex->redirect = 1; + last = 1; + } + + if (cf->args->nelts == 4) { + if (ngx_strcmp(value[3].data, "last") == 0) { + last = 1; + + } else if (ngx_strcmp(value[3].data, "break") == 0) { + regex->break_cycle = 1; + last = 1; + + } else if (ngx_strcmp(value[3].data, "redirect") == 0) { + regex->status = NGX_HTTP_MOVED_TEMPORARILY; + regex->redirect = 1; + last = 1; + + } else if (ngx_strcmp(value[3].data, "permanent") == 0) { + regex->status = NGX_HTTP_MOVED_PERMANENTLY; + regex->redirect = 1; + last = 1; + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[3]); + return NGX_CONF_ERROR; + } + } + + i = 0; + + while (i < value[2].len) { + + data = &value[2].data[i]; + + if (value[2].data[i] == '$' && i < value[2].len + && value[2].data[i + 1] >= '1' && value[2].data[i + 1] <= '9') + { + + /* the "$1" - "$9" captures */ + + copy_capture = ngx_http_rewrite_add_code(lcf->codes, + sizeof(ngx_http_rewrite_copy_capture_code_t), + ®ex); + if (copy_capture == NULL) { + return NGX_CONF_ERROR; + } + + i++; + + copy_capture->code = ngx_http_rewrite_copy_capture_code; + copy_capture->n = value[2].data[i] - '0'; + + if (regex->ncaptures < copy_capture->n) { + regex->ncaptures = copy_capture->n; + } + + copy_capture->n *= 2; + + i++; + + continue; + } + + if (value[2].data[i] == '?') { + + /* the arguments */ + + if (i == value[2].len - 1) { + /* the last "?" drops the original arguments */ + regex->args = 0; + break; + } + + if (!regex->redirect) { + code = ngx_http_rewrite_add_code(lcf->codes, sizeof(uintptr_t), + ®ex); + if (code == NULL) { + return NGX_CONF_ERROR; + } + + *code = ngx_http_rewrite_start_args_code; + + i++; + + continue; + } + } + + i++; + + /* the substituion strings */ + + while (i < value[2].len && value[2].data[i] != '$') { + + if (value[2].data[i] == '?') { + + if (i == value[2].len - 1) { + /* + * the last "?" drops the original arguments, + * and it should not be copied to a substituion + */ + regex->args = 0; + break; + } + + if (!regex->redirect) { + break; + } + } + + i++; + } + + len = &value[2].data[i] - data; + + if (len == 0) { + continue; + } + + regex->size += len; + + size = (len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1); + + copy = ngx_http_rewrite_add_code(lcf->codes, + sizeof(ngx_http_rewrite_copy_code_t) + size, + ®ex); + if (copy == NULL) { + return NGX_CONF_ERROR; + } + + copy->code = ngx_http_rewrite_copy_code; + copy->len = len; + + ngx_memcpy((u_char *) copy + sizeof(ngx_http_rewrite_copy_code_t), + data, len); + } + + n = ngx_regex_capture_count(regex->regex); + + if (n < 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + ngx_regex_capture_count_n " failed for " + "pattern \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } + + if (regex->ncaptures > (ngx_uint_t) n) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "pattern \"%V\" has less captures " + "than referrenced in substitution \"%V\"", + &value[1], &value[2]); + return NGX_CONF_ERROR; + } + + if (regex->ncaptures < (ngx_uint_t) n) { + regex->ncaptures = (ngx_uint_t) n; + } + + if (regex->ncaptures) { + regex->ncaptures = (regex->ncaptures + 1) * 3; + } + + regex_end = ngx_http_rewrite_add_code(lcf->codes, + sizeof(ngx_http_rewrite_regex_end_code_t), + ®ex); + if (regex_end == NULL) { + return NGX_CONF_ERROR; + } + + regex_end->code = ngx_http_rewrite_regex_end_code; + regex_end->uri = regex->uri; + regex_end->args = regex->args; + regex_end->redirect = regex->redirect; + + if (last) { + code = ngx_http_rewrite_add_code(lcf->codes, sizeof(uintptr_t), + ®ex); + if (code == NULL) { + return NGX_CONF_ERROR; + } + + *code = (uintptr_t) NULL; + } + + regex->next = (u_char *) lcf->codes->elts + lcf->codes->nelts + - (u_char *) regex; + + return NGX_CONF_OK; +} + + +static char * +ngx_http_rewrite_return(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_rewrite_loc_conf_t *lcf = conf; + + ngx_str_t *value; + ngx_http_rewrite_return_code_t *ret; + + ret = ngx_http_rewrite_start_code(cf->pool, &lcf->codes, + sizeof(ngx_http_rewrite_return_code_t)); + if (ret == NULL) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + + ret->code = ngx_http_rewrite_return_code; + ret->null = (uintptr_t) NULL; + + ret->status = ngx_atoi(value[1].data, value[1].len); + + if (ret->status == (uintptr_t) NGX_ERROR) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +static char * +ngx_http_rewrite_if(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_rewrite_loc_conf_t *lcf = conf; + + void *mconf; + char *rv; + u_char *elts; + ngx_uint_t i; + ngx_conf_t save; + ngx_http_module_t *module; + ngx_http_conf_ctx_t *ctx, *pctx; + ngx_http_core_loc_conf_t *clcf, *pclcf, **clcfp; + ngx_http_rewrite_if_code_t *if_code; + ngx_http_rewrite_loc_conf_t *nlcf; + + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)); + if (ctx == NULL) { + return NGX_CONF_ERROR; + } + + pctx = cf->ctx; + ctx->main_conf = pctx->main_conf; + ctx->srv_conf = pctx->srv_conf; + + ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module); + if (ctx->loc_conf == NULL) { + return NGX_CONF_ERROR; + } + + for (i = 0; ngx_modules[i]; i++) { + if (ngx_modules[i]->type != NGX_HTTP_MODULE) { + continue; + } + + module = ngx_modules[i]->ctx; + + if (module->create_loc_conf) { + + mconf = module->create_loc_conf(cf); + if (mconf == NULL) { + return NGX_CONF_ERROR; + } + + ctx->loc_conf[ngx_modules[i]->ctx_index] = mconf; + } + } + + pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index]; + + clcf = ctx->loc_conf[ngx_http_core_module.ctx_index]; + clcf->loc_conf = ctx->loc_conf; + clcf->name = pclcf->name; + clcf->noname = 1; + + if (pclcf->locations.elts == NULL) { + if (ngx_array_init(&pclcf->locations, cf->pool, 4, sizeof(void *)) + == NGX_ERROR) + { + return NGX_CONF_ERROR; + } + } + + clcfp = ngx_array_push(&pclcf->locations); + if (clcfp == NULL) { + return NGX_CONF_ERROR; + } + + *clcfp = clcf; + + + if (ngx_http_rewrite_if_condition(cf, lcf) != NGX_CONF_OK) { + return NGX_CONF_ERROR; + } + + if_code = ngx_array_push_n(lcf->codes, sizeof(ngx_http_rewrite_if_code_t)); + if (if_code == NULL) { + return NULL; + } + + if_code->code = ngx_http_rewrite_if_code; + + elts = lcf->codes->elts; + + + /* the inside directives must compile to the same code array */ + + nlcf = ctx->loc_conf[ngx_http_rewrite_module.ctx_index]; + nlcf->codes = lcf->codes; + + + save = *cf; + cf->ctx = ctx; + + if (pclcf->name.len == 0) { + if_code->loc_conf = NULL; + cf->cmd_type = NGX_HTTP_SIF_CONF; + + } else { + if_code->loc_conf = ctx->loc_conf; + cf->cmd_type = NGX_HTTP_LIF_CONF; + } + + rv = ngx_conf_parse(cf, NULL); + + *cf = save; + + if (rv != NGX_CONF_OK) { + return rv; + } + + + if (elts != lcf->codes->elts) { + if_code = (ngx_http_rewrite_if_code_t *) + ((u_char *) if_code + ((u_char *) lcf->codes->elts - elts)); + } + + if_code->next = (u_char *) lcf->codes->elts + lcf->codes->nelts + - (u_char *) if_code; + + return NGX_CONF_OK; +} + + +static char * +ngx_http_rewrite_if_condition(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf) +{ + ngx_str_t *value, err; + ngx_uint_t cur, last; + ngx_http_rewrite_regex_code_t *regex; + u_char errstr[NGX_MAX_CONF_ERRSTR]; + + value = cf->args->elts; + last = cf->args->nelts - 1; + + if (value[1].len < 1 || value[1].data[0] != '(') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid condition \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } + + if (value[1].len == 1) { + cur = 2; + + } else { + cur = 1; + value[1].len--; + value[1].data++; + } + + if (value[last].len < 1 || value[last].data[value[last].len - 1] != ')') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid condition \"%V\"", &value[last]); + return NGX_CONF_ERROR; + } + + if (value[last].len == 1) { + last--; + + } else { + value[last].len--; + value[last].data[value[last].len] = '\0'; + } + + if (value[cur].len > 1 && value[cur].data[0] == '$') { + + if (cur != last && cur + 2 != last) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid condition \"%V\"", &value[cur]); + return NGX_CONF_ERROR; + } + + if (ngx_http_rewrite_variable(cf, lcf, &value[cur])!= NGX_CONF_OK) { + return NGX_CONF_ERROR; + } + + if (cur == last) { + return NGX_CONF_OK; + } + + cur++; + + if ((value[cur].len == 1 && value[cur].data[0] != '~') + || (value[cur].len == 2 + && value[cur].data[0] != '~' && value[cur].data[1] != '*')) + { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "unexpected \"%V\" in condition", &value[cur]); + return NGX_CONF_ERROR; + } + + regex = ngx_http_rewrite_start_code(cf->pool, &lcf->codes, + sizeof(ngx_http_rewrite_regex_code_t)); + if (regex == NULL) { + return NGX_CONF_ERROR; + } + + err.len = NGX_MAX_CONF_ERRSTR; + err.data = errstr; + + regex->regex = ngx_regex_compile(&value[last], + (value[cur].len == 2) ? NGX_REGEX_CASELESS : 0, + cf->pool, &err); + + if (regex->regex == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data); + return NGX_CONF_ERROR; + } + + regex->code = ngx_http_rewrite_regex_start_code; + regex->size = 0; + regex->ncaptures = 0; + regex->status = 0; + regex->next = sizeof(ngx_http_rewrite_regex_code_t); + regex->test = 1; + regex->uri = 0; + regex->args = 0; + regex->redirect = 0; + regex->name = value[last]; + + return NGX_CONF_OK; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid condition \"%V\"", &value[cur]); + + return NGX_CONF_ERROR; +} + + +static char * +ngx_http_rewrite_variable(ngx_conf_t *cf, ngx_http_rewrite_loc_conf_t *lcf, + ngx_str_t *value) +{ + ngx_http_variable_t *var; + ngx_http_rewrite_code_pt *code; + ngx_http_rewrite_var_code_t *var_code; + + value->len--; + value->data++; + + if (value->len == sizeof("invalid_referer") - 1 + && ngx_strncmp(value->data, "invalid_referer", + sizeof("invalid_referer") - 1) == 0) + { + code = ngx_http_rewrite_start_code(cf->pool, &lcf->codes, + sizeof(ngx_http_rewrite_code_pt)); + if (code == NULL) { + return NGX_CONF_ERROR; + } + + *code = ngx_http_rewrite_invalid_referer_code; + + } else { + var = ngx_http_add_variable(cf, value, 0); + + if (var == NULL) { + return NGX_CONF_ERROR; + } + + var_code = ngx_http_rewrite_start_code(cf->pool, &lcf->codes, + sizeof(ngx_http_rewrite_var_code_t)); + if (var_code == NULL) { + return NGX_CONF_ERROR; + } + + var_code->code = ngx_http_rewrite_var_code; + var_code->index = var->index; + } + + return NGX_CONF_OK; +} + + +static char * +ngx_http_rewrite_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_rewrite_loc_conf_t *lcf = conf; + + ngx_uint_t i, server_names; + ngx_str_t *value; + ngx_http_server_name_t *sn; + ngx_http_core_srv_conf_t *cscf; + ngx_http_rewrite_referer_t *ref; + + cscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_core_module); + + if (lcf->referers == NULL) { + lcf->referers = ngx_array_create(cf->pool, + cf->args->nelts + cscf->server_names.nelts, + sizeof(ngx_http_rewrite_referer_t)); + if (lcf->referers == NULL) { + return NGX_CONF_ERROR; + } + } + + value = cf->args->elts; + server_names = 0; + + for (i = 1; i < cf->args->nelts; i++) { + if (value[i].len == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid referer \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + if (ngx_strcmp(value[i].data, "none") == 0) { + lcf->no_referer = 1; + continue; + } + + if (ngx_strcmp(value[i].data, "server_names") == 0) { + server_names = 1; + continue; + } + + ref = ngx_array_push(lcf->referers); + if (ref == NULL) { + return NGX_CONF_ERROR; + } + + if (value[i].data[0] != '*') { + ref->name = value[i]; + ref->wildcard = 0; + continue; + } + + if (value[i].data[1] != '.') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid wildcard referer \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + ref->name.len = value[i].len - 1; + ref->name.data = value[i].data + 1; + ref->wildcard = 1; + } + + if (!server_names) { + return NGX_CONF_OK; + } + + sn = cscf->server_names.elts; + for (i = 0; i < cscf->server_names.nelts; i++) { + ref = ngx_array_push(lcf->referers); + if (ref == NULL) { + return NGX_CONF_ERROR; + } + + ref->name.len = sn[i].name.len + 1; + ref->name.data = ngx_palloc(cf->pool, ref->name.len); + if (ref->name.data == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memcpy(ref->name.data, sn[i].name.data, sn[i].name.len); + ref->name.data[sn[i].name.len] = '/'; + ref->wildcard = sn[i].wildcard; + } + + return NGX_CONF_OK; +} + + +static char * +ngx_http_rewrite_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_rewrite_loc_conf_t *lcf = conf; + + ngx_int_t n; + ngx_str_t *value; + ngx_http_variable_t *v; + ngx_http_rewrite_var_code_t *var; + ngx_http_rewrite_value_code_t *val; + + value = cf->args->elts; + + if (value[1].data[0] != '$') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid variable name \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } + + value[1].len--; + value[1].data++; + + v = ngx_http_add_variable(cf, &value[1], 1); + if (v == NULL) { + return NGX_CONF_ERROR; + } + + v->handler = ngx_http_rewrite_var; + v->data = v->index; + + val = ngx_http_rewrite_start_code(cf->pool, &lcf->codes, + sizeof(ngx_http_rewrite_value_code_t)); + if (val == NULL) { + return NGX_CONF_ERROR; + } + + n = ngx_atoi(value[2].data, value[2].len); + + if (n == NGX_ERROR) { + n = 0; + } + + val->code = ngx_http_rewrite_value_code; + val->value = (uintptr_t) n; + val->text_len = (uintptr_t) value[2].len; + val->text_data = (uintptr_t) value[2].data; + + var = ngx_http_rewrite_start_code(cf->pool, &lcf->codes, + sizeof(ngx_http_rewrite_var_code_t)); + if (var == NULL) { + return NGX_CONF_ERROR; + } + + var->code = ngx_http_rewrite_set_var_code; + var->index = (uintptr_t) v->index; + + return NGX_CONF_OK; +} + + +static void * +ngx_http_rewrite_start_code(ngx_pool_t *pool, ngx_array_t **codes, size_t size) +{ + if (*codes == NULL) { + *codes = ngx_array_create(pool, 256, 1); + if (*codes == NULL) { + return NULL; + } + } + + return ngx_array_push_n(*codes, size); +} + + +static void * +ngx_http_rewrite_add_code(ngx_array_t *codes, size_t size, void *code) +{ + u_char *elts, **p; + void *new; + + elts = codes->elts; + + new = ngx_array_push_n(codes, size); + if (new == NULL) { + return NGX_CONF_ERROR; + } + + if (elts != codes->elts) { + p = code; + *p += (u_char *) codes->elts - elts; + } + + return new; +} diff --git a/src/http/modules/ngx_http_ssi_filter.c b/src/http/modules/ngx_http_ssi_filter_module.c rename from src/http/modules/ngx_http_ssi_filter.c rename to src/http/modules/ngx_http_ssi_filter_module.c --- a/src/http/modules/ngx_http_ssi_filter.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -98,8 +98,6 @@ typedef enum { } ngx_http_ssi_state_e; -static ngx_int_t ngx_http_ssi_error(ngx_http_request_t *r, - ngx_http_ssi_ctx_t *ctx); static ngx_int_t ngx_http_ssi_parse(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx); @@ -1147,21 +1145,25 @@ static ngx_int_t ngx_http_ssi_echo(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, ngx_str_t **params) { + ngx_uint_t i; ngx_buf_t *b; ngx_str_t *var, *value; ngx_chain_t *cl; - ngx_http_variable_value_t *v; + ngx_http_variable_value_t *vv; var = params[NGX_HTTP_SSI_ECHO_VAR]; - value = NULL; - v = ngx_http_get_variable(r, var); + for (i = 0; i < var->len; i++) { + var->data[i] = ngx_toupper(var->data[i]); + } - if (v == NULL) { + vv = ngx_http_get_variable(r, var); + + if (vv == NULL) { return NGX_HTTP_SSI_ERROR; } - if (v == NGX_HTTP_VARIABLE_NOT_FOUND) { + if (vv == NGX_HTTP_VARIABLE_NOT_FOUND) { value = params[NGX_HTTP_SSI_ECHO_DEFAULT]; if (value == NULL) { @@ -1172,7 +1174,7 @@ ngx_http_ssi_echo(ngx_http_request_t *r, } } else { - value = &v->text; + value = &vv->text; if (value->len == 0) { return NGX_OK; diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -19,7 +19,7 @@ static void *ngx_http_ssl_create_main_co static char *ngx_http_ssl_init_main_conf(ngx_conf_t *cf, void *conf); static void *ngx_http_ssl_create_srv_conf(ngx_conf_t *cf); static char *ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, - void *parent, void *child); + void *parent, void *child); static ngx_command_t ngx_http_ssl_commands[] = { @@ -87,11 +87,13 @@ ngx_module_t ngx_http_ssl_module = { }; -static void *ngx_http_ssl_create_main_conf(ngx_conf_t *cf) +static void * +ngx_http_ssl_create_main_conf(ngx_conf_t *cf) { ngx_http_ssl_main_conf_t *mcf; - if (!(mcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssl_main_conf_t)))) { + mcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssl_main_conf_t)); + if (mcf == NULL) { return NGX_CONF_ERROR; } @@ -106,7 +108,8 @@ static void *ngx_http_ssl_create_main_co } -static char *ngx_http_ssl_init_main_conf(ngx_conf_t *cf, void *conf) +static char * +ngx_http_ssl_init_main_conf(ngx_conf_t *cf, void *conf) { ngx_http_ssl_main_conf_t *mcf = conf; @@ -137,11 +140,13 @@ static char *ngx_http_ssl_init_main_conf } -static void *ngx_http_ssl_create_srv_conf(ngx_conf_t *cf) +static void * +ngx_http_ssl_create_srv_conf(ngx_conf_t *cf) { ngx_http_ssl_srv_conf_t *scf; - if (!(scf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssl_srv_conf_t)))) { + scf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssl_srv_conf_t)); + if (scf == NULL) { return NGX_CONF_ERROR; } @@ -162,8 +167,8 @@ static void *ngx_http_ssl_create_srv_con } -static char *ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, - void *parent, void *child) +static char * +ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) { ngx_http_ssl_srv_conf_t *prev = parent; ngx_http_ssl_srv_conf_t *conf = child; @@ -226,7 +231,8 @@ static char *ngx_http_ssl_merge_srv_conf #if 0 -static ngx_int_t ngx_http_ssl_init_process(ngx_cycle_t *cycle) +static ngx_int_t +ngx_http_ssl_init_process(ngx_cycle_t *cycle) { ngx_uint_t i; ngx_http_ssl_srv_conf_t *sscf; diff --git a/src/http/modules/ngx_http_ssl_module.h b/src/http/modules/ngx_http_ssl_module.h --- a/src/http/modules/ngx_http_ssl_module.h +++ b/src/http/modules/ngx_http_ssl_module.h @@ -32,7 +32,7 @@ typedef struct { ngx_int_t ngx_http_ssl_read(ngx_http_request_t *r, u_char *buf, size_t size); ngx_int_t ngx_http_ssl_shutdown(ngx_http_request_t *r); ngx_chain_t *ngx_http_ssl_write(ngx_connection_t *c, ngx_chain_t *in, - off_t limit); + off_t limit); void ngx_http_ssl_close_connection(SSL *ssl, ngx_log_t *log); diff --git a/src/http/modules/ngx_http_static_handler.c b/src/http/modules/ngx_http_static_handler.c deleted file mode 100644 --- a/src/http/modules/ngx_http_static_handler.c +++ /dev/null @@ -1,589 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#include -#include -#include - - -typedef struct { - ngx_http_cache_hash_t *redirect_cache; -} ngx_http_static_loc_conf_t; - - -static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r); -static void *ngx_http_static_create_loc_conf(ngx_conf_t *cf); -static char *ngx_http_static_merge_loc_conf(ngx_conf_t *cf, - void *parent, void *child); -static ngx_int_t ngx_http_static_init(ngx_cycle_t *cycle); - - -static ngx_command_t ngx_http_static_commands[] = { - -#if (NGX_HTTP_CACHE) - - { ngx_string("redirect_cache"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE3, - ngx_http_set_cache_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_static_loc_conf_t, redirect_cache), - NULL }, - -#endif - - ngx_null_command -}; - - - -ngx_http_module_t ngx_http_static_module_ctx = { - NULL, /* pre conf */ - - NULL, /* create main configuration */ - NULL, /* init main configuration */ - - NULL, /* create server configuration */ - NULL, /* merge server configuration */ - - ngx_http_static_create_loc_conf, /* create location configuration */ - ngx_http_static_merge_loc_conf /* merge location configuration */ -}; - - -ngx_module_t ngx_http_static_module = { - NGX_MODULE, - &ngx_http_static_module_ctx, /* module context */ - ngx_http_static_commands, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - ngx_http_static_init, /* init module */ - NULL /* init process */ -}; - - -static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r) -{ - u_char *last; - ngx_fd_t fd; - ngx_int_t rc; - ngx_uint_t level; - ngx_str_t name, location; - ngx_err_t err; - ngx_log_t *log; - ngx_buf_t *b; - ngx_chain_t out; - ngx_file_info_t fi; - ngx_http_cleanup_t *file_cleanup, *redirect_cleanup; - ngx_http_core_loc_conf_t *clcf; - ngx_http_static_loc_conf_t *slcf; -#if (NGX_HTTP_CACHE) - uint32_t file_crc, redirect_crc; - ngx_http_cache_t *file, *redirect; -#endif - - if (r->uri.data[r->uri.len - 1] == '/') { - return NGX_DECLINED; - } - - /* TODO: Win32 */ - if (r->zero_in_uri) { - return NGX_DECLINED; - } - - if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) { - return NGX_HTTP_NOT_ALLOWED; - } - - rc = ngx_http_discard_body(r); - - if (rc != NGX_OK && rc != NGX_AGAIN) { - return rc; - } - -#if (NGX_HTTP_CACHE) - - /* - * there is a valid cached open file, i.e by the index handler, - * and it should be already registered in r->cleanup - */ - - if (r->cache && !r->cache->expired) { - return ngx_http_send_cached(r); - } - -#endif - - log = r->connection->log; - - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - - /* - * make a file name, reserve 2 bytes for a trailing '/' - * in a possible redirect and for the last '\0' - */ - - if (clcf->alias) { - name.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len + 2 - - clcf->name.len); - if (name.data == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - last = ngx_cpymem(name.data, clcf->root.data, clcf->root.len); - last = ngx_cpystrn(last, r->uri.data + clcf->name.len, - r->uri.len + 1 - clcf->name.len); - - name.len = last - name.data; - - location.data = ngx_palloc(r->pool, r->uri.len + 2); - if (location.data == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - last = ngx_cpystrn(location.data, r->uri.data, r->uri.len + 1); - -#if 0 - /* - * aliases usually have trailling "/", - * set it in the start of the possible redirect - */ - - if (*location.data != '/') { - location.data--; - } -#endif - - location.len = last - location.data + 1; - - } else { - name.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len + 2); - if (name.data == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - location.data = ngx_cpymem(name.data, clcf->root.data, clcf->root.len); - last = ngx_cpystrn(location.data, r->uri.data, r->uri.len + 1); - - name.len = last - name.data; - location.len = last - location.data + 1; - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, - "http filename: \"%s\"", name.data); - - - /* allocate cleanups */ - - if (!(file_cleanup = ngx_push_array(&r->cleanup))) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - file_cleanup->valid = 0; - - slcf = ngx_http_get_module_loc_conf(r, ngx_http_static_module); - if (slcf->redirect_cache) { - if (!(redirect_cleanup = ngx_push_array(&r->cleanup))) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - redirect_cleanup->valid = 0; - - } else { - redirect_cleanup = NULL; - } - -#if (NGX_HTTP_CACHE) - - /* look up an open files cache */ - - if (clcf->open_files) { - file = ngx_http_cache_get(clcf->open_files, file_cleanup, - &name, &file_crc); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, - "http open file cache get: %p", file); - - if (file && !file->expired) { - r->cache = file; - return ngx_http_send_cached(r); - } - - } else { - file = NULL; - } - - - /* look up an redirect cache */ - - if (slcf->redirect_cache) { - redirect = ngx_http_cache_get(slcf->redirect_cache, redirect_cleanup, - &name, &redirect_crc); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, - "http redirect cache get: %p", redirect); - - if (redirect && !redirect->expired) { - - /* - * We do not copy a cached value so the cache entry is locked - * until the end of the request. In a single threaded model - * the redirected request should complete before other event - * will be processed. In a multithreaded model this locking - * should keep more popular redirects in cache. - */ - - if (!(r->headers_out.location = - ngx_http_add_header(&r->headers_out, ngx_http_headers_out))) - { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - r->headers_out.location->value = redirect->data.value; - - return NGX_HTTP_MOVED_PERMANENTLY; - } - - } else { - redirect = NULL; - } - -#endif - - /* open file */ - -#if (NGX_WIN9X) - - /* TODO: redirect cache */ - - if (ngx_win32_version < NGX_WIN_NT) { - - /* - * there is no way to open a file or a directory in Win9X with - * one syscall because Win9X has no FILE_FLAG_BACKUP_SEMANTICS flag - * so we need to check its type before the opening - */ - - if (ngx_file_info(name.data, &fi) == NGX_FILE_ERROR) { - err = ngx_errno; - ngx_log_error(NGX_LOG_ERR, log, err, - ngx_file_info_n " \"%s\" failed", name.data); - - if (err == NGX_ENOENT || err == NGX_ENOTDIR) { - return NGX_HTTP_NOT_FOUND; - - } else if (err == NGX_EACCES) { - return NGX_HTTP_FORBIDDEN; - - } else { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - } - - if (ngx_is_dir(&fi)) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, - "HTTP DIR: \"%s\"", name.data); - - if (!(r->headers_out.location = - ngx_http_add_header(&r->headers_out, ngx_http_headers_out))) - { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - *last++ = '/'; - *last = '\0'; - r->headers_out.location->value.len = last - location; - r->headers_out.location->value.data = location; - - return NGX_HTTP_MOVED_PERMANENTLY; - } - } - -#endif - - - fd = ngx_open_file(name.data, NGX_FILE_RDONLY, NGX_FILE_OPEN); - - if (fd == NGX_INVALID_FILE) { - err = ngx_errno; - - if (err == NGX_ENOENT || err == NGX_ENOTDIR) { - level = NGX_LOG_ERR; - rc = NGX_HTTP_NOT_FOUND; - - } else if (err == NGX_EACCES) { - level = NGX_LOG_ERR; - rc = NGX_HTTP_FORBIDDEN; - - } else { - level = NGX_LOG_CRIT; - rc = NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - ngx_log_error(level, log, err, - ngx_open_file_n " \"%s\" failed", name.data); - - return rc; - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", fd); - - if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_CRIT, log, ngx_errno, - ngx_fd_info_n " \"%s\" failed", name.data); - - if (ngx_close_file(fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, - ngx_close_file_n " \"%s\" failed", name.data); - } - - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - if (ngx_is_dir(&fi)) { - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir"); - - if (ngx_close_file(fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, - ngx_close_file_n " \"%s\" failed", name.data); - } - - *last++ = '/'; - *last = '\0'; - - r->headers_out.location = ngx_list_push(&r->headers_out.headers); - if (r->headers_out.location == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - r->headers_out.location->value = location; - -#if (NGX_HTTP_CACHE) - - if (slcf->redirect_cache) { - if (redirect) { - if (location.len == redirect->data.value.len - && ngx_memcmp(redirect->data.value.data, location.data, - location.len) == 0) - { - redirect->accessed = ngx_cached_time; - redirect->updated = ngx_cached_time; - - /* - * we can unlock the cache entry because - * we have the local copy anyway - */ - - ngx_http_cache_unlock(slcf->redirect_cache, redirect, log); - redirect_cleanup->valid = 0; - - return NGX_HTTP_MOVED_PERMANENTLY; - } - } - - location.len++; - redirect = ngx_http_cache_alloc(slcf->redirect_cache, redirect, - redirect_cleanup, - &name, redirect_crc, - &location, log); - location.len--; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, - "http redirect cache alloc: %p", redirect); - - if (redirect) { - redirect->fd = NGX_INVALID_FILE; - redirect->accessed = ngx_cached_time; - redirect->last_modified = 0; - redirect->updated = ngx_cached_time; - redirect->memory = 1; - ngx_http_cache_unlock(slcf->redirect_cache, redirect, log); - redirect_cleanup->valid = 0; - } - - } - -#endif - - return NGX_HTTP_MOVED_PERMANENTLY; - } - -#if !(NGX_WIN32) /* the not regular files are probably Unix specific */ - - if (!ngx_is_file(&fi)) { - ngx_log_error(NGX_LOG_CRIT, log, ngx_errno, - "\"%s\" is not a regular file", name.data); - - if (ngx_close_file(fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, - ngx_close_file_n " \"%s\" failed", name.data); - } - - return NGX_HTTP_NOT_FOUND; - } - -#endif - - -#if (NGX_HTTP_CACHE) - - if (clcf->open_files) { - -#if (NGX_USE_HTTP_FILE_CACHE_UNIQ) - - if (file && file->uniq == ngx_file_uniq(&fi)) { - if (ngx_close_file(fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, - ngx_close_file_n " \"%s\" failed", name.data); - } - file->accessed = ngx_cached_time; - file->updated = ngx_cached_time; - file->expired = 0; - r->cache = file; - - return ngx_http_send_cached(r); - - } else { - if (file) { - ngx_http_cache_unlock(clcf->open_files, file, log); - file = NULL; - } - - file = ngx_http_cache_alloc(clcf->open_files, file, - file_cleanup, - &name, file_crc, NULL, log); - if (file) { - file->uniq = ngx_file_uniq(&fi); - } - } - -#else - file = ngx_http_cache_alloc(clcf->open_files, file, - file_cleanup, - &name, file_crc, NULL, log); -#endif - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, - "http open file cache alloc: %p", file); - - if (file) { - file->fd = fd; - file->data.size = ngx_file_size(&fi); - file->accessed = ngx_cached_time; - file->last_modified = ngx_file_mtime(&fi); - file->updated = ngx_cached_time; - r->cache = file; - } - - return ngx_http_send_cached(r); - } - -#endif - - log->action = "sending response to client"; - - file_cleanup->data.file.fd = fd; - file_cleanup->data.file.name = name.data; - file_cleanup->valid = 1; - file_cleanup->cache = 0; - - r->headers_out.status = NGX_HTTP_OK; - r->headers_out.content_length_n = ngx_file_size(&fi); - r->headers_out.last_modified_time = ngx_file_mtime(&fi); - - if (r->headers_out.content_length_n == 0) { - r->header_only = 1; - } - - if (ngx_http_set_content_type(r) != NGX_OK) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - -#if (NGX_SUPPRESS_WARN) - b = NULL; -#endif - - if (!r->header_only) { - /* we need to allocate all before the header would be sent */ - - if (!(b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)))) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - if (!(b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)))) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - r->filter_allow_ranges = 1; - } - - rc = ngx_http_send_header(r); - - if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { - return rc; - } - - b->in_file = 1; - - if (!r->main) { - b->last_buf = 1; - } - - b->file_pos = 0; - b->file_last = ngx_file_size(&fi); - - b->file->fd = fd; - b->file->name = name; - b->file->log = log; - - out.buf = b; - out.next = NULL; - - return ngx_http_output_filter(r, &out); -} - - -static void *ngx_http_static_create_loc_conf(ngx_conf_t *cf) -{ - ngx_http_static_loc_conf_t *conf; - - if (!(conf = ngx_palloc(cf->pool, sizeof(ngx_http_static_loc_conf_t)))) { - return NGX_CONF_ERROR; - } - - conf->redirect_cache = NULL; - - return conf; -} - - -static char *ngx_http_static_merge_loc_conf(ngx_conf_t *cf, - void *parent, void *child) -{ - ngx_http_static_loc_conf_t *prev = parent; - ngx_http_static_loc_conf_t *conf = child; - - if (conf->redirect_cache == NULL) { - conf->redirect_cache = prev->redirect_cache; - } - - return NGX_CONF_OK; -} - - -static ngx_int_t ngx_http_static_init(ngx_cycle_t *cycle) -{ - ngx_http_handler_pt *h; - ngx_http_core_main_conf_t *cmcf; - - cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module); - - h = ngx_push_array(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers); - if (h == NULL) { - return NGX_ERROR; - } - - *h = ngx_http_static_handler; - - return NGX_OK; -} diff --git a/src/http/modules/ngx_http_static_module.c b/src/http/modules/ngx_http_static_module.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_static_module.c @@ -0,0 +1,597 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +typedef struct { + ngx_http_cache_hash_t *redirect_cache; +} ngx_http_static_loc_conf_t; + + +static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r); +static void *ngx_http_static_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_static_merge_loc_conf(ngx_conf_t *cf, + void *parent, void *child); +static ngx_int_t ngx_http_static_init(ngx_cycle_t *cycle); + + +static ngx_command_t ngx_http_static_commands[] = { + +#if (NGX_HTTP_CACHE) + + { ngx_string("redirect_cache"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE3, + ngx_http_set_cache_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_static_loc_conf_t, redirect_cache), + NULL }, + +#endif + + ngx_null_command +}; + + + +ngx_http_module_t ngx_http_static_module_ctx = { + NULL, /* pre conf */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_static_create_loc_conf, /* create location configuration */ + ngx_http_static_merge_loc_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_static_module = { + NGX_MODULE, + &ngx_http_static_module_ctx, /* module context */ + ngx_http_static_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + ngx_http_static_init, /* init module */ + NULL /* init process */ +}; + + +static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r) +{ + u_char *last; + ngx_fd_t fd; + ngx_int_t rc; + ngx_uint_t level; + ngx_str_t name, location; + ngx_err_t err; + ngx_log_t *log; + ngx_buf_t *b; + ngx_chain_t out; + ngx_file_info_t fi; + ngx_http_cleanup_t *file_cleanup; +#if (NGX_HTTP_CACHE) + ngx_http_cleanup_t *redirect_cleanup; +#endif + ngx_http_core_loc_conf_t *clcf; +#if (NGX_HTTP_CACHE) + ngx_http_static_loc_conf_t *slcf; + uint32_t file_crc, redirect_crc; + ngx_http_cache_t *file, *redirect; +#endif + + if (r->uri.data[r->uri.len - 1] == '/') { + return NGX_DECLINED; + } + + /* TODO: Win32 */ + if (r->zero_in_uri) { + return NGX_DECLINED; + } + + if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) { + return NGX_HTTP_NOT_ALLOWED; + } + + rc = ngx_http_discard_body(r); + + if (rc != NGX_OK && rc != NGX_AGAIN) { + return rc; + } + +#if (NGX_HTTP_CACHE) + + /* + * there is a valid cached open file, i.e by the index handler, + * and it should be already registered in r->cleanup + */ + + if (r->cache && !r->cache->expired) { + return ngx_http_send_cached(r); + } + +#endif + + log = r->connection->log; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + /* + * make a file name, reserve 2 bytes for a trailing '/' + * in a possible redirect and for the last '\0' + */ + + if (clcf->alias) { + name.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len + 2 + - clcf->name.len); + if (name.data == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + last = ngx_cpymem(name.data, clcf->root.data, clcf->root.len); + last = ngx_cpystrn(last, r->uri.data + clcf->name.len, + r->uri.len + 1 - clcf->name.len); + + name.len = last - name.data; + + location.data = ngx_palloc(r->pool, r->uri.len + 2); + if (location.data == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + last = ngx_cpystrn(location.data, r->uri.data, r->uri.len + 1); + +#if 0 + /* + * aliases usually have trailling "/", + * set it in the start of the possible redirect + */ + + if (*location.data != '/') { + location.data--; + } +#endif + + location.len = last - location.data + 1; + + } else { + name.data = ngx_palloc(r->pool, clcf->root.len + r->uri.len + 2); + if (name.data == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + location.data = ngx_cpymem(name.data, clcf->root.data, clcf->root.len); + last = ngx_cpystrn(location.data, r->uri.data, r->uri.len + 1); + + name.len = last - name.data; + location.len = last - location.data + 1; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, + "http filename: \"%s\"", name.data); + + + /* allocate cleanups */ + + file_cleanup = ngx_array_push(&r->cleanup); + if (file_cleanup == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + file_cleanup->valid = 0; + +#if (NGX_HTTP_CACHE) + + slcf = ngx_http_get_module_loc_conf(r, ngx_http_static_module); + if (slcf->redirect_cache) { + redirect_cleanup = ngx_array_push(&r->cleanup); + if (redirect_cleanup == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + redirect_cleanup->valid = 0; + + } else { + redirect_cleanup = NULL; + } + + /* look up an open files cache */ + + if (clcf->open_files) { + file = ngx_http_cache_get(clcf->open_files, file_cleanup, + &name, &file_crc); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, + "http open file cache get: %p", file); + + if (file && !file->expired) { + r->cache = file; + return ngx_http_send_cached(r); + } + + } else { + file = NULL; + } + + + /* look up an redirect cache */ + + if (slcf->redirect_cache) { + redirect = ngx_http_cache_get(slcf->redirect_cache, redirect_cleanup, + &name, &redirect_crc); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, + "http redirect cache get: %p", redirect); + + if (redirect && !redirect->expired) { + + /* + * We do not copy a cached value so the cache entry is locked + * until the end of the request. In a single threaded model + * the redirected request should complete before other event + * will be processed. In a multithreaded model this locking + * should keep more popular redirects in cache. + */ + + r->headers_out.location = ngx_http_add_header(&r->headers_out, + ngx_http_headers_out); + if (r->headers_out.location == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + r->headers_out.location->value = redirect->data.value; + + return NGX_HTTP_MOVED_PERMANENTLY; + } + + } else { + redirect = NULL; + } + +#endif + + /* open file */ + +#if (NGX_WIN9X) + + /* TODO: redirect cache */ + + if (ngx_win32_version < NGX_WIN_NT) { + + /* + * there is no way to open a file or a directory in Win9X with + * one syscall because Win9X has no FILE_FLAG_BACKUP_SEMANTICS flag + * so we need to check its type before the opening + */ + + if (ngx_file_info(name.data, &fi) == NGX_FILE_ERROR) { + err = ngx_errno; + ngx_log_error(NGX_LOG_ERR, log, err, + ngx_file_info_n " \"%s\" failed", name.data); + + if (err == NGX_ENOENT || err == NGX_ENOTDIR) { + return NGX_HTTP_NOT_FOUND; + + } else if (err == NGX_EACCES) { + return NGX_HTTP_FORBIDDEN; + + } else { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + } + + if (ngx_is_dir(&fi)) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, + "HTTP DIR: \"%s\"", name.data); + + r->headers_out.location = ngx_http_add_header(&r->headers_out, + ngx_http_headers_out); + if (r->headers_out.location == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + *last++ = '/'; + *last = '\0'; + r->headers_out.location->value.len = last - location; + r->headers_out.location->value.data = location; + + return NGX_HTTP_MOVED_PERMANENTLY; + } + } + +#endif + + + fd = ngx_open_file(name.data, NGX_FILE_RDONLY, NGX_FILE_OPEN); + + if (fd == NGX_INVALID_FILE) { + err = ngx_errno; + + if (err == NGX_ENOENT || err == NGX_ENOTDIR) { + level = NGX_LOG_ERR; + rc = NGX_HTTP_NOT_FOUND; + + } else if (err == NGX_EACCES) { + level = NGX_LOG_ERR; + rc = NGX_HTTP_FORBIDDEN; + + } else { + level = NGX_LOG_CRIT; + rc = NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + ngx_log_error(level, log, err, + ngx_open_file_n " \"%s\" failed", name.data); + + return rc; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", fd); + + if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_CRIT, log, ngx_errno, + ngx_fd_info_n " \"%s\" failed", name.data); + + if (ngx_close_file(fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + ngx_close_file_n " \"%s\" failed", name.data); + } + + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + if (ngx_is_dir(&fi)) { + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir"); + + if (ngx_close_file(fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + ngx_close_file_n " \"%s\" failed", name.data); + } + + *last++ = '/'; + *last = '\0'; + + r->headers_out.location = ngx_list_push(&r->headers_out.headers); + if (r->headers_out.location == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + r->headers_out.location->value = location; + +#if (NGX_HTTP_CACHE) + + if (slcf->redirect_cache) { + if (redirect) { + if (location.len == redirect->data.value.len + && ngx_memcmp(redirect->data.value.data, location.data, + location.len) == 0) + { + redirect->accessed = ngx_cached_time; + redirect->updated = ngx_cached_time; + + /* + * we can unlock the cache entry because + * we have the local copy anyway + */ + + ngx_http_cache_unlock(slcf->redirect_cache, redirect, log); + redirect_cleanup->valid = 0; + + return NGX_HTTP_MOVED_PERMANENTLY; + } + } + + location.len++; + redirect = ngx_http_cache_alloc(slcf->redirect_cache, redirect, + redirect_cleanup, + &name, redirect_crc, + &location, log); + location.len--; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, + "http redirect cache alloc: %p", redirect); + + if (redirect) { + redirect->fd = NGX_INVALID_FILE; + redirect->accessed = ngx_cached_time; + redirect->last_modified = 0; + redirect->updated = ngx_cached_time; + redirect->memory = 1; + ngx_http_cache_unlock(slcf->redirect_cache, redirect, log); + redirect_cleanup->valid = 0; + } + + } + +#endif + + return NGX_HTTP_MOVED_PERMANENTLY; + } + +#if !(NGX_WIN32) /* the not regular files are probably Unix specific */ + + if (!ngx_is_file(&fi)) { + ngx_log_error(NGX_LOG_CRIT, log, ngx_errno, + "\"%s\" is not a regular file", name.data); + + if (ngx_close_file(fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + ngx_close_file_n " \"%s\" failed", name.data); + } + + return NGX_HTTP_NOT_FOUND; + } + +#endif + + +#if (NGX_HTTP_CACHE) + + if (clcf->open_files) { + +#if (NGX_USE_HTTP_FILE_CACHE_UNIQ) + + if (file && file->uniq == ngx_file_uniq(&fi)) { + if (ngx_close_file(fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + ngx_close_file_n " \"%s\" failed", name.data); + } + file->accessed = ngx_cached_time; + file->updated = ngx_cached_time; + file->expired = 0; + r->cache = file; + + return ngx_http_send_cached(r); + + } else { + if (file) { + ngx_http_cache_unlock(clcf->open_files, file, log); + file = NULL; + } + + file = ngx_http_cache_alloc(clcf->open_files, file, + file_cleanup, + &name, file_crc, NULL, log); + if (file) { + file->uniq = ngx_file_uniq(&fi); + } + } + +#else + file = ngx_http_cache_alloc(clcf->open_files, file, + file_cleanup, + &name, file_crc, NULL, log); +#endif + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, + "http open file cache alloc: %p", file); + + if (file) { + file->fd = fd; + file->data.size = ngx_file_size(&fi); + file->accessed = ngx_cached_time; + file->last_modified = ngx_file_mtime(&fi); + file->updated = ngx_cached_time; + r->cache = file; + } + + return ngx_http_send_cached(r); + } + +#endif + + log->action = "sending response to client"; + + file_cleanup->data.file.fd = fd; + file_cleanup->data.file.name = name.data; + file_cleanup->valid = 1; + file_cleanup->cache = 0; + + r->headers_out.status = NGX_HTTP_OK; + r->headers_out.content_length_n = ngx_file_size(&fi); + r->headers_out.last_modified_time = ngx_file_mtime(&fi); + + if (r->headers_out.content_length_n == 0) { + r->header_only = 1; + } + + if (ngx_http_set_content_type(r) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + +#if (NGX_SUPPRESS_WARN) + b = NULL; +#endif + + if (!r->header_only) { + /* 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; + } + + r->filter_allow_ranges = 1; + } + + rc = ngx_http_send_header(r); + + if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { + return rc; + } + + b->in_file = 1; + + if (!r->main) { + b->last_buf = 1; + } + + b->file_pos = 0; + b->file_last = ngx_file_size(&fi); + + b->file->fd = fd; + b->file->name = name; + b->file->log = log; + + out.buf = b; + out.next = NULL; + + return ngx_http_output_filter(r, &out); +} + + +static void *ngx_http_static_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_static_loc_conf_t *conf; + + conf = ngx_palloc(cf->pool, sizeof(ngx_http_static_loc_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + conf->redirect_cache = NULL; + + return conf; +} + + +static char *ngx_http_static_merge_loc_conf(ngx_conf_t *cf, + void *parent, void *child) +{ + ngx_http_static_loc_conf_t *prev = parent; + ngx_http_static_loc_conf_t *conf = child; + + if (conf->redirect_cache == NULL) { + conf->redirect_cache = prev->redirect_cache; + } + + return NGX_CONF_OK; +} + + +static ngx_int_t ngx_http_static_init(ngx_cycle_t *cycle) +{ + ngx_http_handler_pt *h; + ngx_http_core_main_conf_t *cmcf; + + cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module); + + h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_static_handler; + + return NGX_OK; +} diff --git a/src/http/modules/ngx_http_stub_status_module.c b/src/http/modules/ngx_http_stub_status_module.c --- a/src/http/modules/ngx_http_stub_status_module.c +++ b/src/http/modules/ngx_http_stub_status_module.c @@ -88,7 +88,8 @@ static ngx_int_t ngx_http_status_handler + 6 + 3 * NGX_ATOMIC_T_LEN + sizeof("Reading: Writing: Waiting: \n") + 3 * NGX_ATOMIC_T_LEN; - if (!(b = ngx_create_temp_buf(r->pool, size))) { + b = ngx_create_temp_buf(r->pool, size); + if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/http/modules/ngx_http_userid_filter.c b/src/http/modules/ngx_http_userid_filter_module.c rename from src/http/modules/ngx_http_userid_filter.c rename to src/http/modules/ngx_http_userid_filter_module.c --- a/src/http/modules/ngx_http_userid_filter.c +++ b/src/http/modules/ngx_http_userid_filter_module.c @@ -618,7 +618,7 @@ ngx_http_userid_domain(ngx_conf_t *cf, v } p = ngx_cpymem(new, "; domain=", sizeof("; domain=") - 1); - p = ngx_cpymem(p, domain->data, domain->len); + ngx_memcpy(p, domain->data, domain->len); domain->len += sizeof("; domain=") - 1; domain->data = new; @@ -640,7 +640,7 @@ ngx_http_userid_path(ngx_conf_t *cf, voi } p = ngx_cpymem(new, "; path=", sizeof("; path=") - 1); - p = ngx_cpymem(p, path->data, path->len); + ngx_memcpy(p, path->data, path->len); path->len += sizeof("; path=") - 1; path->data = new; diff --git a/src/http/modules/proxy/ngx_http_proxy_handler.c b/src/http/modules/proxy/ngx_http_proxy_handler.c --- a/src/http/modules/proxy/ngx_http_proxy_handler.c +++ b/src/http/modules/proxy/ngx_http_proxy_handler.c @@ -11,7 +11,9 @@ static ngx_int_t ngx_http_proxy_handler(ngx_http_request_t *r); +#if 0 static ngx_int_t ngx_http_proxy_cache_get(ngx_http_proxy_ctx_t *p); +#endif static size_t ngx_http_proxy_log_proxy_state_getlen(ngx_http_request_t *r, uintptr_t data); @@ -33,8 +35,6 @@ static char *ngx_http_proxy_merge_loc_co static char *ngx_http_proxy_set_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -static char *ngx_http_proxy_parse_upstream(ngx_str_t *url, - ngx_http_proxy_upstream_conf_t *u); static char *ngx_http_proxy_set_x_var(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -362,13 +362,20 @@ static ngx_str_t cache_reasons[] = { }; +static ngx_str_t ngx_http_proxy_uri = ngx_string("/"); + + static ngx_int_t ngx_http_proxy_handler(ngx_http_request_t *r) { ngx_http_proxy_ctx_t *p; - ngx_http_create_ctx(r, p, ngx_http_proxy_module, - sizeof(ngx_http_proxy_ctx_t), - NGX_HTTP_INTERNAL_SERVER_ERROR); + p = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_ctx_t)); + if (p == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + ngx_http_set_ctx(r, p, ngx_http_proxy_module); + p->lcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); p->request = r; @@ -382,7 +389,8 @@ static ngx_int_t ngx_http_proxy_handler( return NGX_HTTP_INTERNAL_SERVER_ERROR; } - if (!(p->state = ngx_array_push(&p->states))) { + p->state = ngx_array_push(&p->states); + if (p->state == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -439,7 +447,8 @@ static ngx_int_t ngx_http_proxy_cache_ge u = p->lcf->upstream; ctx.key.len = u->url.len + r->uri.len - u->location->len + r->args.len; - if (!(ctx.key.data = ngx_palloc(r->pool, ctx.key.len))) { + ctx.key.data = ngx_palloc(r->pool, ctx.key.len); + if (ctx.key.data == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -1072,7 +1081,8 @@ static void *ngx_http_proxy_create_loc_c { ngx_http_proxy_loc_conf_t *conf; - if (!(conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t)))) { + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t)); + if (conf == NULL) { return NGX_CONF_ERROR; } @@ -1332,7 +1342,8 @@ static char *ngx_http_proxy_set_pass(ngx unix_upstream.url.data = url->data + 7; unix_upstream.uri_part = 1; - if (!(lcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream))) { + lcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream); + if (lcf->peers == NULL) { return NGX_CONF_ERROR; } @@ -1359,7 +1370,8 @@ static char *ngx_http_proxy_set_pass(ngx inet_upstream.default_port_value = 80; inet_upstream.uri_part = 1; - if (!(lcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream))) { + lcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream); + if (lcf->peers == NULL) { return NGX_CONF_ERROR; } @@ -1372,8 +1384,13 @@ static char *ngx_http_proxy_set_pass(ngx clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + clcf->handler = ngx_http_proxy_handler; + +#if (NGX_PCRE) + lcf->upstream->location = clcf->regex ? &ngx_http_proxy_uri : &clcf->name; +#else lcf->upstream->location = &clcf->name; - clcf->handler = ngx_http_proxy_handler; +#endif if (clcf->name.data[clcf->name.len - 1] == '/') { clcf->auto_redirect = 1; @@ -1409,7 +1426,8 @@ static char *ngx_http_proxy_set_x_var(ng for (i = 0; i < cmcf->variables.nelts; i++) { if (ngx_strcasecmp(var[i].name.data, value[1].data) == 0) { - if (!(index = ngx_array_push(lcf->x_vars))) { + index = ngx_array_push(lcf->x_vars); + if (index == NULL) { return NGX_CONF_ERROR; } diff --git a/src/http/modules/proxy/ngx_http_proxy_header.c b/src/http/modules/proxy/ngx_http_proxy_header.c --- a/src/http/modules/proxy/ngx_http_proxy_header.c +++ b/src/http/modules/proxy/ngx_http_proxy_header.c @@ -87,7 +87,8 @@ int ngx_http_proxy_copy_header(ngx_http_ /* copy some header pointers and set up r->headers_out */ - if (!(ho = ngx_list_push(&r->headers_out.headers))) { + ho = ngx_list_push(&r->headers_out.headers); + if (ho == NULL) { return NGX_ERROR; } @@ -162,7 +163,8 @@ static int ngx_http_proxy_rewrite_locati r = p->request; uc = p->lcf->upstream; - if (!(location = ngx_list_push(&r->headers_out.headers))) { + location = ngx_list_push(&r->headers_out.headers); + if (location == NULL) { return NGX_ERROR; } @@ -189,7 +191,8 @@ static int ngx_http_proxy_rewrite_locati location->value.len = uc->location->len + (loc->value.len - uc->url.len) + 1; - if (!(location->value.data = ngx_palloc(r->pool, location->value.len))) { + location->value.data = ngx_palloc(r->pool, location->value.len); + if (location->value.data == NULL) { return NGX_ERROR; } diff --git a/src/http/modules/proxy/ngx_http_proxy_upstream.c b/src/http/modules/proxy/ngx_http_proxy_upstream.c --- a/src/http/modules/proxy/ngx_http_proxy_upstream.c +++ b/src/http/modules/proxy/ngx_http_proxy_upstream.c @@ -58,7 +58,8 @@ int ngx_http_proxy_request_upstream(ngx_ r = p->request; - if (!(u = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_upstream_t)))) { + u = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_upstream_t)); + if (u == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -85,7 +86,7 @@ int ngx_http_proxy_request_upstream(ngx_ static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p) { - size_t len; + size_t len, loc_len; ngx_uint_t i, escape, *index; ngx_buf_t *b; ngx_chain_t *chain; @@ -94,6 +95,7 @@ static ngx_chain_t *ngx_http_proxy_creat ngx_http_request_t *r; ngx_http_variable_t *var; ngx_http_variable_value_t *value; + ngx_http_core_loc_conf_t *clcf; ngx_http_core_main_conf_t *cmcf; ngx_http_proxy_upstream_conf_t *uc; @@ -112,16 +114,23 @@ static ngx_chain_t *ngx_http_proxy_creat len = r->method_name.len; } + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + +#if (NGX_PCRE) + loc_len = (clcf->regex) ? 1 : clcf->name.len; +#else + loc_len = clcf->name.len; +#endif + if (r->quoted_uri) { - escape = 2 * ngx_escape_uri(NULL, r->uri.data + uc->location->len, - r->uri.len - uc->location->len, - NGX_ESCAPE_URI); + escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len, + r->uri.len - loc_len, NGX_ESCAPE_URI); } else { escape = 0; } len += uc->uri.len - + r->uri.len - uc->location->len + escape + + r->uri.len - loc_len + escape + sizeof("?") - 1 + r->args.len + sizeof(http_version) - 1 + sizeof(connection_close_header) - 1 @@ -190,7 +199,8 @@ static ngx_chain_t *ngx_http_proxy_creat for (i = 0; i < p->lcf->x_vars->nelts; i++) { - if (!(value = ngx_http_get_indexed_variable(r, index[i]))) { + value = ngx_http_get_indexed_variable(r, index[i]); + if (value == NULL) { continue; } @@ -233,11 +243,13 @@ static ngx_chain_t *ngx_http_proxy_creat len++; #endif - if (!(b = ngx_create_temp_buf(r->pool, len))) { + b = ngx_create_temp_buf(r->pool, len); + if (b == NULL) { return NULL; } - if (!(chain = ngx_alloc_chain_link(r->pool))) { + chain = ngx_alloc_chain_link(r->pool); + if (chain == NULL) { return NULL; } @@ -258,14 +270,13 @@ static ngx_chain_t *ngx_http_proxy_creat b->last = ngx_cpymem(b->last, uc->uri.data, uc->uri.len); if (escape) { - ngx_escape_uri(b->last, r->uri.data + uc->location->len, - r->uri.len - uc->location->len, NGX_ESCAPE_URI); - b->last += r->uri.len - uc->location->len + escape; + ngx_escape_uri(b->last, r->uri.data + loc_len, + r->uri.len - loc_len, NGX_ESCAPE_URI); + b->last += r->uri.len - loc_len + escape; } else { - b->last = ngx_cpymem(b->last, - r->uri.data + uc->location->len, - r->uri.len - uc->location->len); + b->last = ngx_cpymem(b->last, r->uri.data + loc_len, + r->uri.len - loc_len); } if (r->args.len > 0) { @@ -379,7 +390,8 @@ static ngx_chain_t *ngx_http_proxy_creat if (p->lcf->x_vars) { for (i = 0; i < p->lcf->x_vars->nelts; i++) { - if (!(value = ngx_http_get_indexed_variable(r, index[i]))) { + value = ngx_http_get_indexed_variable(r, index[i]); + if (value == NULL) { continue; } @@ -506,7 +518,8 @@ static void ngx_http_proxy_init_upstream } - if (!(cl = ngx_http_proxy_create_request(p))) { + cl = ngx_http_proxy_create_request(p); + if (cl == NULL) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } @@ -517,7 +530,8 @@ static void ngx_http_proxy_init_upstream r->request_body->bufs = cl; - if (!(ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_log_ctx_t)))) { + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_proxy_log_ctx_t)); + if (ctx == NULL) { ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } @@ -531,7 +545,8 @@ static void ngx_http_proxy_init_upstream r->connection->log->handler = ngx_http_proxy_log_error; p->action = "connecting to upstream"; - if (!(output = ngx_pcalloc(r->pool, sizeof(ngx_output_chain_ctx_t)))) { + output = ngx_pcalloc(r->pool, sizeof(ngx_output_chain_ctx_t)); + if (output == NULL) { ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } @@ -544,7 +559,8 @@ static void ngx_http_proxy_init_upstream output->tag = (ngx_buf_tag_t) &ngx_http_proxy_module; output->output_filter = ngx_chain_writer; - if (!(writer = ngx_palloc(r->pool, sizeof(ngx_chain_writer_ctx_t)))) { + writer = ngx_palloc(r->pool, sizeof(ngx_chain_writer_ctx_t)); + if (writer == NULL) { ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } @@ -603,7 +619,8 @@ static void ngx_http_proxy_reinit_upstre state = p->state->cache_state; - if (!(p->state = ngx_push_array(&p->states))) { + p->state = ngx_array_push(&p->states); + if (p->state == NULL) { ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } @@ -775,7 +792,8 @@ static void ngx_http_proxy_connect(ngx_h if (r->request_body->buf) { if (r->request_body->temp_file) { - if (!(output->free = ngx_alloc_chain_link(r->pool))) { + output->free = ngx_alloc_chain_link(r->pool); + if (output->free == NULL) { ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); return; @@ -1005,7 +1023,7 @@ static void ngx_http_proxy_process_upstr rc = ngx_http_proxy_parse_status_line(p); if (rc == NGX_AGAIN) { - if (p->header_in->pos == p->header_in->last) { + if (p->header_in->pos == p->header_in->end) { ngx_log_error(NGX_LOG_ERR, rev->log, 0, "upstream sent too long status line"); ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_INVALID_HEADER); @@ -1158,7 +1176,8 @@ static void ngx_http_proxy_process_upstr /* a header line has been parsed successfully */ - if (!(h = ngx_list_push(&p->upstream->headers_in.headers))) { + h = ngx_list_push(&p->upstream->headers_in.headers); + if (h == NULL) { ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); return; @@ -1315,6 +1334,11 @@ static void ngx_http_proxy_send_response rc = ngx_http_send_header(r); + if (rc == NGX_ERROR || rc > NGX_OK) { + ngx_http_proxy_finalize_request(p, rc); + return; + } + p->header_sent = 1; if (p->cache && p->cache->ctx.file.fd != NGX_INVALID_FILE) { @@ -1361,7 +1385,8 @@ static void ngx_http_proxy_send_response ep->cachable = p->cachable; - if (!(ep->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)))) { + ep->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)); + if (ep->temp_file == NULL) { ngx_http_proxy_finalize_request(p, 0); return; } @@ -1381,7 +1406,8 @@ static void ngx_http_proxy_send_response ep->max_temp_file_size = p->lcf->max_temp_file_size; ep->temp_file_write_size = p->lcf->temp_file_write_size; - if (!(ep->preread_bufs = ngx_alloc_chain_link(r->pool))) { + ep->preread_bufs = ngx_alloc_chain_link(r->pool); + if (ep->preread_bufs == NULL) { ngx_http_proxy_finalize_request(p, 0); return; } @@ -1467,7 +1493,6 @@ static void ngx_http_proxy_process_body( ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, "http proxy process upstream"); p = c->data; - r = p->request; p->action = "reading upstream body"; } 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 @@ -92,7 +92,8 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma /* the main http context */ - if (!(ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)))) { + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)); + if (ctx == NULL) { return NGX_CONF_ERROR; } @@ -162,19 +163,22 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma } if (module->create_main_conf) { - if (!(ctx->main_conf[mi] = module->create_main_conf(cf))) { + ctx->main_conf[mi] = module->create_main_conf(cf); + if (ctx->main_conf[mi] == NULL) { return NGX_CONF_ERROR; } } if (module->create_srv_conf) { - if (!(ctx->srv_conf[mi] = module->create_srv_conf(cf))) { + ctx->srv_conf[mi] = module->create_srv_conf(cf); + if (ctx->srv_conf[mi] == NULL) { return NGX_CONF_ERROR; } } if (module->create_loc_conf) { - if (!(ctx->loc_conf[mi] = module->create_loc_conf(cf))) { + ctx->loc_conf[mi] = module->create_loc_conf(cf); + if (ctx->loc_conf[mi] == NULL) { return NGX_CONF_ERROR; } } @@ -261,13 +265,14 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma /* we needed http{}'s cf->ctx while the merging configuration */ + *cf = pcf; /* init lists of the handlers */ if (ngx_array_init(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers, - cf->pool, 1, sizeof(ngx_http_handler_pt)) == NGX_ERROR) + cf->pool, 1, sizeof(ngx_http_handler_pt)) != NGX_OK) { return NGX_CONF_ERROR; } @@ -278,14 +283,14 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma /* the special find config phase for a single handler */ if (ngx_array_init(&cmcf->phases[NGX_HTTP_FIND_CONFIG_PHASE].handlers, - cf->pool, 1, sizeof(ngx_http_handler_pt)) == NGX_ERROR) + cf->pool, 1, sizeof(ngx_http_handler_pt)) != NGX_OK) { return NGX_CONF_ERROR; } cmcf->phases[NGX_HTTP_FIND_CONFIG_PHASE].type = NGX_OK; - h = ngx_push_array(&cmcf->phases[NGX_HTTP_FIND_CONFIG_PHASE].handlers); + h = ngx_array_push(&cmcf->phases[NGX_HTTP_FIND_CONFIG_PHASE].handlers); if (h == NULL) { return NGX_CONF_ERROR; } @@ -294,7 +299,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma if (ngx_array_init(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers, - cf->pool, 1, sizeof(ngx_http_handler_pt)) == NGX_ERROR) + cf->pool, 1, sizeof(ngx_http_handler_pt)) != NGX_OK) { return NGX_CONF_ERROR; } @@ -303,7 +308,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma if (ngx_array_init(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers, - cf->pool, 4, sizeof(ngx_http_handler_pt)) == NGX_ERROR) + cf->pool, 4, sizeof(ngx_http_handler_pt)) != NGX_OK) { return NGX_CONF_ERROR; } @@ -317,7 +322,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma */ if (ngx_array_init(&in_ports, cf->pool, 10, sizeof(ngx_http_in_port_t)) - == NGX_ERROR) + != NGX_OK) { return NGX_CONF_ERROR; } @@ -354,7 +359,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma /* the address is already in the address list */ if (ngx_http_add_names(cf, &in_addr[a], cscfp[s]) - == NGX_ERROR) + != NGX_OK) { return NGX_CONF_ERROR; } @@ -386,7 +391,8 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma /* the INADDR_ANY is always the last address */ - if (!(inaddr = ngx_array_push(&in_port[p].addrs))) { + inaddr = ngx_array_push(&in_port[p].addrs); + if (inaddr == NULL) { return NGX_CONF_ERROR; } @@ -407,7 +413,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma in_addr[a].core_srv_conf = cscfp[s]; if (ngx_http_add_names(cf, &in_addr[a], cscfp[s]) - == NGX_ERROR) + != NGX_OK) { return NGX_CONF_ERROR; } @@ -426,7 +432,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma */ if (ngx_http_add_address(cf, &in_port[p], &lscf[l], - cscfp[s]) == NGX_ERROR) + cscfp[s]) != NGX_OK) { return NGX_CONF_ERROR; } @@ -438,14 +444,16 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma /* add the port to the in_port list */ - if (!(in_port = ngx_array_push(&in_ports))) { + in_port = ngx_array_push(&in_ports); + if (in_port == NULL) { return NGX_CONF_ERROR; } in_port->port = lscf[l].port; in_port->addrs.elts = NULL; - if (!(in_port->port_text.data = ngx_palloc(cf->pool, 7))) { + in_port->port_text.data = ngx_palloc(cf->pool, 7); + if (in_port->port_text.data == NULL) { return NGX_CONF_ERROR; } @@ -454,7 +462,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma - in_port->port_text.data; if (ngx_http_add_address(cf, in_port, &lscf[l], cscfp[s]) - == NGX_ERROR) + != NGX_OK) { return NGX_CONF_ERROR; } @@ -484,7 +492,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma for (n = 0; n < in_addr[a].names.nelts; n++) { if (in_addr[a].core_srv_conf != name[n].core_srv_conf || name[n].core_srv_conf->restrict_host_names - != NGX_HTTP_RESTRICT_HOST_OFF) + != NGX_HTTP_RESTRICT_HOST_OFF) { virtual_names = 1; break; @@ -496,7 +504,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma for (n = 0; n < in_addr[a].wildcards.nelts; n++) { if (in_addr[a].core_srv_conf != name[n].core_srv_conf || name[n].core_srv_conf->restrict_host_names - != NGX_HTTP_RESTRICT_HOST_OFF) + != NGX_HTTP_RESTRICT_HOST_OFF) { virtual_names = 1; break; @@ -532,7 +540,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma for (n = 0; n < cmcf->server_names_hash; n++) { if (ngx_array_init(&in_addr[a].hash[n], cf->pool, 5, - sizeof(ngx_http_server_name_t)) == NGX_ERROR) + sizeof(ngx_http_server_name_t)) != NGX_OK) { return NGX_CONF_ERROR; } @@ -544,7 +552,8 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma name[s].name.len, cmcf->server_names_hash); - if (!(s_name = ngx_array_push(&in_addr[a].hash[key]))) { + s_name = ngx_array_push(&in_addr[a].hash[key]); + if (s_name == NULL) { return NGX_CONF_ERROR; } @@ -575,13 +584,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma } ls->backlog = -1; -#if 0 -#if 0 - ls->nonblocking = 1; -#else - ls->nonblocking = 0; -#endif -#endif + ls->addr_ntop = 1; ls->handler = ngx_http_init_connection; @@ -612,19 +615,21 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma * the separate ngx_http_in_port_t for the all bindings */ - ngx_test_null(inport, - ngx_palloc(cf->pool, - sizeof(ngx_http_in_port_t)), - NGX_CONF_ERROR); + inport = ngx_palloc(cf->pool, sizeof(ngx_http_in_port_t)); + if (inport == NULL) { + return NGX_CONF_ERROR; + } inport->port = in_port[p].port; inport->port_text = in_port[p].port_text; /* init list of the addresses ... */ - ngx_init_array(inport->addrs, cf->pool, 1, - sizeof(ngx_http_in_addr_t), - NGX_CONF_ERROR); + if (ngx_array_init(&inport->addrs, cf->pool, 1, + sizeof(ngx_http_in_addr_t)) != NGX_OK) + { + return NGX_CONF_ERROR; + } /* ... and set up it with the first address */ @@ -636,7 +641,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma /* prepare for the next cycle */ in_port[p].addrs.elts = (char *) in_port[p].addrs.elts - + in_port[p].addrs.size; + + in_port[p].addrs.size; in_port[p].addrs.nelts--; in_addr = (ngx_http_in_addr_t *) in_port[p].addrs.elts; @@ -705,13 +710,14 @@ ngx_http_add_address(ngx_conf_t *cf, ngx if (in_port->addrs.elts == NULL) { if (ngx_array_init(&in_port->addrs, cf->pool, 10, - sizeof(ngx_http_in_addr_t)) == NGX_ERROR) + sizeof(ngx_http_in_addr_t)) != NGX_OK) { return NGX_ERROR; } } - if (!(in_addr = ngx_array_push(&in_port->addrs))) { + in_addr = ngx_array_push(&in_port->addrs); + if (in_addr == NULL) { return NGX_ERROR; } @@ -750,7 +756,7 @@ ngx_http_add_names(ngx_conf_t *cf, ngx_h if (in_addr->names.elts == NULL) { if (ngx_array_init(&in_addr->names, cf->pool, 10, - sizeof(ngx_http_server_name_t)) == NGX_ERROR) + sizeof(ngx_http_server_name_t)) != NGX_OK) { return NGX_ERROR; } @@ -758,7 +764,7 @@ ngx_http_add_names(ngx_conf_t *cf, ngx_h if (in_addr->wildcards.elts == NULL) { if (ngx_array_init(&in_addr->wildcards, cf->pool, 10, - sizeof(ngx_http_server_name_t)) == NGX_ERROR) + sizeof(ngx_http_server_name_t)) != NGX_OK) { return NGX_ERROR; } @@ -785,7 +791,8 @@ ngx_http_add_names(ngx_conf_t *cf, ngx_h array = &in_addr->names; } - if (!(name = ngx_array_push(array))) { + name = ngx_array_push(array); + if (name == NULL) { return NGX_ERROR; } 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 @@ -16,6 +16,8 @@ typedef struct ngx_http_request_s ngx_h typedef struct ngx_http_log_ctx_s ngx_http_log_ctx_t; typedef struct ngx_http_cleanup_s ngx_http_cleanup_t; typedef struct ngx_http_in_addr_s ngx_http_in_addr_t; +typedef struct ngx_http_variable_value_s ngx_http_variable_value_t; + #if (NGX_HTTP_CACHE) #include @@ -27,7 +29,7 @@ typedef struct ngx_http_in_addr_s ngx_h #include #include #include -#include +#include #include #include @@ -46,16 +48,7 @@ struct ngx_http_log_ctx_s { #define ngx_http_get_module_err_ctx(r, module) \ ((r)->err_ctx ? (r)->err_ctx[module.ctx_index] : (r)->ctx[module.ctx_index]) -/* STUB */ -#define ngx_http_create_ctx(r, cx, module, size, error) \ - do { \ - ngx_test_null(cx, ngx_pcalloc(r->pool, size), error); \ - r->ctx[module.ctx_index] = cx; \ - } while (0) -/**/ - #define ngx_http_set_ctx(r, c, module) r->ctx[module.ctx_index] = c; - #define ngx_http_delete_ctx(r, module) r->ctx[module.ctx_index] = NULL; diff --git a/src/http/ngx_http_busy_lock.c b/src/http/ngx_http_busy_lock.c --- a/src/http/ngx_http_busy_lock.c +++ b/src/http/ngx_http_busy_lock.c @@ -205,13 +205,15 @@ char *ngx_http_set_busy_lock_slot(ngx_co } /* ngx_calloc_shared() */ - if (!(bl = ngx_pcalloc(cf->pool, sizeof(ngx_http_busy_lock_t)))) { + bl = ngx_pcalloc(cf->pool, sizeof(ngx_http_busy_lock_t)); + if (bl == NULL) { return NGX_CONF_ERROR; } *blp = bl; /* ngx_calloc_shared() */ - if (!(bl->mutex = ngx_pcalloc(cf->pool, sizeof(ngx_event_mutex_t)))) { + bl->mutex = ngx_pcalloc(cf->pool, sizeof(ngx_event_mutex_t)); + if (bl->mutex == NULL) { return NGX_CONF_ERROR; } diff --git a/src/http/ngx_http_config.h b/src/http/ngx_http_config.h --- a/src/http/ngx_http_config.h +++ b/src/http/ngx_http_config.h @@ -59,15 +59,15 @@ typedef struct { */ #define ngx_http_conf_get_module_main_conf(cf, module) \ - ((ngx_http_conf_ctx_t *) cf->ctx)->main_conf[module.ctx_index] + ((ngx_http_conf_ctx_t *) cf->ctx)->main_conf[module.ctx_index] #define ngx_http_conf_get_module_srv_conf(cf, module) \ - ((ngx_http_conf_ctx_t *) cf->ctx)->srv_conf[module.ctx_index] + ((ngx_http_conf_ctx_t *) cf->ctx)->srv_conf[module.ctx_index] #define ngx_http_conf_get_module_loc_conf(cf, module) \ - ((ngx_http_conf_ctx_t *) cf->ctx)->loc_conf[module.ctx_index] + ((ngx_http_conf_ctx_t *) cf->ctx)->loc_conf[module.ctx_index] #define ngx_http_cycle_get_module_main_conf(cycle, module) \ - ((ngx_http_conf_ctx_t *) \ - cycle->conf_ctx[ngx_http_module.index])->main_conf[module.ctx_index] + ((ngx_http_conf_ctx_t *) \ + cycle->conf_ctx[ngx_http_module.index])->main_conf[module.ctx_index] diff --git a/src/http/ngx_http_copy_filter.c b/src/http/ngx_http_copy_filter.c deleted file mode 100644 --- a/src/http/ngx_http_copy_filter.c +++ /dev/null @@ -1,132 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#include -#include -#include - - -typedef struct { - ngx_bufs_t bufs; -} ngx_http_copy_filter_conf_t; - - -static void *ngx_http_copy_filter_create_conf(ngx_conf_t *cf); -static char *ngx_http_copy_filter_merge_conf(ngx_conf_t *cf, - void *parent, void *child); -static ngx_int_t ngx_http_copy_filter_init(ngx_cycle_t *cycle); - - -static ngx_command_t ngx_http_copy_filter_commands[] = { - - {ngx_string("output_buffers"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, - ngx_conf_set_bufs_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_copy_filter_conf_t, bufs), - NULL}, - - ngx_null_command -}; - - -static ngx_http_module_t ngx_http_copy_filter_module_ctx = { - NULL, /* pre conf */ - - NULL, /* create main configuration */ - NULL, /* init main configuration */ - - NULL, /* create server configuration */ - NULL, /* merge server configuration */ - - ngx_http_copy_filter_create_conf, /* create location configuration */ - ngx_http_copy_filter_merge_conf /* merge location configuration */ -}; - - -ngx_module_t ngx_http_copy_filter_module = { - NGX_MODULE, - &ngx_http_copy_filter_module_ctx, /* module context */ - ngx_http_copy_filter_commands, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - ngx_http_copy_filter_init, /* init module */ - NULL /* init process */ -}; - - -static ngx_http_output_body_filter_pt ngx_http_next_filter; - - -ngx_int_t ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in) -{ - ngx_output_chain_ctx_t *ctx; - ngx_http_copy_filter_conf_t *conf; - - if (r->connection->write->error) { - return NGX_ERROR; - } - - ctx = ngx_http_get_module_ctx(r->main ? r->main : r, - ngx_http_copy_filter_module); - - if (ctx == NULL) { - conf = ngx_http_get_module_loc_conf(r->main ? r->main : r, - ngx_http_copy_filter_module); - - ngx_http_create_ctx(r, ctx, ngx_http_copy_filter_module, - sizeof(ngx_output_chain_ctx_t), NGX_ERROR); - - ctx->sendfile = r->connection->sendfile; - ctx->need_in_memory = r->filter_need_in_memory; - ctx->need_in_temp = r->filter_need_temporary; - - ctx->pool = r->pool; - ctx->bufs = conf->bufs; - ctx->tag = (ngx_buf_tag_t) &ngx_http_copy_filter_module; - - ctx->output_filter = (ngx_output_chain_filter_pt) ngx_http_next_filter; - ctx->filter_ctx = r; - - } - - return ngx_output_chain(ctx, in); -} - - -static void *ngx_http_copy_filter_create_conf(ngx_conf_t *cf) -{ - ngx_http_copy_filter_conf_t *conf; - - ngx_test_null(conf, - ngx_palloc(cf->pool, sizeof(ngx_http_copy_filter_conf_t)), - NULL); - - conf->bufs.num = 0; - - return conf; -} - - -static char *ngx_http_copy_filter_merge_conf(ngx_conf_t *cf, - void *parent, void *child) -{ - ngx_http_copy_filter_conf_t *prev = parent; - ngx_http_copy_filter_conf_t *conf = child; - - ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, 1, 32768); - - return NULL; -} - - -static ngx_int_t ngx_http_copy_filter_init(ngx_cycle_t *cycle) -{ - ngx_http_next_filter = ngx_http_top_body_filter; - ngx_http_top_body_filter = ngx_http_copy_filter; - - return NGX_OK; -} - diff --git a/src/http/ngx_http_copy_filter_module.c b/src/http/ngx_http_copy_filter_module.c new file mode 100644 --- /dev/null +++ b/src/http/ngx_http_copy_filter_module.c @@ -0,0 +1,140 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +typedef struct { + ngx_bufs_t bufs; +} ngx_http_copy_filter_conf_t; + + +static void *ngx_http_copy_filter_create_conf(ngx_conf_t *cf); +static char *ngx_http_copy_filter_merge_conf(ngx_conf_t *cf, + void *parent, void *child); +static ngx_int_t ngx_http_copy_filter_init(ngx_cycle_t *cycle); + + +static ngx_command_t ngx_http_copy_filter_commands[] = { + + { ngx_string("output_buffers"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, + ngx_conf_set_bufs_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_copy_filter_conf_t, bufs), + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_copy_filter_module_ctx = { + NULL, /* pre conf */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_copy_filter_create_conf, /* create location configuration */ + ngx_http_copy_filter_merge_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_copy_filter_module = { + NGX_MODULE, + &ngx_http_copy_filter_module_ctx, /* module context */ + ngx_http_copy_filter_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + ngx_http_copy_filter_init, /* init module */ + NULL /* init process */ +}; + + +static ngx_http_output_body_filter_pt ngx_http_next_filter; + + +static ngx_int_t +ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in) +{ + ngx_output_chain_ctx_t *ctx; + ngx_http_copy_filter_conf_t *conf; + + if (r->connection->write->error) { + return NGX_ERROR; + } + + ctx = ngx_http_get_module_ctx(r->main ? r->main : r, + ngx_http_copy_filter_module); + + if (ctx == NULL) { + conf = ngx_http_get_module_loc_conf(r->main ? r->main : r, + ngx_http_copy_filter_module); + + ctx = ngx_pcalloc(r->pool, sizeof(ngx_output_chain_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_http_set_ctx(r, ctx, ngx_http_copy_filter_module); + + ctx->sendfile = r->connection->sendfile; + ctx->need_in_memory = r->filter_need_in_memory; + ctx->need_in_temp = r->filter_need_temporary; + + ctx->pool = r->pool; + ctx->bufs = conf->bufs; + ctx->tag = (ngx_buf_tag_t) &ngx_http_copy_filter_module; + + ctx->output_filter = (ngx_output_chain_filter_pt) ngx_http_next_filter; + ctx->filter_ctx = r; + + } + + return ngx_output_chain(ctx, in); +} + + +static void * +ngx_http_copy_filter_create_conf(ngx_conf_t *cf) +{ + ngx_http_copy_filter_conf_t *conf; + + conf = ngx_palloc(cf->pool, sizeof(ngx_http_copy_filter_conf_t)); + if (conf == NULL) { + return NULL; + } + + conf->bufs.num = 0; + + return conf; +} + + +static char * +ngx_http_copy_filter_merge_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_copy_filter_conf_t *prev = parent; + ngx_http_copy_filter_conf_t *conf = child; + + ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, 1, 32768); + + return NULL; +} + + +static ngx_int_t +ngx_http_copy_filter_init(ngx_cycle_t *cycle) +{ + ngx_http_next_filter = ngx_http_top_body_filter; + ngx_http_top_body_filter = ngx_http_copy_filter; + + return NGX_OK; +} + 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 @@ -785,7 +785,8 @@ ngx_http_set_content_type(ngx_http_reque } if (i < r->exten.len) { - if (!(p = ngx_palloc(r->pool, r->exten.len))) { + p = ngx_palloc(r->pool, r->exten.len); + if (p == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -897,7 +898,8 @@ ngx_http_set_exten(ngx_http_request_t *r r->exten.len = r->uri.len - i - 1; if (r->exten.len > 0) { - if (!(r->exten.data = ngx_palloc(r->pool, r->exten.len + 1))) { + r->exten.data = ngx_palloc(r->pool, r->exten.len + 1); + if (r->exten.data == NULL) { return NGX_ERROR; } @@ -997,7 +999,8 @@ ngx_http_core_server(ngx_conf_t *cf, ngx ngx_http_core_srv_conf_t *cscf, **cscfp; ngx_http_core_main_conf_t *cmcf; - if (!(ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)))) { + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)); + if (ctx == NULL) { return NGX_CONF_ERROR; } @@ -1026,7 +1029,8 @@ ngx_http_core_server(ngx_conf_t *cf, ngx module = ngx_modules[m]->ctx; if (module->create_srv_conf) { - if (!(mconf = module->create_srv_conf(cf))) { + mconf = module->create_srv_conf(cf); + if (mconf == NULL) { return NGX_CONF_ERROR; } @@ -1034,7 +1038,8 @@ ngx_http_core_server(ngx_conf_t *cf, ngx } if (module->create_loc_conf) { - if (!(mconf = module->create_loc_conf(cf))) { + mconf = module->create_loc_conf(cf); + if (mconf == NULL) { return NGX_CONF_ERROR; } @@ -1051,7 +1056,8 @@ ngx_http_core_server(ngx_conf_t *cf, ngx cmcf = ctx->main_conf[ngx_http_core_module.ctx_index]; - if (!(cscfp = ngx_array_push(&cmcf->servers))) { + cscfp = ngx_array_push(&cmcf->servers); + if (cscfp == NULL) { return NGX_CONF_ERROR; } @@ -1095,7 +1101,8 @@ ngx_http_core_location(ngx_conf_t *cf, n u_char errstr[NGX_MAX_CONF_ERRSTR]; #endif - if (!(ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)))) { + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)); + if (ctx == NULL) { return NGX_CONF_ERROR; } @@ -1181,7 +1188,9 @@ ngx_http_core_location(ngx_conf_t *cf, n if (pclcf->name.len == 0) { cscf = ctx->srv_conf[ngx_http_core_module.ctx_index]; - if (!(clcfp = ngx_array_push(&cscf->locations))) { + + clcfp = ngx_array_push(&cscf->locations); + if (clcfp == NULL) { return NGX_CONF_ERROR; } @@ -1214,11 +1223,15 @@ ngx_http_core_location(ngx_conf_t *cf, n } if (pclcf->locations.elts == NULL) { - ngx_init_array(pclcf->locations, cf->pool, 4, sizeof(void *), - NGX_CONF_ERROR); + if (ngx_array_init(&pclcf->locations, cf->pool, 4, sizeof(void *)) + != NGX_OK) + { + return NGX_CONF_ERROR; + } } - if (!(clcfp = ngx_push_array(&pclcf->locations))) { + clcfp = ngx_array_push(&pclcf->locations); + if (clcfp == NULL) { return NGX_CONF_ERROR; } } @@ -1347,7 +1360,8 @@ ngx_http_core_type(ngx_conf_t *cf, ngx_c for (i = 1; i < cf->args->nelts; i++) { ngx_http_types_hash_key(key, value[i]); - if (!(type = ngx_array_push(&lcf->types[key]))) { + type = ngx_array_push(&lcf->types[key]); + if (type == NULL) { return NGX_CONF_ERROR; } @@ -1364,7 +1378,8 @@ ngx_http_core_create_main_conf(ngx_conf_ { ngx_http_core_main_conf_t *cmcf; - if (!(cmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_core_main_conf_t)))) { + cmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_core_main_conf_t)); + if (cmcf == NULL) { return NGX_CONF_ERROR; } @@ -1403,7 +1418,8 @@ ngx_http_core_create_srv_conf(ngx_conf_t { ngx_http_core_srv_conf_t *cscf; - if (!(cscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_core_srv_conf_t)))) { + cscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_core_srv_conf_t)); + if (cscf == NULL) { return NGX_CONF_ERROR; } @@ -1455,7 +1471,8 @@ ngx_http_core_merge_srv_conf(ngx_conf_t /* TODO: it does not merge, it inits only */ if (conf->listen.nelts == 0) { - if (!(ls = ngx_array_push(&conf->listen))) { + ls = ngx_array_push(&conf->listen); + if (ls == NULL) { return NGX_CONF_ERROR; } @@ -1470,11 +1487,13 @@ ngx_http_core_merge_srv_conf(ngx_conf_t } if (conf->server_names.nelts == 0) { - if (!(sn = ngx_array_push(&conf->server_names))) { + sn = ngx_array_push(&conf->server_names); + if (sn == NULL) { return NGX_CONF_ERROR; } - if (!(sn->name.data = ngx_palloc(cf->pool, NGX_MAXHOSTNAMELEN))) { + sn->name.data = ngx_palloc(cf->pool, NGX_MAXHOSTNAMELEN); + if (sn->name.data == NULL) { return NGX_CONF_ERROR; } @@ -1528,7 +1547,8 @@ ngx_http_core_create_loc_conf(ngx_conf_t { ngx_http_core_loc_conf_t *lcf; - if (!(lcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_core_loc_conf_t)))) { + lcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_core_loc_conf_t)); + if (lcf == NULL) { return NGX_CONF_ERROR; } @@ -1618,7 +1638,8 @@ ngx_http_core_merge_loc_conf(ngx_conf_t ngx_http_types_hash_key(key, ngx_http_core_default_types[i].exten); - if (!(type = ngx_array_push(&conf->types[key]))) { + type = ngx_array_push(&conf->types[key]); + if (type == NULL) { return NGX_CONF_ERROR; } @@ -1700,7 +1721,8 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx * add resolved name to server names ??? */ - if (!(ls = ngx_array_push(&scf->listen))) { + ls = ngx_array_push(&scf->listen); + if (ls == NULL) { return NGX_CONF_ERROR; } @@ -1796,7 +1818,8 @@ ngx_http_core_server_name(ngx_conf_t *cf return NGX_CONF_ERROR; } - if (!(sn = ngx_array_push(&scf->server_names))) { + sn = ngx_array_push(&scf->server_names); + if (sn == NULL) { return NGX_CONF_ERROR; } @@ -1908,7 +1931,8 @@ ngx_http_core_error_page(ngx_conf_t *cf, } for (i = 1; i < cf->args->nelts - n; i++) { - if (!(err = ngx_array_push(lcf->error_pages))) { + err = ngx_array_push(lcf->error_pages); + if (err == NULL) { return NGX_CONF_ERROR; } @@ -1981,7 +2005,8 @@ ngx_http_core_error_log(ngx_conf_t *cf, { ngx_http_core_loc_conf_t *lcf = conf; - if (!(lcf->err_log = ngx_log_create_errlog(cf->cycle, cf->args))) { + lcf->err_log = ngx_log_create_errlog(cf->cycle, cf->args); + if (lcf->err_log == NULL) { return NGX_CONF_ERROR; } @@ -2021,5 +2046,5 @@ ngx_http_core_lowat_check(ngx_conf_t *cf static ngx_int_t ngx_http_core_init(ngx_cycle_t *cycle) { - return ngx_http_core_variables_init(cycle); + return ngx_http_variables_init(cycle); } diff --git a/src/http/ngx_http_header_filter.c b/src/http/ngx_http_header_filter.c deleted file mode 100644 --- a/src/http/ngx_http_header_filter.c +++ /dev/null @@ -1,481 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#include -#include -#include -#include - - -static ngx_int_t ngx_http_header_filter_init(ngx_cycle_t *cycle); -static ngx_int_t ngx_http_header_filter(ngx_http_request_t *r); - - -static ngx_http_module_t ngx_http_header_filter_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_header_filter_module = { - NGX_MODULE, - &ngx_http_header_filter_module_ctx, /* module context */ - NULL, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - ngx_http_header_filter_init, /* init module */ - NULL /* init process */ -}; - - -static char server_string[] = "Server: " NGINX_VER CRLF; - - -static ngx_str_t http_codes[] = { - - ngx_string("200 OK"), - ngx_null_string, /* "201 Created" */ - ngx_null_string, /* "202 Accepted" */ - ngx_null_string, /* "203 Non-Authoritative Information" */ - ngx_null_string, /* "204 No Content" */ - ngx_null_string, /* "205 Reset Content" */ - ngx_string("206 Partial Content"), - - /* ngx_null_string, */ /* "207 Multi-Status" */ - -#define NGX_HTTP_LEVEL_200 7 - - /* ngx_null_string, */ /* "300 Multiple Choices" */ - - ngx_string("301 Moved Permanently"), - ngx_string("302 Moved Temporarily"), - ngx_null_string, /* "303 See Other" */ - ngx_string("304 Not Modified"), - - /* ngx_null_string, */ /* "305 Use Proxy" */ - /* ngx_null_string, */ /* "306 unused" */ - /* ngx_null_string, */ /* "307 Temporary Redirect" */ - -#define NGX_HTTP_LEVEL_300 4 - - ngx_string("400 Bad Request"), - ngx_string("401 Unauthorized"), - ngx_string("402 Payment Required"), - ngx_string("403 Forbidden"), - ngx_string("404 Not Found"), - ngx_string("405 Not Allowed"), - ngx_string("406 Not Acceptable"), - ngx_null_string, /* "407 Proxy Authentication Required" */ - ngx_string("408 Request Time-out"), - ngx_null_string, /* "409 Conflict" */ - ngx_string("410 Gone"), - ngx_string("411 Length Required"), - ngx_null_string, /* "412 Precondition Failed" */ - ngx_string("413 Request Entity Too Large"), - ngx_null_string, /* "414 Request-URI Too Large", but we never send it - * because we treat such requests as the HTTP/0.9 - * requests and send only a body without a header - */ - ngx_null_string, /* "415 Unsupported Media Type" */ - ngx_string("416 Requested Range Not Satisfiable"), - - /* ngx_null_string, */ /* "417 Expectation Failed" */ - /* ngx_null_string, */ /* "418 unused" */ - /* ngx_null_string, */ /* "419 unused" */ - /* ngx_null_string, */ /* "420 unused" */ - /* ngx_null_string, */ /* "421 unused" */ - /* ngx_null_string, */ /* "422 Unprocessable Entity" */ - /* ngx_null_string, */ /* "423 Locked" */ - /* ngx_null_string, */ /* "424 Failed Dependency" */ - -#define NGX_HTTP_LEVEL_400 17 - - ngx_string("500 Internal Server Error"), - ngx_string("501 Method Not Implemented"), - ngx_string("502 Bad Gateway"), - ngx_string("503 Service Temporarily Unavailable"), - ngx_string("504 Gateway Time-out") - - /* ngx_null_string, */ /* "505 HTTP Version Not Supported" */ - /* ngx_null_string, */ /* "506 Variant Also Negotiates" */ - /* ngx_null_string, */ /* "507 Insufficient Storage" */ - /* ngx_null_string, */ /* "508 unused" */ - /* ngx_null_string, */ /* "509 unused" */ - /* ngx_null_string, */ /* "510 Not Extended" */ -}; - - -ngx_http_header_t ngx_http_headers_out[] = { - { ngx_string("Server"), offsetof(ngx_http_headers_out_t, server) }, - { ngx_string("Date"), offsetof(ngx_http_headers_out_t, date) }, - { ngx_string("Content-Type"), - offsetof(ngx_http_headers_out_t, content_type) }, - { ngx_string("Content-Length"), - offsetof(ngx_http_headers_out_t, content_length) }, - { ngx_string("Content-Encoding"), - offsetof(ngx_http_headers_out_t, content_encoding) }, - { ngx_string("Location"), offsetof(ngx_http_headers_out_t, location) }, - { ngx_string("Last-Modified"), - offsetof(ngx_http_headers_out_t, last_modified) }, - { ngx_string("Accept-Ranges"), - offsetof(ngx_http_headers_out_t, accept_ranges) }, - { ngx_string("Expires"), offsetof(ngx_http_headers_out_t, expires) }, - { ngx_string("Cache-Control"), - offsetof(ngx_http_headers_out_t, cache_control) }, - { ngx_string("ETag"), offsetof(ngx_http_headers_out_t, etag) }, - - { ngx_null_string, 0 } -}; - - -static ngx_int_t -ngx_http_header_filter(ngx_http_request_t *r) -{ - u_char *p; - size_t len; - ngx_uint_t status, i; - ngx_buf_t *b; - ngx_chain_t *ln; - ngx_list_part_t *part; - ngx_table_elt_t *header; - ngx_http_core_loc_conf_t *clcf; - - if (r->http_version < NGX_HTTP_VERSION_10) { - return NGX_OK; - } - - if (r->method == NGX_HTTP_HEAD) { - r->header_only = 1; - } - - if (r->headers_out.last_modified_time != -1) { - if (r->headers_out.status != NGX_HTTP_OK - && r->headers_out.status != NGX_HTTP_NOT_MODIFIED - && r->headers_out.status != NGX_HTTP_PARTIAL_CONTENT) - { - r->headers_out.last_modified_time = -1; - r->headers_out.last_modified = NULL; - } - } - - len = sizeof("HTTP/1.x ") - 1 + sizeof(CRLF) - 1 - /* the end of the header */ - + sizeof(CRLF) - 1; - - /* status line */ - - if (r->headers_out.status_line.len) { - len += r->headers_out.status_line.len; -#if (NGX_SUPPRESS_WARN) - status = NGX_INVALID_ARRAY_INDEX; -#endif - - } else { - - if (r->headers_out.status < NGX_HTTP_MOVED_PERMANENTLY) { - /* 2XX */ - status = r->headers_out.status - NGX_HTTP_OK; - - } else if (r->headers_out.status < NGX_HTTP_BAD_REQUEST) { - /* 3XX */ - status = r->headers_out.status - NGX_HTTP_MOVED_PERMANENTLY - + NGX_HTTP_LEVEL_200; - - if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED) { - r->header_only = 1; - } - - } else if (r->headers_out.status < NGX_HTTP_INTERNAL_SERVER_ERROR) { - /* 4XX */ - status = r->headers_out.status - NGX_HTTP_BAD_REQUEST - + NGX_HTTP_LEVEL_200 - + NGX_HTTP_LEVEL_300; - - } else { - /* 5XX */ - status = r->headers_out.status - NGX_HTTP_INTERNAL_SERVER_ERROR - + NGX_HTTP_LEVEL_200 - + NGX_HTTP_LEVEL_300 - + NGX_HTTP_LEVEL_400; - } - - len += http_codes[status].len; - } - - if (r->headers_out.server && r->headers_out.server->key.len) { - len += r->headers_out.server->key.len - + r->headers_out.server->value.len + 2; - } else { - len += sizeof(server_string) - 1; - } - - if (r->headers_out.date && r->headers_out.date->key.len) { - len += r->headers_out.date->key.len - + r->headers_out.date->value.len + 2; - } else { - len += sizeof("Date: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1; - } - - if (r->headers_out.content_length == NULL) { - if (r->headers_out.content_length_n >= 0) { - len += sizeof("Content-Length: ") - 1 + NGX_OFF_T_LEN + 2; - } - } - - if (r->headers_out.content_type && r->headers_out.content_type->value.len) { - r->headers_out.content_type->key.len = 0; - len += sizeof("Content-Type: ") - 1 - + r->headers_out.content_type->value.len + 2; - - if (r->headers_out.charset.len) { - len += sizeof("; charset=") - 1 + r->headers_out.charset.len; - } - } - - if (r->headers_out.location - && r->headers_out.location->value.len - && r->headers_out.location->value.data[0] == '/') - { - r->headers_out.location->key.len = 0; - len += sizeof("Location: http://") - 1 - + r->server_name.len + r->headers_out.location->value.len + 2; - - if (r->port != 80) { - len += r->port_text->len; - } - } - - if (r->headers_out.last_modified && r->headers_out.last_modified->key.len) { - len += r->headers_out.last_modified->key.len - + r->headers_out.last_modified->value.len + 2; - - } else if (r->headers_out.last_modified_time != -1) { - len += sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1; - } - - if (r->chunked) { - len += sizeof("Transfer-Encoding: chunked" CRLF) - 1; - } - - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - - if (r->keepalive) { - len += sizeof("Connection: keep-alive" CRLF) - 1; - - /* - * MSIE and Opera ignore the "Keep-Alive: timeout=" header. - * MSIE keeps the connection alive for about 60-65 seconds. - * Opera keeps the connection alive very long. - * Mozilla keeps the connection alive for N plus about 1-10 seconds. - * Konqueror keeps the connection alive for about N seconds. - */ - - if (clcf->keepalive_header) { - len += sizeof("Keep-Alive: timeout=") - 1 + NGX_TIME_T_LEN + 2; - } - - } else { - len += sizeof("Connection: closed" CRLF) - 1; - } - - part = &r->headers_out.headers.part; - header = part->elts; - - for (i = 0; /* void */; i++) { - - if (i >= part->nelts) { - if (part->next == NULL) { - break; - } - - part = part->next; - header = part->elts; - i = 0; - } - - if (header[i].key.len == 0) { - continue; - } - - len += header[i].key.len + sizeof(": ") - 1 + header[i].value.len - + sizeof(CRLF) - 1; - } - - if (!(b = ngx_create_temp_buf(r->pool, len))) { - return NGX_ERROR; - } - - /* "HTTP/1.x " */ - b->last = ngx_cpymem(b->last, "HTTP/1.1 ", sizeof("HTTP/1.x ") - 1); - - /* status line */ - if (r->headers_out.status_line.len) { - b->last = ngx_cpymem(b->last, r->headers_out.status_line.data, - r->headers_out.status_line.len); - - } else { - b->last = ngx_cpymem(b->last, http_codes[status].data, - http_codes[status].len); - } - *b->last++ = CR; *b->last++ = LF; - - if (!(r->headers_out.server && r->headers_out.server->key.len)) { - b->last = ngx_cpymem(b->last, server_string, sizeof(server_string) - 1); - } - - if (!(r->headers_out.date && r->headers_out.date->key.len)) { - b->last = ngx_cpymem(b->last, "Date: ", sizeof("Date: ") - 1); - b->last = ngx_cpymem(b->last, ngx_cached_http_time.data, - ngx_cached_http_time.len); - - *b->last++ = CR; *b->last++ = LF; - } - - if (r->headers_out.content_length == NULL) { - if (r->headers_out.content_length_n >= 0) { - b->last = ngx_sprintf(b->last, "Content-Length: %O" CRLF, - r->headers_out.content_length_n); - } - } - - if (r->headers_out.content_type && r->headers_out.content_type->value.len) { - b->last = ngx_cpymem(b->last, "Content-Type: ", - sizeof("Content-Type: ") - 1); - p = b->last; - b->last = ngx_cpymem(b->last, r->headers_out.content_type->value.data, - r->headers_out.content_type->value.len); - - if (r->headers_out.charset.len) { - b->last = ngx_cpymem(b->last, "; charset=", - sizeof("; charset=") - 1); - b->last = ngx_cpymem(b->last, r->headers_out.charset.data, - r->headers_out.charset.len); - - r->headers_out.content_type->value.len = b->last - p; - r->headers_out.content_type->value.data = p; - } - - *b->last++ = CR; *b->last++ = LF; - } - - if (r->headers_out.location - && r->headers_out.location->value.len - && r->headers_out.location->value.data[0] == '/') - { - p = b->last + sizeof("Location: ") - 1; - b->last = ngx_cpymem(b->last, "Location: http://", - sizeof("Location: http://") - 1); - b->last = ngx_cpymem(b->last, r->server_name.data, - r->server_name.len); - if (r->port != 80) { - b->last = ngx_cpymem(b->last, r->port_text->data, - r->port_text->len); - } - - b->last = ngx_cpymem(b->last, r->headers_out.location->value.data, - r->headers_out.location->value.len); - - r->headers_out.location->value.len = b->last - p; - r->headers_out.location->value.data = p; - - *b->last++ = CR; *b->last++ = LF; - } - - if (!(r->headers_out.last_modified && r->headers_out.last_modified->key.len) - && r->headers_out.last_modified_time != -1) - { - b->last = ngx_cpymem(b->last, "Last-Modified: ", - sizeof("Last-Modified: ") - 1); - b->last = ngx_http_time(b->last, r->headers_out.last_modified_time); - - *b->last++ = CR; *b->last++ = LF; - } - - if (r->chunked) { - b->last = ngx_cpymem(b->last, "Transfer-Encoding: chunked" CRLF, - sizeof("Transfer-Encoding: chunked" CRLF) - 1); - } - - if (r->keepalive) { - b->last = ngx_cpymem(b->last, "Connection: keep-alive" CRLF, - sizeof("Connection: keep-alive" CRLF) - 1); - - if (clcf->keepalive_header) { - b->last = ngx_sprintf(b->last, "Keep-Alive: timeout=%T" CRLF, - clcf->keepalive_header); - } - - } else { - b->last = ngx_cpymem(b->last, "Connection: close" CRLF, - sizeof("Connection: close" CRLF) - 1); - } - - part = &r->headers_out.headers.part; - header = part->elts; - - for (i = 0; /* void */; i++) { - - if (i >= part->nelts) { - if (part->next == NULL) { - break; - } - - part = part->next; - header = part->elts; - i = 0; - } - - if (header[i].key.len == 0) { - continue; - } - - b->last = ngx_cpymem(b->last, header[i].key.data, header[i].key.len); - *b->last++ = ':' ; *b->last++ = ' ' ; - - b->last = ngx_cpymem(b->last, header[i].value.data, - header[i].value.len); - *b->last++ = CR; *b->last++ = LF; - } - -#if (NGX_DEBUG) - *b->last = '\0'; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "%s\n", b->pos); -#endif - - /* the end of HTTP header */ - *b->last++ = CR; *b->last++ = LF; - - r->header_size = b->last - b->pos; - - if (r->header_only) { - b->last_buf = 1; - } - - if (!(ln = ngx_alloc_chain_link(r->pool))) { - return NGX_ERROR; - } - - ln->buf = b; - ln->next = NULL; - - return ngx_http_write_filter(r, ln); -} - - -static ngx_int_t -ngx_http_header_filter_init(ngx_cycle_t *cycle) -{ - ngx_http_top_header_filter = ngx_http_header_filter; - - return NGX_OK; -} diff --git a/src/http/ngx_http_header_filter_module.c b/src/http/ngx_http_header_filter_module.c new file mode 100644 --- /dev/null +++ b/src/http/ngx_http_header_filter_module.c @@ -0,0 +1,478 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include +#include + + +static ngx_int_t ngx_http_header_filter_init(ngx_cycle_t *cycle); +static ngx_int_t ngx_http_header_filter(ngx_http_request_t *r); + + +static ngx_http_module_t ngx_http_header_filter_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_header_filter_module = { + NGX_MODULE, + &ngx_http_header_filter_module_ctx, /* module context */ + NULL, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + ngx_http_header_filter_init, /* init module */ + NULL /* init process */ +}; + + +static char server_string[] = "Server: " NGINX_VER CRLF; + + +static ngx_str_t http_codes[] = { + + ngx_string("200 OK"), + ngx_null_string, /* "201 Created" */ + ngx_null_string, /* "202 Accepted" */ + ngx_null_string, /* "203 Non-Authoritative Information" */ + ngx_null_string, /* "204 No Content" */ + ngx_null_string, /* "205 Reset Content" */ + ngx_string("206 Partial Content"), + + /* ngx_null_string, */ /* "207 Multi-Status" */ + +#define NGX_HTTP_LEVEL_200 7 + + /* ngx_null_string, */ /* "300 Multiple Choices" */ + + ngx_string("301 Moved Permanently"), + ngx_string("302 Moved Temporarily"), + ngx_null_string, /* "303 See Other" */ + ngx_string("304 Not Modified"), + + /* ngx_null_string, */ /* "305 Use Proxy" */ + /* ngx_null_string, */ /* "306 unused" */ + /* ngx_null_string, */ /* "307 Temporary Redirect" */ + +#define NGX_HTTP_LEVEL_300 4 + + ngx_string("400 Bad Request"), + ngx_string("401 Unauthorized"), + ngx_string("402 Payment Required"), + ngx_string("403 Forbidden"), + ngx_string("404 Not Found"), + ngx_string("405 Not Allowed"), + ngx_string("406 Not Acceptable"), + ngx_null_string, /* "407 Proxy Authentication Required" */ + ngx_string("408 Request Time-out"), + ngx_null_string, /* "409 Conflict" */ + ngx_string("410 Gone"), + ngx_string("411 Length Required"), + ngx_null_string, /* "412 Precondition Failed" */ + ngx_string("413 Request Entity Too Large"), + ngx_null_string, /* "414 Request-URI Too Large", but we never send it + * because we treat such requests as the HTTP/0.9 + * requests and send only a body without a header + */ + ngx_null_string, /* "415 Unsupported Media Type" */ + ngx_string("416 Requested Range Not Satisfiable"), + + /* ngx_null_string, */ /* "417 Expectation Failed" */ + /* ngx_null_string, */ /* "418 unused" */ + /* ngx_null_string, */ /* "419 unused" */ + /* ngx_null_string, */ /* "420 unused" */ + /* ngx_null_string, */ /* "421 unused" */ + /* ngx_null_string, */ /* "422 Unprocessable Entity" */ + /* ngx_null_string, */ /* "423 Locked" */ + /* ngx_null_string, */ /* "424 Failed Dependency" */ + +#define NGX_HTTP_LEVEL_400 17 + + ngx_string("500 Internal Server Error"), + ngx_string("501 Method Not Implemented"), + ngx_string("502 Bad Gateway"), + ngx_string("503 Service Temporarily Unavailable"), + ngx_string("504 Gateway Time-out") + + /* ngx_null_string, */ /* "505 HTTP Version Not Supported" */ + /* ngx_null_string, */ /* "506 Variant Also Negotiates" */ + /* ngx_null_string, */ /* "507 Insufficient Storage" */ + /* ngx_null_string, */ /* "508 unused" */ + /* ngx_null_string, */ /* "509 unused" */ + /* ngx_null_string, */ /* "510 Not Extended" */ +}; + + +ngx_http_header_t ngx_http_headers_out[] = { + { ngx_string("Server"), offsetof(ngx_http_headers_out_t, server) }, + { ngx_string("Date"), offsetof(ngx_http_headers_out_t, date) }, + { ngx_string("Content-Type"), + offsetof(ngx_http_headers_out_t, content_type) }, + { ngx_string("Content-Length"), + offsetof(ngx_http_headers_out_t, content_length) }, + { ngx_string("Content-Encoding"), + offsetof(ngx_http_headers_out_t, content_encoding) }, + { ngx_string("Location"), offsetof(ngx_http_headers_out_t, location) }, + { ngx_string("Last-Modified"), + offsetof(ngx_http_headers_out_t, last_modified) }, + { ngx_string("Accept-Ranges"), + offsetof(ngx_http_headers_out_t, accept_ranges) }, + { ngx_string("Expires"), offsetof(ngx_http_headers_out_t, expires) }, + { ngx_string("Cache-Control"), + offsetof(ngx_http_headers_out_t, cache_control) }, + { ngx_string("ETag"), offsetof(ngx_http_headers_out_t, etag) }, + + { ngx_null_string, 0 } +}; + + +static ngx_int_t +ngx_http_header_filter(ngx_http_request_t *r) +{ + u_char *p; + size_t len; + ngx_uint_t status, i; + ngx_buf_t *b; + ngx_chain_t out; + ngx_list_part_t *part; + ngx_table_elt_t *header; + ngx_http_core_loc_conf_t *clcf; + + if (r->http_version < NGX_HTTP_VERSION_10) { + return NGX_OK; + } + + if (r->method == NGX_HTTP_HEAD) { + r->header_only = 1; + } + + if (r->headers_out.last_modified_time != -1) { + if (r->headers_out.status != NGX_HTTP_OK + && r->headers_out.status != NGX_HTTP_NOT_MODIFIED + && r->headers_out.status != NGX_HTTP_PARTIAL_CONTENT) + { + r->headers_out.last_modified_time = -1; + r->headers_out.last_modified = NULL; + } + } + + len = sizeof("HTTP/1.x ") - 1 + sizeof(CRLF) - 1 + /* the end of the header */ + + sizeof(CRLF) - 1; + + /* status line */ + + if (r->headers_out.status_line.len) { + len += r->headers_out.status_line.len; +#if (NGX_SUPPRESS_WARN) + status = NGX_INVALID_ARRAY_INDEX; +#endif + + } else { + + if (r->headers_out.status < NGX_HTTP_MOVED_PERMANENTLY) { + /* 2XX */ + status = r->headers_out.status - NGX_HTTP_OK; + + } else if (r->headers_out.status < NGX_HTTP_BAD_REQUEST) { + /* 3XX */ + status = r->headers_out.status - NGX_HTTP_MOVED_PERMANENTLY + + NGX_HTTP_LEVEL_200; + + if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED) { + r->header_only = 1; + } + + } else if (r->headers_out.status < NGX_HTTP_INTERNAL_SERVER_ERROR) { + /* 4XX */ + status = r->headers_out.status - NGX_HTTP_BAD_REQUEST + + NGX_HTTP_LEVEL_200 + + NGX_HTTP_LEVEL_300; + + } else { + /* 5XX */ + status = r->headers_out.status - NGX_HTTP_INTERNAL_SERVER_ERROR + + NGX_HTTP_LEVEL_200 + + NGX_HTTP_LEVEL_300 + + NGX_HTTP_LEVEL_400; + } + + len += http_codes[status].len; + } + + if (r->headers_out.server && r->headers_out.server->key.len) { + len += r->headers_out.server->key.len + + r->headers_out.server->value.len + 2; + } else { + len += sizeof(server_string) - 1; + } + + if (r->headers_out.date && r->headers_out.date->key.len) { + len += r->headers_out.date->key.len + + r->headers_out.date->value.len + 2; + } else { + len += sizeof("Date: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1; + } + + if (r->headers_out.content_length == NULL) { + if (r->headers_out.content_length_n >= 0) { + len += sizeof("Content-Length: ") - 1 + NGX_OFF_T_LEN + 2; + } + } + + if (r->headers_out.content_type && r->headers_out.content_type->value.len) { + r->headers_out.content_type->key.len = 0; + len += sizeof("Content-Type: ") - 1 + + r->headers_out.content_type->value.len + 2; + + if (r->headers_out.charset.len) { + len += sizeof("; charset=") - 1 + r->headers_out.charset.len; + } + } + + if (r->headers_out.location + && r->headers_out.location->value.len + && r->headers_out.location->value.data[0] == '/') + { + r->headers_out.location->key.len = 0; + len += sizeof("Location: http://") - 1 + + r->server_name.len + r->headers_out.location->value.len + 2; + + if (r->port != 80) { + len += r->port_text->len; + } + } + + if (r->headers_out.last_modified && r->headers_out.last_modified->key.len) { + len += r->headers_out.last_modified->key.len + + r->headers_out.last_modified->value.len + 2; + + } else if (r->headers_out.last_modified_time != -1) { + len += sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1; + } + + if (r->chunked) { + len += sizeof("Transfer-Encoding: chunked" CRLF) - 1; + } + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (r->keepalive) { + len += sizeof("Connection: keep-alive" CRLF) - 1; + + /* + * MSIE and Opera ignore the "Keep-Alive: timeout=" header. + * MSIE keeps the connection alive for about 60-65 seconds. + * Opera keeps the connection alive very long. + * Mozilla keeps the connection alive for N plus about 1-10 seconds. + * Konqueror keeps the connection alive for about N seconds. + */ + + if (clcf->keepalive_header) { + len += sizeof("Keep-Alive: timeout=") - 1 + NGX_TIME_T_LEN + 2; + } + + } else { + len += sizeof("Connection: closed" CRLF) - 1; + } + + part = &r->headers_out.headers.part; + header = part->elts; + + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; + } + + if (header[i].key.len == 0) { + continue; + } + + len += header[i].key.len + sizeof(": ") - 1 + header[i].value.len + + sizeof(CRLF) - 1; + } + + b = ngx_create_temp_buf(r->pool, len); + if (b == NULL) { + return NGX_ERROR; + } + + /* "HTTP/1.x " */ + b->last = ngx_cpymem(b->last, "HTTP/1.1 ", sizeof("HTTP/1.x ") - 1); + + /* status line */ + if (r->headers_out.status_line.len) { + b->last = ngx_cpymem(b->last, r->headers_out.status_line.data, + r->headers_out.status_line.len); + + } else { + b->last = ngx_cpymem(b->last, http_codes[status].data, + http_codes[status].len); + } + *b->last++ = CR; *b->last++ = LF; + + if (!(r->headers_out.server && r->headers_out.server->key.len)) { + b->last = ngx_cpymem(b->last, server_string, sizeof(server_string) - 1); + } + + if (!(r->headers_out.date && r->headers_out.date->key.len)) { + b->last = ngx_cpymem(b->last, "Date: ", sizeof("Date: ") - 1); + b->last = ngx_cpymem(b->last, ngx_cached_http_time.data, + ngx_cached_http_time.len); + + *b->last++ = CR; *b->last++ = LF; + } + + if (r->headers_out.content_length == NULL) { + if (r->headers_out.content_length_n >= 0) { + b->last = ngx_sprintf(b->last, "Content-Length: %O" CRLF, + r->headers_out.content_length_n); + } + } + + if (r->headers_out.content_type && r->headers_out.content_type->value.len) { + b->last = ngx_cpymem(b->last, "Content-Type: ", + sizeof("Content-Type: ") - 1); + p = b->last; + b->last = ngx_cpymem(b->last, r->headers_out.content_type->value.data, + r->headers_out.content_type->value.len); + + if (r->headers_out.charset.len) { + b->last = ngx_cpymem(b->last, "; charset=", + sizeof("; charset=") - 1); + b->last = ngx_cpymem(b->last, r->headers_out.charset.data, + r->headers_out.charset.len); + + r->headers_out.content_type->value.len = b->last - p; + r->headers_out.content_type->value.data = p; + } + + *b->last++ = CR; *b->last++ = LF; + } + + if (r->headers_out.location + && r->headers_out.location->value.len + && r->headers_out.location->value.data[0] == '/') + { + p = b->last + sizeof("Location: ") - 1; + b->last = ngx_cpymem(b->last, "Location: http://", + sizeof("Location: http://") - 1); + b->last = ngx_cpymem(b->last, r->server_name.data, + r->server_name.len); + if (r->port != 80) { + b->last = ngx_cpymem(b->last, r->port_text->data, + r->port_text->len); + } + + b->last = ngx_cpymem(b->last, r->headers_out.location->value.data, + r->headers_out.location->value.len); + + r->headers_out.location->value.len = b->last - p; + r->headers_out.location->value.data = p; + + *b->last++ = CR; *b->last++ = LF; + } + + if (!(r->headers_out.last_modified && r->headers_out.last_modified->key.len) + && r->headers_out.last_modified_time != -1) + { + b->last = ngx_cpymem(b->last, "Last-Modified: ", + sizeof("Last-Modified: ") - 1); + b->last = ngx_http_time(b->last, r->headers_out.last_modified_time); + + *b->last++ = CR; *b->last++ = LF; + } + + if (r->chunked) { + b->last = ngx_cpymem(b->last, "Transfer-Encoding: chunked" CRLF, + sizeof("Transfer-Encoding: chunked" CRLF) - 1); + } + + if (r->keepalive) { + b->last = ngx_cpymem(b->last, "Connection: keep-alive" CRLF, + sizeof("Connection: keep-alive" CRLF) - 1); + + if (clcf->keepalive_header) { + b->last = ngx_sprintf(b->last, "Keep-Alive: timeout=%T" CRLF, + clcf->keepalive_header); + } + + } else { + b->last = ngx_cpymem(b->last, "Connection: close" CRLF, + sizeof("Connection: close" CRLF) - 1); + } + + part = &r->headers_out.headers.part; + header = part->elts; + + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; + } + + if (header[i].key.len == 0) { + continue; + } + + b->last = ngx_cpymem(b->last, header[i].key.data, header[i].key.len); + *b->last++ = ':' ; *b->last++ = ' ' ; + + b->last = ngx_cpymem(b->last, header[i].value.data, + header[i].value.len); + *b->last++ = CR; *b->last++ = LF; + } + +#if (NGX_DEBUG) + *b->last = '\0'; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "%s\n", b->pos); +#endif + + /* the end of HTTP header */ + *b->last++ = CR; *b->last++ = LF; + + r->header_size = b->last - b->pos; + + if (r->header_only) { + b->last_buf = 1; + } + + out.buf = b; + out.next = NULL; + + return ngx_http_write_filter(r, &out); +} + + +static ngx_int_t +ngx_http_header_filter_init(ngx_cycle_t *cycle) +{ + ngx_http_top_header_filter = ngx_http_header_filter; + + return NGX_OK; +} diff --git a/src/http/ngx_http_log_handler.c b/src/http/ngx_http_log_handler.c deleted file mode 100644 --- a/src/http/ngx_http_log_handler.c +++ /dev/null @@ -1,1098 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#include -#include -#include -#include - - -static u_char *ngx_http_log_addr(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op); -static u_char *ngx_http_log_connection(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op); -static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op); -static u_char *ngx_http_log_time(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op); -static u_char *ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op); -static u_char *ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op); -static u_char *ngx_http_log_status(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op); -static u_char *ngx_http_log_length(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op); -static u_char *ngx_http_log_apache_length(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op); -static u_char *ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op); - -static size_t ngx_http_log_request_getlen(ngx_http_request_t *r, - uintptr_t data); -static u_char *ngx_http_log_request(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op); - -static ngx_int_t ngx_http_log_header_in_compile(ngx_http_log_op_t *op, - ngx_str_t *value); -static size_t ngx_http_log_header_in_getlen(ngx_http_request_t *r, - uintptr_t data); -static u_char *ngx_http_log_header_in(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op); -static size_t ngx_http_log_unknown_header_in_getlen(ngx_http_request_t *r, - uintptr_t data); -static u_char *ngx_http_log_unknown_header_in(ngx_http_request_t *r, - u_char *buf, ngx_http_log_op_t *op); - -static ngx_int_t ngx_http_log_header_out_compile(ngx_http_log_op_t *op, - ngx_str_t *value); -static size_t ngx_http_log_header_out_getlen(ngx_http_request_t *r, - uintptr_t data); -static u_char *ngx_http_log_header_out(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op); -static size_t ngx_http_log_unknown_header_out_getlen(ngx_http_request_t *r, - uintptr_t data); -static u_char *ngx_http_log_unknown_header_out(ngx_http_request_t *r, - u_char *buf, ngx_http_log_op_t *op); - -static u_char *ngx_http_log_connection_header_out(ngx_http_request_t *r, - u_char *buf, ngx_http_log_op_t *op); -static u_char *ngx_http_log_transfer_encoding_header_out(ngx_http_request_t *r, - u_char *buf, ngx_http_log_op_t *op); - -static ngx_table_elt_t *ngx_http_log_unknown_header(ngx_list_t *headers, - ngx_str_t *value); - -static ngx_int_t ngx_http_log_set_formats(ngx_conf_t *cf); -static void *ngx_http_log_create_main_conf(ngx_conf_t *cf); -static void *ngx_http_log_create_loc_conf(ngx_conf_t *cf); -static char *ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent, - void *child); -static char *ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); -static char *ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); -static ngx_int_t ngx_http_log_parse_format(ngx_conf_t *cf, ngx_array_t *ops, - ngx_str_t *line); - - -static ngx_command_t ngx_http_log_commands[] = { - - { ngx_string("log_format"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE, - ngx_http_log_set_format, - NGX_HTTP_MAIN_CONF_OFFSET, - 0, - NULL }, - - { ngx_string("access_log"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, - ngx_http_log_set_log, - NGX_HTTP_LOC_CONF_OFFSET, - 0, - NULL }, - - ngx_null_command -}; - - -ngx_http_module_t ngx_http_log_module_ctx = { - ngx_http_log_set_formats, /* pre conf */ - - ngx_http_log_create_main_conf, /* create main configuration */ - NULL, /* init main configuration */ - - NULL, /* create server configuration */ - NULL, /* merge server configuration */ - - ngx_http_log_create_loc_conf, /* create location configration */ - ngx_http_log_merge_loc_conf /* merge location configration */ -}; - - -ngx_module_t ngx_http_log_module = { - NGX_MODULE, - &ngx_http_log_module_ctx, /* module context */ - ngx_http_log_commands, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - NULL, /* init module */ - NULL /* init process */ -}; - - -static ngx_str_t http_access_log = ngx_string(NGX_HTTP_LOG_PATH); - - -static ngx_str_t ngx_http_combined_fmt = - ngx_string("%addr - - [%time] \"%request\" %status %apache_length " - "\"%{Referer}i\" \"%{User-Agent}i\""); - - -ngx_http_log_op_name_t ngx_http_log_fmt_ops[] = { - { ngx_string("addr"), INET_ADDRSTRLEN - 1, NULL, NULL, ngx_http_log_addr }, - { ngx_string("conn"), NGX_ATOMIC_T_LEN, NULL, NULL, - ngx_http_log_connection }, - { ngx_string("pipe"), 1, NULL, NULL, ngx_http_log_pipe }, - { ngx_string("time"), sizeof("28/Sep/1970:12:00:00 +0600") - 1, - NULL, NULL, ngx_http_log_time }, - { ngx_string("msec"), NGX_TIME_T_LEN + 4, NULL, NULL, ngx_http_log_msec }, - { ngx_string("request_time"), NGX_TIME_T_LEN, NULL, NULL, - ngx_http_log_request_time }, - { ngx_string("status"), 3, NULL, NULL, ngx_http_log_status }, - { ngx_string("length"), NGX_OFF_T_LEN, NULL, NULL, ngx_http_log_length }, - { ngx_string("apache_length"), NGX_OFF_T_LEN, - NULL, NULL, ngx_http_log_apache_length }, - { ngx_string("request_length"), NGX_SIZE_T_LEN, - NULL, NULL, ngx_http_log_request_length }, - - { ngx_string("request"), 0, NULL, - ngx_http_log_request_getlen, - ngx_http_log_request }, - - { ngx_string("i"), 0, ngx_http_log_header_in_compile, - ngx_http_log_header_in_getlen, - ngx_http_log_header_in }, - - { ngx_string("o"), 0, ngx_http_log_header_out_compile, - ngx_http_log_header_out_getlen, - ngx_http_log_header_out }, - - { ngx_null_string, 0, NULL, NULL, NULL } -}; - - -ngx_int_t -ngx_http_log_handler(ngx_http_request_t *r) -{ - ngx_uint_t i, l; - u_char *line, *p; - size_t len; - ngx_http_log_t *log; - ngx_http_log_op_t *op; - ngx_http_log_loc_conf_t *lcf; -#if (NGX_WIN32) - u_long written; -#endif - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http log handler"); - - lcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module); - - if (lcf->off) { - return NGX_OK; - } - - log = lcf->logs->elts; - for (l = 0; l < lcf->logs->nelts; l++) { - - len = 0; - op = log[l].ops->elts; - for (i = 0; i < log[l].ops->nelts; i++) { - if (op[i].len == 0) { - len += op[i].getlen(r, op[i].data); - - } else { - len += op[i].len; - } - } - -#if (NGX_WIN32) - len += 2; -#else - len++; -#endif - - if (!(line = ngx_palloc(r->pool, len))) { - return NGX_ERROR; - } - - p = line; - - for (i = 0; i < log[l].ops->nelts; i++) { - p = op[i].run(r, p, &op[i]); - } - -#if (NGX_WIN32) - *p++ = CR; *p++ = LF; - WriteFile(log[l].file->fd, line, p - line, &written, NULL); -#else - *p++ = LF; - write(log[l].file->fd, line, p - line); -#endif - } - - return NGX_OK; -} - - -static u_char * -ngx_http_log_copy_short(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op) -{ - size_t len; - uintptr_t data; - - len = op->len; - data = op->data; - - while (len--) { - *buf++ = (u_char) (data & 0xff); - data >>= 8; - } - - return buf; -} - - -static u_char * -ngx_http_log_copy_long(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op) -{ - return ngx_cpymem(buf, (u_char *) op->data, op->len); -} - - -static u_char * -ngx_http_log_addr(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) -{ - return ngx_cpymem(buf, r->connection->addr_text.data, - r->connection->addr_text.len); -} - - -static u_char * -ngx_http_log_connection(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op) -{ - return ngx_sprintf(buf, "%ui", r->connection->number); -} - - -static u_char * -ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) -{ - if (r->pipeline) { - *buf = 'p'; - } else { - *buf = '.'; - } - - return buf + 1; -} - - -static u_char * -ngx_http_log_time(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) -{ - return ngx_cpymem(buf, ngx_cached_http_log_time.data, - ngx_cached_http_log_time.len); -} - - -static u_char * -ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) -{ - struct timeval tv; - - ngx_gettimeofday(&tv); - - return ngx_sprintf(buf, "%l.%03l", tv.tv_sec, tv.tv_usec / 1000); -} - - -static u_char * -ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op) -{ - time_t elapsed; - - elapsed = ngx_time() - r->start_time; - - return ngx_sprintf(buf, "%T", elapsed); -} - - -static size_t -ngx_http_log_request_getlen(ngx_http_request_t *r, uintptr_t data) -{ - return r->request_line.len; -} - - -static u_char * -ngx_http_log_request(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) -{ - return ngx_cpymem(buf, r->request_line.data, r->request_line.len); -} - - -static u_char * -ngx_http_log_status(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) -{ - return ngx_sprintf(buf, "%ui", - r->err_status ? r->err_status : r->headers_out.status); -} - - -static u_char * -ngx_http_log_length(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) -{ - return ngx_sprintf(buf, "%O", r->connection->sent); -} - - -static u_char * -ngx_http_log_apache_length(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op) -{ - off_t length; - - length = r->connection->sent - r->header_size; - - if (length > 0) { - return ngx_sprintf(buf, "%O", length); - } - - *buf = '0'; - - return buf + 1; -} - - -static u_char * -ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op) -{ - return ngx_sprintf(buf, "%z", r->request_length); -} - - -static ngx_int_t -ngx_http_log_header_in_compile(ngx_http_log_op_t *op, ngx_str_t *value) -{ - ngx_uint_t i; - - op->len = 0; - - for (i = 0; ngx_http_headers_in[i].name.len != 0; i++) { - - if (ngx_http_headers_in[i].name.len != value->len) { - continue; - } - - if (ngx_strncasecmp(ngx_http_headers_in[i].name.data, value->data, - value->len) == 0) - { - op->getlen = ngx_http_log_header_in_getlen; - op->run = ngx_http_log_header_in; - op->data = ngx_http_headers_in[i].offset; - - return NGX_OK; - } - } - - op->getlen = ngx_http_log_unknown_header_in_getlen; - op->run = ngx_http_log_unknown_header_in; - op->data = (uintptr_t) value; - - return NGX_OK; -} - - -static size_t -ngx_http_log_header_in_getlen(ngx_http_request_t *r, uintptr_t data) -{ - ngx_table_elt_t *h; - - h = *(ngx_table_elt_t **) ((char *) &r->headers_in + data); - - if (h) { - return h->value.len; - } - - return 1; -} - - -static u_char * -ngx_http_log_header_in(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op) -{ - ngx_table_elt_t *h; - - h = *(ngx_table_elt_t **) ((char *) &r->headers_in + op->data); - - if (h) { - return ngx_cpymem(buf, h->value.data, h->value.len); - } - - *buf = '-'; - - return buf + 1; -} - - -static size_t -ngx_http_log_unknown_header_in_getlen(ngx_http_request_t *r, uintptr_t data) -{ - ngx_table_elt_t *h; - - h = ngx_http_log_unknown_header(&r->headers_in.headers, (ngx_str_t *) data); - - if (h) { - return h->value.len; - } - - return 1; -} - - -static u_char * -ngx_http_log_unknown_header_in(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op) -{ - ngx_table_elt_t *h; - - h = ngx_http_log_unknown_header(&r->headers_in.headers, - (ngx_str_t *) op->data); - - if (h) { - return ngx_cpymem(buf, h->value.data, h->value.len); - } - - *buf = '-'; - - return buf + 1; -} - - -static ngx_int_t -ngx_http_log_header_out_compile(ngx_http_log_op_t *op, ngx_str_t *value) -{ - ngx_uint_t i; - - op->len = 0; - - for (i = 0; ngx_http_headers_out[i].name.len != 0; i++) { - - if (ngx_http_headers_out[i].name.len != value->len) { - continue; - } - - if (ngx_strncasecmp(ngx_http_headers_out[i].name.data, value->data, - value->len) == 0) - { - op->getlen = ngx_http_log_header_out_getlen; - op->run = ngx_http_log_header_out; - op->data = ngx_http_headers_out[i].offset; - - return NGX_OK; - } - } - - if (value->len == sizeof("Connection") - 1 - && ngx_strncasecmp(value->data, "Connection", value->len) == 0) - { - op->len = sizeof("keep-alive") - 1; - op->getlen = NULL; - op->run = ngx_http_log_connection_header_out; - op->data = 0; - return NGX_OK; - } - - if (value->len == sizeof("Transfer-Encoding") - 1 - && ngx_strncasecmp(value->data, "Transfer-Encoding", value->len) == 0) - { - op->len = sizeof("chunked") - 1; - op->getlen = NULL; - op->run = ngx_http_log_transfer_encoding_header_out; - op->data = 0; - return NGX_OK; - } - - op->getlen = ngx_http_log_unknown_header_out_getlen; - op->run = ngx_http_log_unknown_header_out; - op->data = (uintptr_t) value; - - return NGX_OK; -} - - -static size_t -ngx_http_log_header_out_getlen(ngx_http_request_t *r, uintptr_t data) -{ - ngx_table_elt_t *h; - - h = *(ngx_table_elt_t **) ((char *) &r->headers_out + data); - - if (h) { - return h->value.len; - } - - /* - * No header pointer was found. - * However, some headers: "Date", "Server", "Content-Length", - * and "Last-Modified" have a special handling in the header filter - * but we do not set up their pointers in the filter because - * they are too seldom needed to be logged. - */ - - if (data == offsetof(ngx_http_headers_out_t, date)) { - return ngx_cached_http_time.len; - } - - if (data == offsetof(ngx_http_headers_out_t, server)) { - return (sizeof(NGINX_VER) - 1); - } - - if (data == offsetof(ngx_http_headers_out_t, content_length)) { - if (r->headers_out.content_length_n == -1) { - return 1; - } - - return NGX_OFF_T_LEN; - } - - if (data == offsetof(ngx_http_headers_out_t, last_modified)) { - if (r->headers_out.last_modified_time == -1) { - return 1; - } - - return sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1; - } - - return 1; -} - - -static u_char * -ngx_http_log_header_out(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op) -{ - ngx_table_elt_t *h; - - h = *(ngx_table_elt_t **) ((char *) &r->headers_out + op->data); - - if (h) { - return ngx_cpymem(buf, h->value.data, h->value.len); - } - - /* - * No header pointer was found. - * However, some headers: "Date", "Server", "Content-Length", - * and "Last-Modified" have a special handling in the header filter - * but we do not set up their pointers in the filter because - * they are too seldom needed to be logged. - */ - - if (op->data == offsetof(ngx_http_headers_out_t, date)) { - return ngx_cpymem(buf, ngx_cached_http_time.data, - ngx_cached_http_time.len); - } - - if (op->data == offsetof(ngx_http_headers_out_t, server)) { - return ngx_cpymem(buf, NGINX_VER, sizeof(NGINX_VER) - 1); - } - - if (op->data == offsetof(ngx_http_headers_out_t, content_length)) { - if (r->headers_out.content_length_n == -1) { - *buf = '-'; - - return buf + 1; - } - - return ngx_sprintf(buf, "%O", r->headers_out.content_length_n); - } - - if (op->data == offsetof(ngx_http_headers_out_t, last_modified)) { - if (r->headers_out.last_modified_time == -1) { - *buf = '-'; - - return buf + 1; - } - - return ngx_http_time(buf, r->headers_out.last_modified_time); - } - - *buf = '-'; - - return buf + 1; -} - - -static size_t -ngx_http_log_unknown_header_out_getlen(ngx_http_request_t *r, uintptr_t data) -{ - ngx_table_elt_t *h; - - h = ngx_http_log_unknown_header(&r->headers_out.headers, - (ngx_str_t *) data); - - if (h) { - return h->value.len; - } - - return 1; -} - - -static u_char * -ngx_http_log_unknown_header_out(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op) -{ - ngx_table_elt_t *h; - - h = ngx_http_log_unknown_header(&r->headers_out.headers, - (ngx_str_t *) op->data); - - if (h) { - return ngx_cpymem(buf, h->value.data, h->value.len); - } - - *buf = '-'; - - return buf + 1; -} - - -static ngx_table_elt_t * -ngx_http_log_unknown_header(ngx_list_t *headers, ngx_str_t *value) -{ - ngx_uint_t i; - ngx_list_part_t *part; - ngx_table_elt_t *h; - - part = &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 (h[i].key.len != value->len) { - continue; - } - - if (ngx_strncasecmp(h[i].key.data, value->data, value->len) == 0) { - return &h[i]; - } - } - - return NULL; -} - - -static u_char * -ngx_http_log_connection_header_out(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op) -{ - if (r->keepalive) { - return ngx_cpymem(buf, "keep-alive", sizeof("keep-alive") - 1); - - } else { - return ngx_cpymem(buf, "close", sizeof("close") - 1); - } -} - - -static u_char * -ngx_http_log_transfer_encoding_header_out(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op) -{ - if (r->chunked) { - return ngx_cpymem(buf, "chunked", sizeof("chunked") - 1); - } - - *buf = '-'; - - return buf + 1; -} - - -static ngx_int_t -ngx_http_log_set_formats(ngx_conf_t *cf) -{ - ngx_http_log_op_name_t *op; - - for (op = ngx_http_log_fmt_ops; op->name.len; op++) { /* void */ } - op->run = NULL; - - return NGX_OK; -} - - -static void * -ngx_http_log_create_main_conf(ngx_conf_t *cf) -{ - ngx_http_log_main_conf_t *conf; - - char *rc; - ngx_str_t *value; - - if (!(conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_main_conf_t)))) { - return NGX_CONF_ERROR; - } - - if (ngx_array_init(&conf->formats, cf->pool, 4, sizeof(ngx_http_log_fmt_t)) - == NGX_ERROR) - { - return NGX_CONF_ERROR; - } - - cf->args->nelts = 0; - - if (!(value = ngx_array_push(cf->args))) { - return NGX_CONF_ERROR; - } - - if (!(value = ngx_array_push(cf->args))) { - return NGX_CONF_ERROR; - } - - value->len = sizeof("combined") - 1; - value->data = (u_char *) "combined"; - - if (!(value = ngx_array_push(cf->args))) { - return NGX_CONF_ERROR; - } - - *value = ngx_http_combined_fmt; - - rc = ngx_http_log_set_format(cf, NULL, conf); - if (rc != NGX_CONF_OK) { - return NULL; - } - - return conf; -} - - -static void * -ngx_http_log_create_loc_conf(ngx_conf_t *cf) -{ - ngx_http_log_loc_conf_t *conf; - - if (!(conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_loc_conf_t)))) { - return NGX_CONF_ERROR; - } - - return conf; -} - - -static char * -ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) -{ - ngx_http_log_loc_conf_t *prev = parent; - ngx_http_log_loc_conf_t *conf = child; - - ngx_http_log_t *log; - ngx_http_log_fmt_t *fmt; - ngx_http_log_main_conf_t *lmcf; - - if (conf->logs == NULL) { - - if (conf->off) { - return NGX_CONF_OK; - } - - if (prev->logs) { - conf->logs = prev->logs; - - } else { - - if (prev->off) { - conf->off = prev->off; - return NGX_CONF_OK; - } - - conf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t)); - if (conf->logs == NULL) { - return NGX_CONF_ERROR; - } - - if (!(log = ngx_array_push(conf->logs))) { - return NGX_CONF_ERROR; - } - - log->file = ngx_conf_open_file(cf->cycle, &http_access_log); - if (log->file == NULL) { - return NGX_CONF_ERROR; - } - - lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module); - fmt = lmcf->formats.elts; - - /* the default "combined" format */ - log->ops = fmt[0].ops; - } - } - - return NGX_CONF_OK; -} - - -static char * -ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_http_log_loc_conf_t *llcf = conf; - - ngx_uint_t i; - ngx_str_t *value, name; - ngx_http_log_t *log; - ngx_http_log_fmt_t *fmt; - ngx_http_log_main_conf_t *lmcf; - - value = cf->args->elts; - - if (ngx_strcmp(value[1].data, "off") == 0) { - llcf->off = 1; - return NGX_CONF_OK; - } - - if (llcf->logs == NULL) { - llcf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t)); - if (llcf->logs == NULL) { - return NGX_CONF_ERROR; - } - } - - lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module); - - if (!(log = ngx_array_push(llcf->logs))) { - return NGX_CONF_ERROR; - } - - if (!(log->file = ngx_conf_open_file(cf->cycle, &value[1]))) { - return NGX_CONF_ERROR; - } - - if (cf->args->nelts == 3) { - name = value[2]; - } else { - name.len = sizeof("combined") - 1; - name.data = (u_char *) "combined"; - } - - fmt = lmcf->formats.elts; - for (i = 0; i < lmcf->formats.nelts; i++) { - if (fmt[i].name.len == name.len - && ngx_strcasecmp(fmt[i].name.data, name.data) == 0) - { - log->ops = fmt[i].ops; - return NGX_CONF_OK; - } - } - - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "unknown log format \"%V\"", &name); - - return NGX_CONF_ERROR; -} - - -static char * -ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_http_log_main_conf_t *lmcf = conf; - - ngx_uint_t s, f, invalid; - u_char *data, *p, *fname; - size_t i, len, fname_len; - ngx_str_t *value, arg, *a; - ngx_http_log_op_t *op; - ngx_http_log_fmt_t *fmt; - ngx_http_log_op_name_t *name; - - value = cf->args->elts; - - fmt = lmcf->formats.elts; - for (f = 0; f < lmcf->formats.nelts; f++) { - if (fmt[f].name.len == value[1].len - && ngx_strcmp(fmt->name.data, value[1].data) == 0) - { - return "duplicate \"log_format\" name"; - } - } - - if (!(fmt = ngx_push_array(&lmcf->formats))) { - return NGX_CONF_ERROR; - } - - fmt->name = value[1]; - - if (!(fmt->ops = ngx_array_create(cf->pool, 20, sizeof(ngx_http_log_op_t)))) - { - return NGX_CONF_ERROR; - } - - invalid = 0; - data = NULL; - - for (s = 2; s < cf->args->nelts && !invalid; s++) { - - i = 0; - - while (i < value[s].len) { - - if (!(op = ngx_push_array(fmt->ops))) { - return NGX_CONF_ERROR; - } - - data = &value[s].data[i]; - - if (value[s].data[i] == '%') { - i++; - - if (i == value[s].len) { - invalid = 1; - break; - } - - if (value[s].data[i] == '{') { - i++; - - arg.data = &value[s].data[i]; - - while (i < value[s].len && value[s].data[i] != '}') { - i++; - } - - arg.len = &value[s].data[i] - arg.data; - - if (i == value[s].len || arg.len == 0) { - invalid = 1; - break; - } - - i++; - - } else { - arg.len = 0; - } - - fname = &value[s].data[i]; - - while (i < value[s].len - && ((value[s].data[i] >= 'a' && value[s].data[i] <= 'z') - || value[s].data[i] == '_')) - { - i++; - } - - fname_len = &value[s].data[i] - fname; - - if (fname_len == 0) { - invalid = 1; - break; - } - - for (name = ngx_http_log_fmt_ops; name->run; name++) { - if (name->name.len == 0) { - name = (ngx_http_log_op_name_t *) name->run; - } - - if (name->name.len == fname_len - && ngx_strncmp(name->name.data, fname, fname_len) == 0) - { - if (name->compile == NULL) { - if (arg.len) { - fname[fname_len] = '\0'; - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"%s\" must not have argument", - data); - return NGX_CONF_ERROR; - } - - op->len = name->len; - op->getlen = name->getlen; - op->run = name->run; - op->data = 0; - - break; - } - - if (arg.len == 0) { - fname[fname_len] = '\0'; - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"%s\" requires argument", - data); - return NGX_CONF_ERROR; - } - - if (!(a = ngx_palloc(cf->pool, sizeof(ngx_str_t)))) { - return NGX_CONF_ERROR; - } - - *a = arg; - if (name->compile(op, a) == NGX_ERROR) { - return NGX_CONF_ERROR; - } - - break; - } - } - - if (name->name.len == 0) { - invalid = 1; - break; - } - - } else { - i++; - - while (i < value[s].len && value[s].data[i] != '%') { - i++; - } - - len = &value[s].data[i] - data; - - if (len) { - - op->len = len; - op->getlen = NULL; - - if (len <= sizeof(uintptr_t)) { - op->run = ngx_http_log_copy_short; - op->data = 0; - - while (len--) { - op->data <<= 8; - op->data |= data[len]; - } - - } else { - op->run = ngx_http_log_copy_long; - - if (!(p = ngx_palloc(cf->pool, len))) { - return NGX_CONF_ERROR; - } - - ngx_memcpy(p, data, len); - op->data = (uintptr_t) p; - } - } - } - } - } - - if (invalid) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid parameter \"%s\"", data); - return NGX_CONF_ERROR; - } - - return NGX_CONF_OK; -} diff --git a/src/http/ngx_http_log_handler.h b/src/http/ngx_http_log_handler.h deleted file mode 100644 --- a/src/http/ngx_http_log_handler.h +++ /dev/null @@ -1,70 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#ifndef _NGX_HTTP_LOG_HANDLER_H_INCLUDED_ -#define _NGX_HTTP_LOG_HANDLER_H_INCLUDED_ - - -#include -#include -#include - - -typedef struct ngx_http_log_op_s ngx_http_log_op_t; - -typedef u_char *(*ngx_http_log_op_run_pt) (ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op); - -typedef size_t (*ngx_http_log_op_getlen_pt) (ngx_http_request_t *r, - uintptr_t data); - -typedef ngx_int_t (*ngx_http_log_op_compile_pt) (ngx_http_log_op_t *op, - ngx_str_t *value); - -struct ngx_http_log_op_s { - size_t len; - ngx_http_log_op_getlen_pt getlen; - ngx_http_log_op_run_pt run; - uintptr_t data; -}; - - -typedef struct { - ngx_str_t name; - ngx_array_t *ops; /* array of ngx_http_log_op_t */ -} ngx_http_log_fmt_t; - - -typedef struct { - ngx_str_t name; - size_t len; - ngx_http_log_op_compile_pt compile; - ngx_http_log_op_getlen_pt getlen; - ngx_http_log_op_run_pt run; -} ngx_http_log_op_name_t; - - -typedef struct { - ngx_array_t formats; /* array of ngx_http_log_fmt_t */ -} ngx_http_log_main_conf_t; - - -typedef struct { - ngx_open_file_t *file; - ngx_array_t *ops; /* array of ngx_http_log_op_t */ -} ngx_http_log_t; - - -typedef struct { - ngx_array_t *logs; /* array of ngx_http_log_t */ - ngx_uint_t off; /* unsigned off:1 */ -} ngx_http_log_loc_conf_t; - - -extern ngx_http_log_op_name_t ngx_http_log_fmt_ops[]; - - -#endif /* _NGX_HTTP_LOG_HANDLER_H_INCLUDED_ */ diff --git a/src/http/ngx_http_log_module.c b/src/http/ngx_http_log_module.c new file mode 100644 --- /dev/null +++ b/src/http/ngx_http_log_module.c @@ -0,0 +1,1181 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include +#include + + +static u_char *ngx_http_log_addr(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op); +static u_char *ngx_http_log_connection(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op); +static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op); +static u_char *ngx_http_log_time(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op); +static u_char *ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op); +static u_char *ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op); +static u_char *ngx_http_log_status(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op); +static u_char *ngx_http_log_length(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op); +static u_char *ngx_http_log_apache_length(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op); +static u_char *ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op); + +static size_t ngx_http_log_request_getlen(ngx_http_request_t *r, + uintptr_t data); +static u_char *ngx_http_log_request(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op); + +static ngx_int_t ngx_http_log_header_in_compile(ngx_conf_t *cf, + ngx_http_log_op_t *op, ngx_str_t *value); +static size_t ngx_http_log_header_in_getlen(ngx_http_request_t *r, + uintptr_t data); +static u_char *ngx_http_log_header_in(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op); +static size_t ngx_http_log_unknown_header_in_getlen(ngx_http_request_t *r, + uintptr_t data); +static u_char *ngx_http_log_unknown_header_in(ngx_http_request_t *r, + u_char *buf, ngx_http_log_op_t *op); + +static ngx_int_t ngx_http_log_header_out_compile(ngx_conf_t *cf, + ngx_http_log_op_t *op, ngx_str_t *value); +static size_t ngx_http_log_header_out_getlen(ngx_http_request_t *r, + uintptr_t data); +static u_char *ngx_http_log_header_out(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op); +static size_t ngx_http_log_unknown_header_out_getlen(ngx_http_request_t *r, + uintptr_t data); +static u_char *ngx_http_log_unknown_header_out(ngx_http_request_t *r, + u_char *buf, ngx_http_log_op_t *op); + +static u_char *ngx_http_log_connection_header_out(ngx_http_request_t *r, + u_char *buf, ngx_http_log_op_t *op); +static u_char *ngx_http_log_transfer_encoding_header_out(ngx_http_request_t *r, + u_char *buf, ngx_http_log_op_t *op); + +static ngx_table_elt_t *ngx_http_log_unknown_header(ngx_list_t *headers, + ngx_str_t *value); + +static ngx_int_t ngx_http_log_variable_compile(ngx_conf_t *cf, + ngx_http_log_op_t *op, ngx_str_t *value); +static size_t ngx_http_log_variable_getlen(ngx_http_request_t *r, + uintptr_t data); +static u_char *ngx_http_log_variable(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op); + + +static ngx_int_t ngx_http_log_set_formats(ngx_conf_t *cf); +static void *ngx_http_log_create_main_conf(ngx_conf_t *cf); +static void *ngx_http_log_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent, + void *child); +static char *ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + + +static ngx_command_t ngx_http_log_commands[] = { + + { ngx_string("log_format"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE, + ngx_http_log_set_format, + NGX_HTTP_MAIN_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("access_log"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, + ngx_http_log_set_log, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +ngx_http_module_t ngx_http_log_module_ctx = { + ngx_http_log_set_formats, /* pre conf */ + + ngx_http_log_create_main_conf, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_log_create_loc_conf, /* create location configration */ + ngx_http_log_merge_loc_conf /* merge location configration */ +}; + + +ngx_module_t ngx_http_log_module = { + NGX_MODULE, + &ngx_http_log_module_ctx, /* module context */ + ngx_http_log_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init module */ + NULL /* init process */ +}; + + +static ngx_str_t http_access_log = ngx_string(NGX_HTTP_LOG_PATH); + + +static ngx_str_t ngx_http_combined_fmt = + ngx_string("%addr - - [%time] \"%request\" %status %apache_length " + "\"%{Referer}i\" \"%{User-Agent}i\""); + + +ngx_http_log_op_name_t ngx_http_log_fmt_ops[] = { + { ngx_string("addr"), INET_ADDRSTRLEN - 1, NULL, NULL, ngx_http_log_addr }, + { ngx_string("conn"), NGX_ATOMIC_T_LEN, NULL, NULL, + ngx_http_log_connection }, + { ngx_string("pipe"), 1, NULL, NULL, ngx_http_log_pipe }, + { ngx_string("time"), sizeof("28/Sep/1970:12:00:00 +0600") - 1, + NULL, NULL, ngx_http_log_time }, + { ngx_string("msec"), NGX_TIME_T_LEN + 4, NULL, NULL, ngx_http_log_msec }, + { ngx_string("request_time"), NGX_TIME_T_LEN, NULL, NULL, + ngx_http_log_request_time }, + { ngx_string("status"), 3, NULL, NULL, ngx_http_log_status }, + { ngx_string("length"), NGX_OFF_T_LEN, NULL, NULL, ngx_http_log_length }, + { ngx_string("apache_length"), NGX_OFF_T_LEN, + NULL, NULL, ngx_http_log_apache_length }, + { ngx_string("request_length"), NGX_SIZE_T_LEN, + NULL, NULL, ngx_http_log_request_length }, + + { ngx_string("request"), 0, NULL, + ngx_http_log_request_getlen, + ngx_http_log_request }, + + { ngx_string("i"), 0, ngx_http_log_header_in_compile, NULL, + ngx_http_log_header_in }, + { ngx_string("o"), 0, ngx_http_log_header_out_compile, NULL, + ngx_http_log_header_out }, + { ngx_string("v"), 0, ngx_http_log_variable_compile, NULL, + ngx_http_log_variable }, + + { ngx_null_string, 0, NULL, NULL, NULL } +}; + + +ngx_int_t +ngx_http_log_handler(ngx_http_request_t *r) +{ + ngx_uint_t i, l; + u_char *line, *p; + size_t len; + ngx_http_log_t *log; + ngx_http_log_op_t *op; + ngx_http_log_loc_conf_t *lcf; +#if (NGX_WIN32) + u_long written; +#endif + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http log handler"); + + lcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module); + + if (lcf->off) { + return NGX_OK; + } + + log = lcf->logs->elts; + for (l = 0; l < lcf->logs->nelts; l++) { + + len = 0; + op = log[l].ops->elts; + for (i = 0; i < log[l].ops->nelts; i++) { + if (op[i].len == 0) { + len += op[i].getlen(r, op[i].data); + + } else { + len += op[i].len; + } + } + +#if (NGX_WIN32) + len += 2; +#else + len++; +#endif + + line = ngx_palloc(r->pool, len); + if (line == NULL) { + return NGX_ERROR; + } + + p = line; + + for (i = 0; i < log[l].ops->nelts; i++) { + p = op[i].run(r, p, &op[i]); + } + +#if (NGX_WIN32) + *p++ = CR; *p++ = LF; + WriteFile(log[l].file->fd, line, p - line, &written, NULL); +#else + *p++ = LF; + write(log[l].file->fd, line, p - line); +#endif + } + + return NGX_OK; +} + + +static u_char * +ngx_http_log_copy_short(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op) +{ + size_t len; + uintptr_t data; + + len = op->len; + data = op->data; + + while (len--) { + *buf++ = (u_char) (data & 0xff); + data >>= 8; + } + + return buf; +} + + +static u_char * +ngx_http_log_copy_long(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op) +{ + return ngx_cpymem(buf, (u_char *) op->data, op->len); +} + + +static u_char * +ngx_http_log_addr(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) +{ + return ngx_cpymem(buf, r->connection->addr_text.data, + r->connection->addr_text.len); +} + + +static u_char * +ngx_http_log_connection(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op) +{ + return ngx_sprintf(buf, "%ui", r->connection->number); +} + + +static u_char * +ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) +{ + if (r->pipeline) { + *buf = 'p'; + } else { + *buf = '.'; + } + + return buf + 1; +} + + +static u_char * +ngx_http_log_time(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) +{ + return ngx_cpymem(buf, ngx_cached_http_log_time.data, + ngx_cached_http_log_time.len); +} + + +static u_char * +ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) +{ + struct timeval tv; + + ngx_gettimeofday(&tv); + + return ngx_sprintf(buf, "%l.%03l", tv.tv_sec, tv.tv_usec / 1000); +} + + +static u_char * +ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op) +{ + time_t elapsed; + + elapsed = ngx_time() - r->start_time; + + return ngx_sprintf(buf, "%T", elapsed); +} + + +static size_t +ngx_http_log_request_getlen(ngx_http_request_t *r, uintptr_t data) +{ + return r->request_line.len; +} + + +static u_char * +ngx_http_log_request(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) +{ + return ngx_cpymem(buf, r->request_line.data, r->request_line.len); +} + + +static u_char * +ngx_http_log_status(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) +{ + return ngx_sprintf(buf, "%ui", + r->err_status ? r->err_status : r->headers_out.status); +} + + +static u_char * +ngx_http_log_length(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) +{ + return ngx_sprintf(buf, "%O", r->connection->sent); +} + + +static u_char * +ngx_http_log_apache_length(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op) +{ + off_t length; + + length = r->connection->sent - r->header_size; + + if (length > 0) { + return ngx_sprintf(buf, "%O", length); + } + + *buf = '0'; + + return buf + 1; +} + + +static u_char * +ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op) +{ + return ngx_sprintf(buf, "%z", r->request_length); +} + + +static ngx_int_t +ngx_http_log_header_in_compile(ngx_conf_t *cf, ngx_http_log_op_t *op, + ngx_str_t *value) +{ + ngx_uint_t i; + + op->len = 0; + + for (i = 0; ngx_http_headers_in[i].name.len != 0; i++) { + + if (ngx_http_headers_in[i].name.len != value->len) { + continue; + } + + if (ngx_strncasecmp(ngx_http_headers_in[i].name.data, value->data, + value->len) == 0) + { + op->getlen = ngx_http_log_header_in_getlen; + op->run = ngx_http_log_header_in; + op->data = ngx_http_headers_in[i].offset; + + return NGX_OK; + } + } + + op->getlen = ngx_http_log_unknown_header_in_getlen; + op->run = ngx_http_log_unknown_header_in; + op->data = (uintptr_t) value; + + return NGX_OK; +} + + +static size_t +ngx_http_log_header_in_getlen(ngx_http_request_t *r, uintptr_t data) +{ + ngx_table_elt_t *h; + + h = *(ngx_table_elt_t **) ((char *) &r->headers_in + data); + + if (h) { + return h->value.len; + } + + return 1; +} + + +static u_char * +ngx_http_log_header_in(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op) +{ + ngx_table_elt_t *h; + + h = *(ngx_table_elt_t **) ((char *) &r->headers_in + op->data); + + if (h) { + return ngx_cpymem(buf, h->value.data, h->value.len); + } + + *buf = '-'; + + return buf + 1; +} + + +static size_t +ngx_http_log_unknown_header_in_getlen(ngx_http_request_t *r, uintptr_t data) +{ + ngx_table_elt_t *h; + + h = ngx_http_log_unknown_header(&r->headers_in.headers, (ngx_str_t *) data); + + if (h) { + return h->value.len; + } + + return 1; +} + + +static u_char * +ngx_http_log_unknown_header_in(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op) +{ + ngx_table_elt_t *h; + + h = ngx_http_log_unknown_header(&r->headers_in.headers, + (ngx_str_t *) op->data); + + if (h) { + return ngx_cpymem(buf, h->value.data, h->value.len); + } + + *buf = '-'; + + return buf + 1; +} + + +static ngx_int_t +ngx_http_log_header_out_compile(ngx_conf_t *cf, ngx_http_log_op_t *op, + ngx_str_t *value) +{ + ngx_uint_t i; + + op->len = 0; + + for (i = 0; ngx_http_headers_out[i].name.len != 0; i++) { + + if (ngx_http_headers_out[i].name.len != value->len) { + continue; + } + + if (ngx_strncasecmp(ngx_http_headers_out[i].name.data, value->data, + value->len) == 0) + { + op->getlen = ngx_http_log_header_out_getlen; + op->run = ngx_http_log_header_out; + op->data = ngx_http_headers_out[i].offset; + + return NGX_OK; + } + } + + if (value->len == sizeof("Connection") - 1 + && ngx_strncasecmp(value->data, "Connection", value->len) == 0) + { + op->len = sizeof("keep-alive") - 1; + op->getlen = NULL; + op->run = ngx_http_log_connection_header_out; + op->data = 0; + return NGX_OK; + } + + if (value->len == sizeof("Transfer-Encoding") - 1 + && ngx_strncasecmp(value->data, "Transfer-Encoding", value->len) == 0) + { + op->len = sizeof("chunked") - 1; + op->getlen = NULL; + op->run = ngx_http_log_transfer_encoding_header_out; + op->data = 0; + return NGX_OK; + } + + op->getlen = ngx_http_log_unknown_header_out_getlen; + op->run = ngx_http_log_unknown_header_out; + op->data = (uintptr_t) value; + + return NGX_OK; +} + + +static size_t +ngx_http_log_header_out_getlen(ngx_http_request_t *r, uintptr_t data) +{ + ngx_table_elt_t *h; + + h = *(ngx_table_elt_t **) ((char *) &r->headers_out + data); + + if (h) { + return h->value.len; + } + + /* + * No header pointer was found. + * However, some headers: "Date", "Server", "Content-Length", + * and "Last-Modified" have a special handling in the header filter + * but we do not set up their pointers in the filter because + * they are too seldom needed to be logged. + */ + + if (data == offsetof(ngx_http_headers_out_t, date)) { + return ngx_cached_http_time.len; + } + + if (data == offsetof(ngx_http_headers_out_t, server)) { + return (sizeof(NGINX_VER) - 1); + } + + if (data == offsetof(ngx_http_headers_out_t, content_length)) { + if (r->headers_out.content_length_n == -1) { + return 1; + } + + return NGX_OFF_T_LEN; + } + + if (data == offsetof(ngx_http_headers_out_t, last_modified)) { + if (r->headers_out.last_modified_time == -1) { + return 1; + } + + return sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1; + } + + return 1; +} + + +static u_char * +ngx_http_log_header_out(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op) +{ + ngx_table_elt_t *h; + + h = *(ngx_table_elt_t **) ((char *) &r->headers_out + op->data); + + if (h) { + return ngx_cpymem(buf, h->value.data, h->value.len); + } + + /* + * No header pointer was found. + * However, some headers: "Date", "Server", "Content-Length", + * and "Last-Modified" have a special handling in the header filter + * but we do not set up their pointers in the filter because + * they are too seldom needed to be logged. + */ + + if (op->data == offsetof(ngx_http_headers_out_t, date)) { + return ngx_cpymem(buf, ngx_cached_http_time.data, + ngx_cached_http_time.len); + } + + if (op->data == offsetof(ngx_http_headers_out_t, server)) { + return ngx_cpymem(buf, NGINX_VER, sizeof(NGINX_VER) - 1); + } + + if (op->data == offsetof(ngx_http_headers_out_t, content_length)) { + if (r->headers_out.content_length_n == -1) { + *buf = '-'; + + return buf + 1; + } + + return ngx_sprintf(buf, "%O", r->headers_out.content_length_n); + } + + if (op->data == offsetof(ngx_http_headers_out_t, last_modified)) { + if (r->headers_out.last_modified_time == -1) { + *buf = '-'; + + return buf + 1; + } + + return ngx_http_time(buf, r->headers_out.last_modified_time); + } + + *buf = '-'; + + return buf + 1; +} + + +static size_t +ngx_http_log_unknown_header_out_getlen(ngx_http_request_t *r, uintptr_t data) +{ + ngx_table_elt_t *h; + + h = ngx_http_log_unknown_header(&r->headers_out.headers, + (ngx_str_t *) data); + + if (h) { + return h->value.len; + } + + return 1; +} + + +static u_char * +ngx_http_log_unknown_header_out(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op) +{ + ngx_table_elt_t *h; + + h = ngx_http_log_unknown_header(&r->headers_out.headers, + (ngx_str_t *) op->data); + + if (h) { + return ngx_cpymem(buf, h->value.data, h->value.len); + } + + *buf = '-'; + + return buf + 1; +} + + +static ngx_table_elt_t * +ngx_http_log_unknown_header(ngx_list_t *headers, ngx_str_t *value) +{ + ngx_uint_t i; + ngx_list_part_t *part; + ngx_table_elt_t *h; + + part = &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 (h[i].key.len != value->len) { + continue; + } + + if (ngx_strncasecmp(h[i].key.data, value->data, value->len) == 0) { + return &h[i]; + } + } + + return NULL; +} + + +static u_char * +ngx_http_log_connection_header_out(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op) +{ + if (r->keepalive) { + return ngx_cpymem(buf, "keep-alive", sizeof("keep-alive") - 1); + + } else { + return ngx_cpymem(buf, "close", sizeof("close") - 1); + } +} + + +static u_char * +ngx_http_log_transfer_encoding_header_out(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op) +{ + if (r->chunked) { + return ngx_cpymem(buf, "chunked", sizeof("chunked") - 1); + } + + *buf = '-'; + + return buf + 1; +} + + +static ngx_int_t +ngx_http_log_variable_compile(ngx_conf_t *cf, ngx_http_log_op_t *op, + ngx_str_t *value) +{ + ngx_uint_t i; + ngx_http_variable_t *var; + + for (i = 0; i < value->len; i++) { + value->data[i] = ngx_toupper(value->data[i]); + } + + var = ngx_http_add_variable(cf, value, 0); + if (var == NULL) { + return NGX_ERROR; + } + + op->len = 0; + op->getlen = ngx_http_log_variable_getlen; + op->run = ngx_http_log_variable; + op->data = var->index; + + return NGX_OK; +} + + +static size_t +ngx_http_log_variable_getlen(ngx_http_request_t *r, uintptr_t data) +{ + ngx_http_variable_value_t *value; + + value = ngx_http_get_indexed_variable(r, data); + + if (value == NULL + || value == NGX_HTTP_VARIABLE_NOT_FOUND + || value->text.len == 0) + { + return 1; + } + + return value->text.len; +} + + +static u_char * +ngx_http_log_variable(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) +{ + ngx_http_variable_value_t *value; + + value = ngx_http_get_indexed_variable(r, op->data); + + if (value == NULL + || value == NGX_HTTP_VARIABLE_NOT_FOUND + || value->text.len == 0) + { + *buf = '-'; + return buf + 1; + } + + return ngx_cpymem(buf, value->text.data, value->text.len); +} + + +static ngx_int_t +ngx_http_log_set_formats(ngx_conf_t *cf) +{ + ngx_http_log_op_name_t *op; + + for (op = ngx_http_log_fmt_ops; op->name.len; op++) { /* void */ } + op->run = NULL; + + return NGX_OK; +} + + +static void * +ngx_http_log_create_main_conf(ngx_conf_t *cf) +{ + ngx_http_log_main_conf_t *conf; + + char *rc; + ngx_str_t *value; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_main_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + if (ngx_array_init(&conf->formats, cf->pool, 4, sizeof(ngx_http_log_fmt_t)) + == NGX_ERROR) + { + return NGX_CONF_ERROR; + } + + cf->args->nelts = 0; + + value = ngx_array_push(cf->args); + if (value == NULL) { + return NGX_CONF_ERROR; + } + + value = ngx_array_push(cf->args); + if (value == NULL) { + return NGX_CONF_ERROR; + } + + value->len = sizeof("combined") - 1; + value->data = (u_char *) "combined"; + + value = ngx_array_push(cf->args); + if (value == NULL) { + return NGX_CONF_ERROR; + } + + *value = ngx_http_combined_fmt; + + rc = ngx_http_log_set_format(cf, NULL, conf); + if (rc != NGX_CONF_OK) { + return NULL; + } + + return conf; +} + + +static void * +ngx_http_log_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_log_loc_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_loc_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + return conf; +} + + +static char * +ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_log_loc_conf_t *prev = parent; + ngx_http_log_loc_conf_t *conf = child; + + ngx_http_log_t *log; + ngx_http_log_fmt_t *fmt; + ngx_http_log_main_conf_t *lmcf; + + if (conf->logs == NULL) { + + if (conf->off) { + return NGX_CONF_OK; + } + + if (prev->logs) { + conf->logs = prev->logs; + + } else { + + if (prev->off) { + conf->off = prev->off; + return NGX_CONF_OK; + } + + conf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t)); + if (conf->logs == NULL) { + return NGX_CONF_ERROR; + } + + log = ngx_array_push(conf->logs); + if (log == NULL) { + return NGX_CONF_ERROR; + } + + log->file = ngx_conf_open_file(cf->cycle, &http_access_log); + if (log->file == NULL) { + return NGX_CONF_ERROR; + } + + lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module); + fmt = lmcf->formats.elts; + + /* the default "combined" format */ + log->ops = fmt[0].ops; + } + } + + return NGX_CONF_OK; +} + + +static char * +ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_log_loc_conf_t *llcf = conf; + + ngx_uint_t i; + ngx_str_t *value, name; + ngx_http_log_t *log; + ngx_http_log_fmt_t *fmt; + ngx_http_log_main_conf_t *lmcf; + + value = cf->args->elts; + + if (ngx_strcmp(value[1].data, "off") == 0) { + llcf->off = 1; + return NGX_CONF_OK; + } + + if (llcf->logs == NULL) { + llcf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t)); + if (llcf->logs == NULL) { + return NGX_CONF_ERROR; + } + } + + lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module); + + log = ngx_array_push(llcf->logs); + if (log == NULL) { + return NGX_CONF_ERROR; + } + + log->file = ngx_conf_open_file(cf->cycle, &value[1]); + if (log->file == NULL) { + return NGX_CONF_ERROR; + } + + if (cf->args->nelts == 3) { + name = value[2]; + } else { + name.len = sizeof("combined") - 1; + name.data = (u_char *) "combined"; + } + + fmt = lmcf->formats.elts; + for (i = 0; i < lmcf->formats.nelts; i++) { + if (fmt[i].name.len == name.len + && ngx_strcasecmp(fmt[i].name.data, name.data) == 0) + { + log->ops = fmt[i].ops; + return NGX_CONF_OK; + } + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "unknown log format \"%V\"", &name); + + return NGX_CONF_ERROR; +} + + +static char * +ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_log_main_conf_t *lmcf = conf; + + ngx_uint_t s, f, invalid; + u_char *data, *p, *fname; + size_t i, len, fname_len; + ngx_str_t *value, arg, *a; + ngx_http_log_op_t *op; + ngx_http_log_fmt_t *fmt; + ngx_http_log_op_name_t *name; + + value = cf->args->elts; + + fmt = lmcf->formats.elts; + for (f = 0; f < lmcf->formats.nelts; f++) { + if (fmt[f].name.len == value[1].len + && ngx_strcmp(fmt->name.data, value[1].data) == 0) + { + return "duplicate \"log_format\" name"; + } + } + + fmt = ngx_array_push(&lmcf->formats); + if (fmt == NULL) { + return NGX_CONF_ERROR; + } + + fmt->name = value[1]; + + fmt->ops = ngx_array_create(cf->pool, 20, sizeof(ngx_http_log_op_t)); + if (fmt->ops == NULL) { + return NGX_CONF_ERROR; + } + + invalid = 0; + data = NULL; + arg.data = NULL; + + for (s = 2; s < cf->args->nelts && !invalid; s++) { + + i = 0; + + while (i < value[s].len) { + + op = ngx_array_push(fmt->ops); + if (op == NULL) { + return NGX_CONF_ERROR; + } + + data = &value[s].data[i]; + + if (value[s].data[i] == '%') { + i++; + + if (i == value[s].len) { + invalid = 1; + break; + } + + if (value[s].data[i] == '{') { + i++; + + arg.data = &value[s].data[i]; + + while (i < value[s].len && value[s].data[i] != '}') { + i++; + } + + arg.len = &value[s].data[i] - arg.data; + + if (i == value[s].len || arg.len == 0) { + invalid = 1; + break; + } + + i++; + + } else { + arg.len = 0; + } + + fname = &value[s].data[i]; + + while (i < value[s].len + && ((value[s].data[i] >= 'a' && value[s].data[i] <= 'z') + || value[s].data[i] == '_')) + { + i++; + } + + fname_len = &value[s].data[i] - fname; + + if (fname_len == 0) { + invalid = 1; + break; + } + + for (name = ngx_http_log_fmt_ops; name->run; name++) { + if (name->name.len == 0) { + name = (ngx_http_log_op_name_t *) name->run; + } + + if (name->name.len == fname_len + && ngx_strncmp(name->name.data, fname, fname_len) == 0) + { + if (name->compile == NULL) { + if (arg.len) { + fname[fname_len] = '\0'; + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"%s\" must not have argument", + data); + return NGX_CONF_ERROR; + } + + op->len = name->len; + op->getlen = name->getlen; + op->run = name->run; + op->data = 0; + + break; + } + + if (arg.len == 0) { + fname[fname_len] = '\0'; + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"%s\" requires argument", + data); + return NGX_CONF_ERROR; + } + + a = ngx_palloc(cf->pool, sizeof(ngx_str_t)); + if (a == NULL) { + return NGX_CONF_ERROR; + } + + *a = arg; + if (name->compile(cf, op, a) == NGX_ERROR) { + return NGX_CONF_ERROR; + } + + break; + } + } + + if (name->name.len == 0) { + invalid = 1; + break; + } + + } else { + i++; + + while (i < value[s].len && value[s].data[i] != '%') { + i++; + } + + len = &value[s].data[i] - data; + + if (len) { + + op->len = len; + op->getlen = NULL; + + if (len <= sizeof(uintptr_t)) { + op->run = ngx_http_log_copy_short; + op->data = 0; + + while (len--) { + op->data <<= 8; + op->data |= data[len]; + } + + } else { + op->run = ngx_http_log_copy_long; + + p = ngx_palloc(cf->pool, len); + if (p == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memcpy(p, data, len); + op->data = (uintptr_t) p; + } + } + } + } + } + + if (invalid) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%s\"", data); + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} diff --git a/src/http/ngx_http_log_module.h b/src/http/ngx_http_log_module.h new file mode 100644 --- /dev/null +++ b/src/http/ngx_http_log_module.h @@ -0,0 +1,71 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#ifndef _NGX_HTTP_LOG_MODULE_H_INCLUDED_ +#define _NGX_HTTP_LOG_MODULE_H_INCLUDED_ + + +#include +#include +#include + + +typedef struct ngx_http_log_op_s ngx_http_log_op_t; + +typedef u_char *(*ngx_http_log_op_run_pt) (ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op); + +typedef size_t (*ngx_http_log_op_getlen_pt) (ngx_http_request_t *r, + uintptr_t data); + +typedef ngx_int_t (*ngx_http_log_op_compile_pt) (ngx_conf_t *cf, + ngx_http_log_op_t *op, ngx_str_t *value); + + +struct ngx_http_log_op_s { + size_t len; + ngx_http_log_op_getlen_pt getlen; + ngx_http_log_op_run_pt run; + uintptr_t data; +}; + + +typedef struct { + ngx_str_t name; + ngx_array_t *ops; /* array of ngx_http_log_op_t */ +} ngx_http_log_fmt_t; + + +typedef struct { + ngx_str_t name; + size_t len; + ngx_http_log_op_compile_pt compile; + ngx_http_log_op_getlen_pt getlen; + ngx_http_log_op_run_pt run; +} ngx_http_log_op_name_t; + + +typedef struct { + ngx_array_t formats; /* array of ngx_http_log_fmt_t */ +} ngx_http_log_main_conf_t; + + +typedef struct { + ngx_open_file_t *file; + ngx_array_t *ops; /* array of ngx_http_log_op_t */ +} ngx_http_log_t; + + +typedef struct { + ngx_array_t *logs; /* array of ngx_http_log_t */ + ngx_uint_t off; /* unsigned off:1 */ +} ngx_http_log_loc_conf_t; + + +extern ngx_http_log_op_name_t ngx_http_log_fmt_ops[]; + + +#endif /* _NGX_HTTP_LOG_MODULE_H_INCLUDED_ */ 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 @@ -461,7 +461,6 @@ ngx_int_t ngx_http_parse_request_line(ng default: return NGX_HTTP_PARSE_INVALID_REQUEST; } - break; } } @@ -646,7 +645,6 @@ ngx_int_t ngx_http_parse_header_line(ngx default: return NGX_HTTP_PARSE_INVALID_HEADER; } - break; /* end of header */ case sw_header_almost_done: @@ -656,7 +654,6 @@ ngx_int_t ngx_http_parse_header_line(ngx default: return NGX_HTTP_PARSE_INVALID_HEADER; } - break; } } diff --git a/src/http/ngx_http_parse_time.c b/src/http/ngx_http_parse_time.c --- a/src/http/ngx_http_parse_time.c +++ b/src/http/ngx_http_parse_time.c @@ -229,10 +229,14 @@ time_t ngx_http_parse_time(u_char *value return NGX_ERROR; } - if (sizeof(time_t) <= 4 && year >= 2038) { +#if (NGX_TIME_T_SIZE <= 4) + + if (year >= 2038) { return NGX_ERROR; } +#endif + /* * shift new year to March 1 and start months from 1 (not 0), * it is needed for Gauss's formula 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 @@ -18,7 +18,7 @@ static void ngx_http_process_request_lin static void ngx_http_process_request_headers(ngx_event_t *rev); static ssize_t ngx_http_read_request_header(ngx_http_request_t *r); static ngx_int_t ngx_http_alloc_large_header_buffer(ngx_http_request_t *r, - ngx_uint_t request_line); + ngx_uint_t request_line); static ngx_int_t ngx_http_process_request_header(ngx_http_request_t *r); static ngx_int_t ngx_http_find_virtual_server(ngx_http_request_t *r); @@ -34,7 +34,7 @@ static void ngx_http_set_lingering_close static void ngx_http_lingering_close_handler(ngx_event_t *ev); static void ngx_http_client_error(ngx_http_request_t *r, - int client_error, int error); + int client_error, int error); static u_char *ngx_http_log_error(ngx_log_t *log, u_char *buf, size_t len); @@ -100,19 +100,22 @@ ngx_http_header_t ngx_http_headers_in[] #if 0 -static void ngx_http_dummy(ngx_event_t *wev) +static void +ngx_http_dummy(ngx_event_t *wev) { return; } #endif -void ngx_http_init_connection(ngx_connection_t *c) +void +ngx_http_init_connection(ngx_connection_t *c) { ngx_event_t *rev; ngx_http_log_ctx_t *ctx; - if (!(ctx = ngx_palloc(c->pool, sizeof(ngx_http_log_ctx_t)))) { + ctx = ngx_palloc(c->pool, sizeof(ngx_http_log_ctx_t)); + if (ctx == NULL) { ngx_http_close_connection(c); return; } @@ -186,7 +189,8 @@ void ngx_http_init_connection(ngx_connec } -static void ngx_http_init_request(ngx_event_t *rev) +static +void ngx_http_init_request(ngx_event_t *rev) { ngx_uint_t i; socklen_t len; @@ -225,7 +229,8 @@ static void ngx_http_init_request(ngx_ev #endif } else { - if (!(hc = ngx_pcalloc(c->pool, sizeof(ngx_http_connection_t)))) { + hc = ngx_pcalloc(c->pool, sizeof(ngx_http_connection_t)); + if (hc == NULL) { #if (NGX_STAT_STUB) ngx_atomic_dec(ngx_stat_reading); @@ -248,7 +253,8 @@ static void ngx_http_init_request(ngx_ev } } else { - if (!(r = ngx_pcalloc(c->pool, sizeof(ngx_http_request_t)))) { + r = ngx_pcalloc(c->pool, sizeof(ngx_http_request_t)); + if (r == NULL) { #if (NGX_STAT_STUB) ngx_atomic_dec(ngx_stat_reading); @@ -388,7 +394,8 @@ static void ngx_http_init_request(ngx_ev r->header_in = c->buffer; } - if (!(r->pool = ngx_create_pool(cscf->request_pool_size, c->log))) { + r->pool = ngx_create_pool(cscf->request_pool_size, c->log); + if (r->pool == NULL) { ngx_http_close_connection(c); return; } @@ -444,7 +451,8 @@ static void ngx_http_init_request(ngx_ev #if (NGX_HTTP_SSL) -static void ngx_http_ssl_handshake(ngx_event_t *rev) +static void +ngx_http_ssl_handshake(ngx_event_t *rev) { u_char buf[1]; ssize_t n; @@ -504,7 +512,8 @@ static void ngx_http_ssl_handshake(ngx_e #endif -static void ngx_http_process_request_line(ngx_event_t *rev) +static void +ngx_http_process_request_line(ngx_event_t *rev) { ssize_t n; ngx_int_t rc, rv; @@ -554,7 +563,8 @@ static void ngx_http_process_request_lin if (r->complex_uri || r->quoted_uri) { - if (!(r->uri.data = ngx_palloc(r->pool, r->uri.len + 1))) { + r->uri.data = ngx_palloc(r->pool, r->uri.len + 1); + if (r->uri.data == NULL) { ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); ngx_http_close_connection(c); return; @@ -707,7 +717,8 @@ static void ngx_http_process_request_lin } -static void ngx_http_process_request_headers(ngx_event_t *rev) +static void +ngx_http_process_request_headers(ngx_event_t *rev) { ssize_t n; ngx_int_t rc, rv, i; @@ -764,7 +775,8 @@ static void ngx_http_process_request_hea r->headers_n++; - if (!(h = ngx_list_push(&r->headers_in.headers))) { + h = ngx_list_push(&r->headers_in.headers); + if (h == NULL) { ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); ngx_http_close_connection(c); return; @@ -781,7 +793,8 @@ static void ngx_http_process_request_hea if (h->key.len == sizeof("Cookie") - 1 && ngx_strcasecmp(h->key.data, "Cookie") == 0) { - if (!(cookie = ngx_array_push(&r->headers_in.cookies))) { + cookie = ngx_array_push(&r->headers_in.cookies); + if (cookie == NULL) { ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); ngx_http_close_connection(c); return; @@ -879,7 +892,8 @@ static void ngx_http_process_request_hea } -static ssize_t ngx_http_read_request_header(ngx_http_request_t *r) +static ssize_t +ngx_http_read_request_header(ngx_http_request_t *r) { ssize_t n; ngx_event_t *rev; @@ -933,8 +947,9 @@ static ssize_t ngx_http_read_request_hea } -static ngx_int_t ngx_http_alloc_large_header_buffer(ngx_http_request_t *r, - ngx_uint_t request_line) +static ngx_int_t +ngx_http_alloc_large_header_buffer(ngx_http_request_t *r, + ngx_uint_t request_line) { u_char *old, *new; ngx_buf_t *b; @@ -1076,7 +1091,8 @@ static ngx_int_t ngx_http_alloc_large_he } -static ngx_int_t ngx_http_process_request_header(ngx_http_request_t *r) +static ngx_int_t +ngx_http_process_request_header(ngx_http_request_t *r) { u_char *ua, *user_agent, ch; size_t len; @@ -1106,7 +1122,7 @@ static ngx_int_t ngx_http_process_reques if (r->headers_in.content_length) { r->headers_in.content_length_n = - ngx_atoi(r->headers_in.content_length->value.data, + ngx_atosz(r->headers_in.content_length->value.data, r->headers_in.content_length->value.len); if (r->headers_in.content_length_n == NGX_ERROR) { @@ -1137,7 +1153,7 @@ static ngx_int_t ngx_http_process_reques if (r->headers_in.keep_alive) { r->headers_in.keep_alive_n = - ngx_atoi(r->headers_in.keep_alive->value.data, + ngx_atotm(r->headers_in.keep_alive->value.data, r->headers_in.keep_alive->value.len); } } @@ -1191,7 +1207,8 @@ static ngx_int_t ngx_http_process_reques } -static ngx_int_t ngx_http_find_virtual_server(ngx_http_request_t *r) +static ngx_int_t +ngx_http_find_virtual_server(ngx_http_request_t *r) { ngx_int_t rc; ngx_uint_t i, n, key, found; @@ -1297,7 +1314,8 @@ static ngx_int_t ngx_http_find_virtual_s } -void ngx_http_finalize_request(ngx_http_request_t *r, int rc) +void +ngx_http_finalize_request(ngx_http_request_t *r, int rc) { ngx_http_core_loc_conf_t *clcf; @@ -1380,7 +1398,8 @@ void ngx_http_finalize_request(ngx_http_ } -static void ngx_http_set_write_handler(ngx_http_request_t *r) +static void +ngx_http_set_write_handler(ngx_http_request_t *r) { ngx_event_t *wev; ngx_http_core_loc_conf_t *clcf; @@ -1409,7 +1428,8 @@ static void ngx_http_set_write_handler(n } -void ngx_http_writer(ngx_event_t *wev) +void +ngx_http_writer(ngx_event_t *wev) { int rc; ngx_connection_t *c; @@ -1486,7 +1506,8 @@ void ngx_http_writer(ngx_event_t *wev) } -static void ngx_http_block_read(ngx_event_t *rev) +static void +ngx_http_block_read(ngx_event_t *rev) { ngx_connection_t *c; ngx_http_request_t *r; @@ -1506,7 +1527,8 @@ static void ngx_http_block_read(ngx_even } -ngx_int_t ngx_http_discard_body(ngx_http_request_t *r) +ngx_int_t +ngx_http_discard_body(ngx_http_request_t *r) { ssize_t size; ngx_event_t *rev; @@ -1546,7 +1568,8 @@ ngx_int_t ngx_http_discard_body(ngx_http } -static void ngx_http_read_discarded_body_event(ngx_event_t *rev) +static void +ngx_http_read_discarded_body_event(ngx_event_t *rev) { ngx_int_t rc; ngx_connection_t *c; @@ -1572,7 +1595,8 @@ static void ngx_http_read_discarded_body } -static ngx_int_t ngx_http_read_discarded_body(ngx_http_request_t *r) +static ngx_int_t +ngx_http_read_discarded_body(ngx_http_request_t *r) { ssize_t size, n; u_char buffer[NGX_HTTP_DISCARD_BUFFER_SIZE]; @@ -1615,7 +1639,8 @@ static ngx_int_t ngx_http_read_discarded } -static void ngx_http_set_keepalive(ngx_http_request_t *r) +static void +ngx_http_set_keepalive(ngx_http_request_t *r) { int tcp_nodelay; ngx_int_t i; @@ -1776,7 +1801,7 @@ static void ngx_http_set_keepalive(ngx_h c->log->action = "keepalive"; if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) { - if (ngx_tcp_push(c->fd) == NGX_ERROR) { + if (ngx_tcp_push(c->fd) == -1) { ngx_connection_error(c, ngx_socket_errno, ngx_tcp_push_n " failed"); ngx_http_close_connection(c); return; @@ -1818,13 +1843,13 @@ static void ngx_http_set_keepalive(ngx_h } -static void ngx_http_keepalive_handler(ngx_event_t *rev) +static void +ngx_http_keepalive_handler(ngx_event_t *rev) { - size_t size; - ssize_t n; - ngx_buf_t *b; - ngx_connection_t *c; - ngx_http_connection_t *hc; + size_t size; + ssize_t n; + ngx_buf_t *b; + ngx_connection_t *c; c = rev->data; @@ -1855,7 +1880,6 @@ static void ngx_http_keepalive_handler(n #endif - hc = c->data; b = c->buffer; size = b->end - b->start; @@ -1867,7 +1891,8 @@ static void ngx_http_keepalive_handler(n * to keep the buffer size. */ - if (!(b->pos = ngx_palloc(c->pool, size))) { + b->pos = ngx_palloc(c->pool, size); + if (b->pos == NULL) { ngx_http_close_connection(c); return; } @@ -1919,7 +1944,8 @@ static void ngx_http_keepalive_handler(n } -static void ngx_http_set_lingering_close(ngx_http_request_t *r) +static void +ngx_http_set_lingering_close(ngx_http_request_t *r) { ngx_event_t *rev, *wev; ngx_connection_t *c; @@ -1977,7 +2003,8 @@ static void ngx_http_set_lingering_close } -static void ngx_http_lingering_close_handler(ngx_event_t *rev) +static void +ngx_http_lingering_close_handler(ngx_event_t *rev) { ssize_t n; ngx_msec_t timer; @@ -2036,7 +2063,8 @@ static void ngx_http_lingering_close_han } -void ngx_http_empty_handler(ngx_event_t *wev) +void +ngx_http_empty_handler(ngx_event_t *wev) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0, "http empty handler"); @@ -2044,12 +2072,14 @@ void ngx_http_empty_handler(ngx_event_t } -ngx_int_t ngx_http_send_last(ngx_http_request_t *r) +ngx_int_t +ngx_http_send_last(ngx_http_request_t *r) { ngx_buf_t *b; ngx_chain_t out; - if (!(b = ngx_calloc_buf(r->pool))) { + b = ngx_calloc_buf(r->pool); + if (b == NULL) { return NGX_ERROR; } @@ -2061,7 +2091,8 @@ ngx_int_t ngx_http_send_last(ngx_http_re } -void ngx_http_close_request(ngx_http_request_t *r, int error) +void +ngx_http_close_request(ngx_http_request_t *r, int error) { ngx_uint_t i; ngx_log_t *log; @@ -2171,7 +2202,8 @@ void ngx_http_close_request(ngx_http_req #if (NGX_HTTP_SSL) -void ngx_ssl_close_handler(ngx_event_t *ev) +void +ngx_ssl_close_handler(ngx_event_t *ev) { ngx_connection_t *c; @@ -2189,7 +2221,8 @@ void ngx_ssl_close_handler(ngx_event_t * #endif -void ngx_http_close_connection(ngx_connection_t *c) +void +ngx_http_close_connection(ngx_connection_t *c) { ngx_pool_t *pool; @@ -2216,12 +2249,12 @@ void ngx_http_close_connection(ngx_conne ngx_close_connection(c); - ngx_destroy_pool(c->pool); + ngx_destroy_pool(pool); } -static void ngx_http_client_error(ngx_http_request_t *r, - int client_error, int error) +static void +ngx_http_client_error(ngx_http_request_t *r, int client_error, int error) { u_char *p; ngx_http_log_ctx_t *ctx; @@ -2315,7 +2348,8 @@ static void ngx_http_client_error(ngx_ht } -static u_char *ngx_http_log_error(ngx_log_t *log, u_char *buf, size_t len) +static u_char * +ngx_http_log_error(ngx_log_t *log, u_char *buf, size_t len) { u_char *p; ngx_http_log_ctx_t *ctx; 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 @@ -119,91 +119,91 @@ typedef enum { typedef struct { - ngx_str_t name; - ngx_uint_t offset; + ngx_str_t name; + ngx_uint_t offset; } ngx_http_header_t; typedef struct { - ngx_list_t headers; + ngx_list_t headers; - ngx_table_elt_t *host; - ngx_table_elt_t *connection; - ngx_table_elt_t *if_modified_since; - ngx_table_elt_t *user_agent; - ngx_table_elt_t *referer; - ngx_table_elt_t *content_length; - ngx_table_elt_t *content_type; + ngx_table_elt_t *host; + ngx_table_elt_t *connection; + ngx_table_elt_t *if_modified_since; + ngx_table_elt_t *user_agent; + ngx_table_elt_t *referer; + ngx_table_elt_t *content_length; + ngx_table_elt_t *content_type; - ngx_table_elt_t *range; + ngx_table_elt_t *range; #if (NGX_HTTP_GZIP) - ngx_table_elt_t *accept_encoding; - ngx_table_elt_t *via; + ngx_table_elt_t *accept_encoding; + ngx_table_elt_t *via; #endif - ngx_table_elt_t *authorization; + ngx_table_elt_t *authorization; - ngx_table_elt_t *keep_alive; + ngx_table_elt_t *keep_alive; #if (NGX_HTTP_PROXY) - ngx_table_elt_t *x_forwarded_for; - ngx_table_elt_t *x_real_ip; - ngx_table_elt_t *x_url; + ngx_table_elt_t *x_forwarded_for; + ngx_table_elt_t *x_real_ip; + ngx_table_elt_t *x_url; #endif #if (NGX_HTTP_HEADERS) - ngx_table_elt_t *accept; - ngx_table_elt_t *accept_language; + ngx_table_elt_t *accept; + ngx_table_elt_t *accept_language; #endif - ngx_array_t cookies; + ngx_array_t cookies; + + size_t host_name_len; + ssize_t content_length_n; + time_t keep_alive_n; - size_t host_name_len; - ssize_t content_length_n; - size_t connection_type; - ssize_t keep_alive_n; - - unsigned msie:1; - unsigned msie4:1; - unsigned opera:1; - unsigned gecko:1; - unsigned konqueror:1; + unsigned connection_type:2; + unsigned msie:1; + unsigned msie4:1; + unsigned opera:1; + unsigned gecko:1; + unsigned konqueror:1; } ngx_http_headers_in_t; typedef struct { - off_t start; - off_t end; - ngx_str_t content_range; + off_t start; + off_t end; + ngx_str_t content_range; } ngx_http_range_t; typedef struct { - ngx_list_t headers; + ngx_list_t headers; - ngx_uint_t status; - ngx_str_t status_line; + ngx_uint_t status; + ngx_str_t status_line; - ngx_table_elt_t *server; - ngx_table_elt_t *date; - ngx_table_elt_t *content_type; - ngx_table_elt_t *content_length; - ngx_table_elt_t *content_encoding; - ngx_table_elt_t *location; - ngx_table_elt_t *last_modified; - ngx_table_elt_t *content_range; - ngx_table_elt_t *accept_ranges; - ngx_table_elt_t *expires; - ngx_table_elt_t *cache_control; - ngx_table_elt_t *etag; + ngx_table_elt_t *server; + ngx_table_elt_t *date; + ngx_table_elt_t *content_type; + ngx_table_elt_t *content_length; + ngx_table_elt_t *content_encoding; + ngx_table_elt_t *location; + ngx_table_elt_t *last_modified; + ngx_table_elt_t *content_range; + ngx_table_elt_t *accept_ranges; + ngx_table_elt_t *expires; + ngx_table_elt_t *cache_control; + ngx_table_elt_t *etag; - ngx_str_t charset; - ngx_array_t ranges; + ngx_str_t charset; + ngx_array_t ranges; - off_t content_length_n; - time_t date_time; - time_t last_modified_time; + off_t content_length_n; + time_t date_time; + time_t last_modified_time; } ngx_http_headers_out_t; @@ -221,172 +221,171 @@ typedef struct { struct ngx_http_cleanup_s { union { struct { - ngx_fd_t fd; - u_char *name; + ngx_fd_t fd; + u_char *name; } file; struct { - ngx_http_cache_hash_t *hash; - ngx_http_cache_entry_t *cache; + ngx_http_cache_hash_t *hash; + ngx_http_cache_entry_t *cache; } cache; } data; - unsigned valid:1; - unsigned cache:1; + unsigned valid:1; + unsigned cache:1; }; typedef struct { - ngx_http_request_t *request; + ngx_http_request_t *request; - ngx_buf_t **busy; - ngx_int_t nbusy; + ngx_buf_t **busy; + ngx_int_t nbusy; - ngx_buf_t **free; - ngx_int_t nfree; + ngx_buf_t **free; + ngx_int_t nfree; - ngx_uint_t pipeline; /* unsigned pipeline:1; */ + ngx_uint_t pipeline; /* unsigned pipeline:1; */ } ngx_http_connection_t; typedef ngx_int_t (*ngx_http_handler_pt)(ngx_http_request_t *r); struct ngx_http_request_s { - uint32_t signature; /* "HTTP" */ + uint32_t signature; /* "HTTP" */ - ngx_connection_t *connection; + ngx_connection_t *connection; - void **ctx; - void **main_conf; - void **srv_conf; - void **loc_conf; + void **ctx; + void **main_conf; + void **srv_conf; + void **loc_conf; - ngx_http_cache_t *cache; + ngx_http_cache_t *cache; - ngx_http_upstream_t *upstream; + ngx_http_upstream_t *upstream; - ngx_file_t file; + ngx_file_t file; - ngx_pool_t *pool; - ngx_buf_t *header_in; + ngx_pool_t *pool; + ngx_buf_t *header_in; - ngx_http_headers_in_t headers_in; - ngx_http_headers_out_t headers_out; + ngx_http_headers_in_t headers_in; + ngx_http_headers_out_t headers_out; - ngx_http_request_body_t *request_body; + ngx_http_request_body_t *request_body; - time_t lingering_time; - time_t start_time; + time_t lingering_time; + time_t start_time; - ngx_uint_t method; - ngx_uint_t http_version; - ngx_uint_t http_major; - ngx_uint_t http_minor; - - ngx_str_t request_line; - ngx_str_t uri; - ngx_str_t args; - ngx_str_t exten; - ngx_str_t unparsed_uri; - - ngx_str_t method_name; - ngx_str_t http_protocol; + ngx_uint_t method; + ngx_uint_t http_version; + ngx_uint_t http_major; + ngx_uint_t http_minor; + + ngx_str_t request_line; + ngx_str_t uri; + ngx_str_t args; + ngx_str_t exten; + ngx_str_t unparsed_uri; - ngx_http_request_t *main; - - uint32_t in_addr; - ngx_uint_t port; - ngx_str_t *port_text; /* ":80" */ - ngx_str_t server_name; - ngx_http_in_addr_t *virtual_names; + ngx_str_t method_name; + ngx_str_t http_protocol; + + ngx_http_request_t *main; - ngx_uint_t phase; - ngx_int_t phase_handler; - ngx_http_handler_pt content_handler; + uint32_t in_addr; + ngx_uint_t port; + ngx_str_t *port_text; /* ":80" */ + ngx_str_t server_name; + ngx_http_in_addr_t *virtual_names; - ngx_uint_t nvariables; - void **variables; + ngx_uint_t phase; + ngx_int_t phase_handler; + ngx_http_handler_pt content_handler; - ngx_array_t cleanup; + ngx_http_variable_value_t **variables; + + ngx_array_t cleanup; /* used to learn the Apache compatible response length without a header */ - size_t header_size; + size_t header_size; - size_t request_length; + size_t request_length; - u_char *discarded_buffer; - void **err_ctx; - ngx_uint_t err_status; + u_char *discarded_buffer; + void **err_ctx; + ngx_uint_t err_status; - ngx_http_connection_t *http_connection; + ngx_http_connection_t *http_connection; - unsigned http_state:4; + unsigned http_state:4; /* URI with "/." and on Win32 with "//" */ - unsigned complex_uri:1; + unsigned complex_uri:1; /* URI with "%" */ - unsigned quoted_uri:1; + unsigned quoted_uri:1; /* URI with "+" */ - unsigned plus_in_uri:1; + unsigned plus_in_uri:1; /* URI with "\0" or "%00" */ - unsigned zero_in_uri:1; + unsigned zero_in_uri:1; - unsigned uri_changed:1; - unsigned uri_changes:4; + unsigned uri_changed:1; + unsigned uri_changes:4; - unsigned low_case_exten:1; - unsigned header_timeout_set:1; + unsigned low_case_exten:1; + unsigned header_timeout_set:1; - unsigned proxy:1; - unsigned bypass_cache:1; - unsigned no_cache:1; + unsigned proxy:1; + unsigned bypass_cache:1; + unsigned no_cache:1; #if 0 - unsigned cachable:1; + unsigned cachable:1; #endif - unsigned pipeline:1; + unsigned pipeline:1; - unsigned plain_http:1; - unsigned chunked:1; - unsigned header_only:1; - unsigned keepalive:1; - unsigned lingering_close:1; - unsigned closed:1; + unsigned plain_http:1; + unsigned chunked:1; + unsigned header_only:1; + unsigned keepalive:1; + unsigned lingering_close:1; + unsigned closed:1; - unsigned filter_need_in_memory:1; - unsigned filter_ssi_need_in_memory:1; - unsigned filter_need_temporary:1; - unsigned filter_allow_ranges:1; + unsigned filter_need_in_memory:1; + unsigned filter_ssi_need_in_memory:1; + unsigned filter_need_temporary:1; + unsigned filter_allow_ranges:1; #if (NGX_STAT_STUB) - unsigned stat_reading:1; - unsigned stat_writing:1; + unsigned stat_reading:1; + unsigned stat_writing:1; #endif - ngx_uint_t headers_n; + ngx_uint_t headers_n; /* used to parse HTTP headers */ - ngx_uint_t state; - u_char *uri_start; - u_char *uri_end; - u_char *uri_ext; - u_char *args_start; - u_char *request_start; - u_char *request_end; - u_char *method_end; - u_char *schema_start; - u_char *schema_end; - u_char *host_start; - u_char *host_end; - u_char *port_start; - u_char *port_end; - u_char *header_name_start; - u_char *header_name_end; - u_char *header_start; - u_char *header_end; + ngx_uint_t state; + u_char *uri_start; + u_char *uri_end; + u_char *uri_ext; + u_char *args_start; + u_char *request_start; + u_char *request_end; + u_char *method_end; + u_char *schema_start; + u_char *schema_end; + u_char *host_start; + u_char *host_end; + u_char *port_start; + u_char *port_end; + u_char *header_name_start; + u_char *header_name_end; + u_char *header_start; + u_char *header_end; }; diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c --- a/src/http/ngx_http_request_body.c +++ b/src/http/ngx_http_request_body.c @@ -12,7 +12,7 @@ static void ngx_http_read_client_request_body_handler(ngx_event_t *rev); static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r, - ngx_connection_t *c); + ngx_connection_t *c); /* * on completion ngx_http_read_client_request_body() adds to @@ -21,22 +21,35 @@ static ngx_int_t ngx_http_do_read_client * *) one memory or file buf that contains the rest of the body */ -ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r, - ngx_http_client_body_handler_pt post_handler) +ngx_int_t +ngx_http_read_client_request_body(ngx_http_request_t *r, + ngx_http_client_body_handler_pt post_handler) { ssize_t size; ngx_buf_t *b; ngx_chain_t *cl; + ngx_connection_t *c; ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; - if (!(rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)))) { + rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); + if (rb == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } r->request_body = rb; + /* STUB */ + if (r->file.fd != NGX_INVALID_FILE) { + if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, + ngx_close_file_n " \"%V\" failed", &r->file.name); + } + r->file.fd = NGX_INVALID_FILE; + } + /**/ + if (r->headers_in.content_length_n <= 0) { post_handler(r); return NGX_OK; @@ -58,7 +71,8 @@ ngx_int_t ngx_http_read_client_request_b /* there is the pre-read part of the request body */ - if (!(b = ngx_calloc_buf(r->pool))) { + b = ngx_calloc_buf(r->pool); + if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -66,7 +80,8 @@ ngx_int_t ngx_http_read_client_request_b b->start = b->pos = r->header_in->pos; b->end = b->last = r->header_in->last; - if (!(rb->bufs = ngx_alloc_chain_link(r->pool))) { + rb->bufs = ngx_alloc_chain_link(r->pool); + if (rb->bufs == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -103,11 +118,13 @@ ngx_int_t ngx_http_read_client_request_b size = clcf->client_body_buffer_size; } - if (!(rb->buf = ngx_create_temp_buf(r->pool, size))) { + rb->buf = ngx_create_temp_buf(r->pool, size); + if (rb->buf == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } - if (!(cl = ngx_alloc_chain_link(r->pool))) { + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -121,14 +138,16 @@ ngx_int_t ngx_http_read_client_request_b rb->bufs = cl; } - r->connection->read->event_handler = - ngx_http_read_client_request_body_handler; + c = r->connection; - return ngx_http_do_read_client_request_body(r, r->connection); + c->read->event_handler = ngx_http_read_client_request_body_handler; + + return ngx_http_do_read_client_request_body(r, c); } -static void ngx_http_read_client_request_body_handler(ngx_event_t *rev) +static void +ngx_http_read_client_request_body_handler(ngx_event_t *rev) { ngx_int_t rc; ngx_connection_t *c; @@ -150,8 +169,9 @@ static void ngx_http_read_client_request } -static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r, - ngx_connection_t *c) +static ngx_int_t +ngx_http_do_read_client_request_body(ngx_http_request_t *r, + ngx_connection_t *c) { size_t size; ssize_t n; @@ -169,7 +189,8 @@ static ngx_int_t ngx_http_do_read_client if (rb->buf->last == rb->buf->end) { if (rb->temp_file == NULL) { - if (!(tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)))) { + tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)); + if (tf == NULL) { return NGX_ERROR; } @@ -268,7 +289,8 @@ static ngx_int_t ngx_http_do_read_client return NGX_HTTP_INTERNAL_SERVER_ERROR; } - if (!(b = ngx_calloc_buf(r->pool))) { + b = ngx_calloc_buf(r->pool); + if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } 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 @@ -17,7 +17,7 @@ static u_char error_tail[] = ; -static u_char msie_stub[] = +static u_char ngx_http_msie_stub[] = "" CRLF "" CRLF "" CRLF @@ -234,9 +234,9 @@ ngx_int_t ngx_http_special_response_handler(ngx_http_request_t *r, ngx_int_t error) { ngx_int_t rc; - ngx_uint_t err, i, msie_padding; + ngx_uint_t i, err, msie_padding; ngx_buf_t *b; - ngx_chain_t *out, **ll, *cl; + ngx_chain_t *out, *cl; ngx_http_err_page_t *err_page; ngx_http_core_loc_conf_t *clcf; @@ -327,7 +327,7 @@ ngx_http_special_response_handler(ngx_ht && error >= NGX_HTTP_BAD_REQUEST && error != NGX_HTTP_REQUEST_URI_TOO_LARGE) { - r->headers_out.content_length_n += sizeof(msie_stub) - 1; + r->headers_out.content_length_n += sizeof(ngx_http_msie_stub) - 1; msie_padding = 1; } @@ -360,43 +360,64 @@ ngx_http_special_response_handler(ngx_ht return NGX_OK; } - out = NULL; - ll = NULL; - if (!(b = ngx_calloc_buf(r->pool))) { + b = ngx_calloc_buf(r->pool); + if (b == NULL) { return NGX_ERROR; } + b->memory = 1; b->pos = error_pages[err].data; b->last = error_pages[err].data + error_pages[err].len; - ngx_alloc_link_and_set_buf(cl, b, r->pool, NGX_ERROR); - ngx_chain_add_link(out, ll, cl); + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { + return NGX_ERROR; + } + + cl->buf = b; + out = cl; - if (!(b = ngx_calloc_buf(r->pool))) { + b = ngx_calloc_buf(r->pool); + if (b == NULL) { return NGX_ERROR; } + b->memory = 1; b->pos = error_tail; b->last = error_tail + sizeof(error_tail) - 1; - ngx_alloc_link_and_set_buf(cl, b, r->pool, NGX_ERROR); - ngx_chain_add_link(out, ll, cl); + cl->next = ngx_alloc_chain_link(r->pool); + if (cl->next == NULL) { + return NGX_ERROR; + } + + cl = cl->next; + cl->buf = b; if (msie_padding) { - if (!(b = ngx_calloc_buf(r->pool))) { + b = ngx_calloc_buf(r->pool); + if (b == NULL) { return NGX_ERROR; } + b->memory = 1; - b->pos = msie_stub; - b->last = msie_stub + sizeof(msie_stub) - 1; + b->pos = ngx_http_msie_stub; + b->last = ngx_http_msie_stub + sizeof(ngx_http_msie_stub) - 1; - ngx_alloc_link_and_set_buf(cl, b, r->pool, NGX_ERROR); - ngx_chain_add_link(out, ll, cl); + cl->next = ngx_alloc_chain_link(r->pool); + if (cl->next == NULL) { + return NGX_ERROR; + } + + cl = cl->next; + cl->buf = b; } b->last_buf = 1; + cl->next = NULL; + return ngx_http_output_filter(r, out); } 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 @@ -129,13 +129,14 @@ ngx_http_upstream_init(ngx_http_request_ u->writer.pool = r->pool; if (ngx_array_init(&u->states, r->pool, u->peer.peers->number, - sizeof(ngx_http_upstream_state_t)) == NGX_ERROR) + sizeof(ngx_http_upstream_state_t)) != NGX_OK) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } - if (!(u->state = ngx_push_array(&u->states))) { + u->state = ngx_array_push(&u->states); + if (u->state == NULL) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } @@ -317,7 +318,8 @@ ngx_http_upstream_connect(ngx_http_reque if (r->request_body->buf) { if (r->request_body->temp_file) { - if (!(u->output.free = ngx_alloc_chain_link(r->pool))) { + u->output.free = ngx_alloc_chain_link(r->pool); + if (u->output.free == NULL) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_INTERNAL_SERVER_ERROR); return; @@ -392,7 +394,8 @@ ngx_http_upstream_reinit(ngx_http_reques /* add one more state */ - if (!(u->state = ngx_push_array(&u->states))) { + u->state = ngx_array_push(&u->states); + if (u->state == NULL) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_INTERNAL_SERVER_ERROR); return; @@ -739,7 +742,8 @@ ngx_http_upstream_send_response(ngx_http p->cachable = u->cachable; - if (!(p->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)))) { + p->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)); + if (p->temp_file == NULL) { ngx_http_upstream_finalize_request(r, u, 0); return; } @@ -759,7 +763,8 @@ ngx_http_upstream_send_response(ngx_http p->max_temp_file_size = u->conf->max_temp_file_size; p->temp_file_write_size = u->conf->temp_file_write_size; - if (!(p->preread_bufs = ngx_alloc_chain_link(r->pool))) { + p->preread_bufs = ngx_alloc_chain_link(r->pool); + if (p->preread_bufs == NULL) { ngx_http_upstream_finalize_request(r, u, 0); return; } 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 @@ -25,7 +25,7 @@ static ngx_http_variable_value_t * ngx_http_variable_header(ngx_http_request_t *r, uintptr_t data); static ngx_http_variable_value_t * - ngx_http_variable_unknown_header(ngx_http_request_t *r, ngx_str_t *var); + ngx_http_variable_unknown_header(ngx_http_request_t *r, uintptr_t data); static ngx_http_variable_value_t * ngx_http_variable_remote_addr(ngx_http_request_t *r, uintptr_t data); static ngx_http_variable_value_t * @@ -69,39 +69,71 @@ static ngx_http_core_variable_t ngx_htt ngx_http_variable_t * -ngx_http_add_variable(ngx_conf_t *cf) +ngx_http_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t set) { - ngx_http_variable_t *var; + ngx_uint_t i; + ngx_http_variable_t *v; ngx_http_core_main_conf_t *cmcf; cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); - if (cmcf->variables.elts == NULL) { + v = cmcf->variables.elts; + + if (v == NULL) { if (ngx_array_init(&cmcf->variables, cf->pool, 4, sizeof(ngx_http_variable_t)) == NGX_ERROR) { return NULL; } + + } else { + for (i = 0; i < cmcf->variables.nelts; i++) { + if (name->len != v[i].name.len + || ngx_strncasecmp(name->data, v[i].name.data, name->len) != 0) + { + continue; + } + + if (set && v[i].handler) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the duplicate \"%V\" variable", name); + return NULL; + } + + return &v[i]; + } } - if (!(var = ngx_array_push(&cmcf->variables))) { + v = ngx_array_push(&cmcf->variables); + if (v == NULL) { return NULL; } - var->index = cmcf->variables.nelts - 1; + v->name.len = name->len; + v->name.data = ngx_palloc(cf->pool, name->len); + if (v->name.data == NULL) { + return NULL; + } - return var; + for (i = 0; i < name->len; i++) { + v->name.data[i] = ngx_toupper(name->data[i]); + } + + v->index = cmcf->variables.nelts - 1; + v->handler = NULL; + v->data = 0; + + return v; } ngx_http_variable_value_t * ngx_http_get_indexed_variable(ngx_http_request_t *r, ngx_uint_t index) { - ngx_http_variable_t *var; + ngx_http_variable_t *v; + ngx_http_variable_value_t *vv; ngx_http_core_main_conf_t *cmcf; - /* TODO: cached variables */ - cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); if (cmcf->variables.elts == NULL || cmcf->variables.nelts <= index) { @@ -110,70 +142,70 @@ ngx_http_get_indexed_variable(ngx_http_r return NULL; } - var = cmcf->variables.elts; + if (r->variables && r->variables[index]) { + return r->variables[index]; + } - return var[index].handler(r, var[index].data); -} - + v = cmcf->variables.elts; -ngx_int_t -ngx_http_get_variable_index(ngx_http_core_main_conf_t *cmcf, ngx_str_t *name) -{ - ngx_uint_t i; - ngx_http_variable_t *var; + vv = v[index].handler(r, v[index].data); - var = cmcf->variables.elts; - for (i = 0; i < cmcf->variables.nelts; i++) { - if (var[i].name.len != name->len) { - continue; - } - - if (ngx_strncasecmp(var[i].name.data, name->data, name->len) == 0) { - return var[i].index; + if (r->variables == NULL) { + r->variables = ngx_pcalloc(r->pool, cmcf->variables.nelts + * sizeof(ngx_http_variable_value_t *)); + if (r->variables == NULL) { + return NULL; } } - return -1; + r->variables[index] = vv; + + return vv; } ngx_http_variable_value_t * ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name) { - ngx_int_t index; ngx_uint_t i, key; - ngx_http_core_variable_t *var; + ngx_http_variable_t *v; + ngx_http_core_variable_t *cv; ngx_http_core_main_conf_t *cmcf; cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); - index = ngx_http_get_variable_index(cmcf, name); + v = cmcf->variables.elts; + for (i = 0; i < cmcf->variables.nelts; i++) { + if (v[i].name.len != name->len) { + continue; + } - if (index != -1) { - return ngx_http_get_indexed_variable(r, index); + if (ngx_strncmp(v[i].name.data, name->data, name->len) == 0) { + return ngx_http_get_indexed_variable(r, v[i].index); + } } ngx_http_vars_hash_key(key, name); - var = ngx_http_core_variables_hash[key].elts; + cv = ngx_http_core_variables_hash[key].elts; for (i = 0; i < ngx_http_core_variables_hash[key].nelts; i++) { - - if (var[i].name.len != name->len - || ngx_strncasecmp(var[i].name.data, name->data, name->len) != 0) - { + if (cv[i].name.len != name->len) { continue; } - return var[i].handler(r, var[i].data); + if (ngx_strncmp(cv[i].name.data, name->data, name->len) == 0) { + return cv[i].handler(r, cv[i].data); + } } - if (ngx_strncasecmp(name->data, "HTTP_", 5) != 0) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "unknown \"%V\" variable", name); - return NGX_HTTP_VARIABLE_NOT_FOUND; + if (ngx_strncmp(name->data, "HTTP_", 5) == 0) { + return ngx_http_variable_unknown_header(r, (uintptr_t) name); } - return ngx_http_variable_unknown_header(r, name); + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "unknown \"%V\" variable", name); + + return NGX_HTTP_VARIABLE_NOT_FOUND; } @@ -181,7 +213,7 @@ static ngx_http_variable_value_t * ngx_http_variable_header(ngx_http_request_t *r, uintptr_t data) { ngx_table_elt_t *h; - ngx_http_variable_value_t *v; + ngx_http_variable_value_t *vv; h = *(ngx_table_elt_t **) ((char *) &r->headers_in + data); @@ -189,25 +221,28 @@ ngx_http_variable_header(ngx_http_reques return NGX_HTTP_VARIABLE_NOT_FOUND; } - if (!(v = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)))) { + vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); + if (vv == NULL) { return NULL; } - v->value = 0; - v->text = h->value; + vv->value = 0; + vv->text = h->value; - return v; + return vv; } static ngx_http_variable_value_t * -ngx_http_variable_unknown_header(ngx_http_request_t *r, ngx_str_t *var) +ngx_http_variable_unknown_header(ngx_http_request_t *r, uintptr_t data) { + ngx_str_t *var = (ngx_str_t *) data; + u_char ch; ngx_uint_t i, n; ngx_list_part_t *part; ngx_table_elt_t *header; - ngx_http_variable_value_t *v; + ngx_http_variable_value_t *vv; part = &r->headers_in.headers.part; header = part->elts; @@ -241,13 +276,14 @@ ngx_http_variable_unknown_header(ngx_htt } if (n + 5 == var->len) { - if (!(v = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)))) { + vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); + if (vv == NULL) { return NULL; } - v->value = 0; - v->text = header[i].value; - return v; + vv->value = 0; + vv->text = header[i].value; + return vv; } } @@ -258,56 +294,61 @@ ngx_http_variable_unknown_header(ngx_htt static ngx_http_variable_value_t * ngx_http_variable_remote_addr(ngx_http_request_t *r, uintptr_t data) { - ngx_http_variable_value_t *v; + ngx_http_variable_value_t *vv; - if (!(v = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)))) { + vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); + if (vv == NULL) { return NULL; } - v->value = 0; - v->text = r->connection->addr_text; + vv->value = 0; + vv->text = r->connection->addr_text; - return v; + return vv; } static ngx_http_variable_value_t * ngx_http_variable_uri(ngx_http_request_t *r, uintptr_t data) { - ngx_http_variable_value_t *v; + ngx_http_variable_value_t *vv; - if (!(v = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)))) { + vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); + if (vv == NULL) { return NULL; } - v->value = 0; - v->text = r->uri; + vv->value = 0; + vv->text = r->uri; - return v; + return vv; } static ngx_http_variable_value_t * ngx_http_variable_query_string(ngx_http_request_t *r, uintptr_t data) { - ngx_http_variable_value_t *v; + ngx_http_variable_value_t *vv; - if (!(v = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)))) { + vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); + if (vv == NULL) { return NULL; } - v->value = 0; - v->text = r->args; + vv->value = 0; + vv->text = r->args; - return v; + return vv; } ngx_int_t -ngx_http_core_variables_init(ngx_cycle_t *cycle) +ngx_http_variables_init(ngx_cycle_t *cycle) { - ngx_uint_t i, key; - ngx_http_core_variable_t *var, *v; + ngx_uint_t i, j, key; + ngx_http_variable_t *v; + ngx_http_core_variable_t *cv, *vp; + ngx_http_core_main_conf_t *cmcf; ngx_http_core_variables_hash = ngx_palloc(cycle->pool, NGX_HTTP_VARS_HASH_PRIME @@ -324,14 +365,54 @@ ngx_http_core_variables_init(ngx_cycle_t } } - for (var = ngx_http_core_variables; var->name.len; var++) { - ngx_http_vars_hash_key(key, &var->name); + for (cv = ngx_http_core_variables; cv->name.len; cv++) { + ngx_http_vars_hash_key(key, &cv->name); - if (!(v = ngx_array_push(&ngx_http_core_variables_hash[key]))) { + vp = ngx_array_push(&ngx_http_core_variables_hash[key]); + if (vp == NULL) { return NGX_ERROR; } - *v = *var; + *vp = *cv; + } + + + cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module); + + v = cmcf->variables.elts; + for (i = 0; i < cmcf->variables.nelts; i++) { + + if (v[i].handler) { + continue; + } + + ngx_http_vars_hash_key(key, &v[i].name); + + cv = ngx_http_core_variables_hash[key].elts; + for (j = 0; j < ngx_http_core_variables_hash[key].nelts; j++) { + if (cv[j].name.len != v[i].name.len) { + continue; + } + + if (ngx_strncmp(cv[j].name.data, v[i].name.data, v[i].name.len) + == 0) + { + v[i].handler = cv[j].handler; + v[i].data = cv[j].data; + continue; + } + } + + if (ngx_strncmp(v[i].name.data, "HTTP_", 5) == 0) { + v[i].handler = ngx_http_variable_unknown_header; + v[i].data = (uintptr_t) &v[i].name; + continue; + } + + ngx_log_error(NGX_LOG_ERR, cycle->log, 0, + "unknown \"%V\" variable", &v[i].name); + + return NGX_ERROR; } return NGX_OK; diff --git a/src/http/ngx_http_variables.h b/src/http/ngx_http_variables.h --- a/src/http/ngx_http_variables.h +++ b/src/http/ngx_http_variables.h @@ -17,45 +17,41 @@ #define NGX_HTTP_VARIABLE_NOT_FOUND (ngx_http_variable_value_t *) -1 -typedef struct { +struct ngx_http_variable_value_s { ngx_uint_t value; ngx_str_t text; -} ngx_http_variable_value_t; - +}; typedef struct ngx_http_variable_s ngx_http_variable_t; typedef ngx_http_variable_value_t * - (*ngx_http_get_variable_pt) (ngx_http_request_t *r, void *var); + (*ngx_http_get_variable_pt) (ngx_http_request_t *r, uintptr_t data); struct ngx_http_variable_s { - ngx_str_t name; - ngx_uint_t index; - ngx_http_get_variable_pt handler; - void *data; - ngx_uint_t uses; + ngx_str_t name; + ngx_uint_t index; + ngx_http_get_variable_pt handler; + uintptr_t data; }; -typedef ngx_http_variable_value_t * - (*ngx_http_get_core_variable_pt) (ngx_http_request_t *r, uintptr_t data); - typedef struct { - ngx_str_t name; - ngx_http_get_core_variable_pt handler; - uintptr_t data; + ngx_str_t name; + ngx_http_get_variable_pt handler; + uintptr_t data; } ngx_http_core_variable_t; -ngx_http_variable_t *ngx_http_add_variable(ngx_conf_t *cf); +ngx_http_variable_t *ngx_http_add_variable(ngx_conf_t *cf, ngx_str_t *name, + ngx_uint_t set); ngx_int_t ngx_http_get_variable_index(ngx_http_core_main_conf_t *cmcf, ngx_str_t *name); ngx_http_variable_value_t *ngx_http_get_indexed_variable(ngx_http_request_t *r, ngx_uint_t index); ngx_http_variable_value_t *ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name); -ngx_int_t ngx_http_core_variables_init(ngx_cycle_t *cycle); +ngx_int_t ngx_http_variables_init(ngx_cycle_t *cycle); #endif /* _NGX_HTTP_VARIABLES_H_INCLUDED_ */ diff --git a/src/http/ngx_http_write_filter.c b/src/http/ngx_http_write_filter.c deleted file mode 100644 --- a/src/http/ngx_http_write_filter.c +++ /dev/null @@ -1,238 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#include -#include -#include -#include - - -typedef struct { - ngx_chain_t *out; -} ngx_http_write_filter_ctx_t; - - -static ngx_int_t ngx_http_write_filter_init(ngx_cycle_t *cycle); - - -ngx_http_module_t ngx_http_write_filter_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_write_filter_module = { - NGX_MODULE, - &ngx_http_write_filter_module_ctx, /* module context */ - NULL, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - ngx_http_write_filter_init, /* init module */ - NULL /* init process */ -}; - - -ngx_int_t ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) -{ - off_t size, sent; - ngx_uint_t last, flush; - ngx_chain_t *cl, *ln, **ll, *chain; - ngx_connection_t *c; - ngx_http_core_loc_conf_t *clcf; - ngx_http_write_filter_ctx_t *ctx; - - ctx = ngx_http_get_module_ctx(r->main ? r->main : r, - ngx_http_write_filter_module); - - if (ctx == NULL) { - ngx_http_create_ctx(r, ctx, ngx_http_write_filter_module, - sizeof(ngx_http_write_filter_ctx_t), NGX_ERROR); - } - - size = 0; - flush = 0; - last = 0; - ll = &ctx->out; - - /* find the size, the flush point and the last link of the saved chain */ - - for (cl = ctx->out; cl; cl = cl->next) { - ll = &cl->next; - - ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, - "write old buf t:%d f:%d %p, pos %p, size: %z " - "file: %O, size: %z", - cl->buf->temporary, cl->buf->in_file, - cl->buf->start, cl->buf->pos, - cl->buf->last - cl->buf->pos, - cl->buf->file_pos, - cl->buf->file_last - cl->buf->file_pos); - -#if 1 - if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - "zero size buf in writer " - "t:%d r:%d f:%d %p %p-%p %p %O-%O", - cl->buf->temporary, - cl->buf->recycled, - cl->buf->in_file, - cl->buf->start, - cl->buf->pos, - cl->buf->last, - cl->buf->file, - cl->buf->file_pos, - cl->buf->file_last); - - ngx_debug_point(); - return NGX_ERROR; - } -#endif - - size += ngx_buf_size(cl->buf); - - if (cl->buf->flush || cl->buf->recycled) { - flush = 1; - } - - if (cl->buf->last_buf) { - last = 1; - } - } - - /* add the new chain to the existent one */ - - for (ln = in; ln; ln = ln->next) { - if (!(cl = ngx_alloc_chain_link(r->pool))) { - return NGX_ERROR; - } - - cl->buf = ln->buf; - *ll = cl; - ll = &cl->next; - - ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, - "write new buf t:%d f:%d %p, pos %p, size: %z " - "file: %O, size: %z", - cl->buf->temporary, cl->buf->in_file, - cl->buf->start, cl->buf->pos, - cl->buf->last - cl->buf->pos, - cl->buf->file_pos, - cl->buf->file_last - cl->buf->file_pos); - -#if 1 - if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - "zero size buf in writer " - "t:%d r:%d f:%d %p %p-%p %p %O-%O", - cl->buf->temporary, - cl->buf->recycled, - cl->buf->in_file, - cl->buf->start, - cl->buf->pos, - cl->buf->last, - cl->buf->file, - cl->buf->file_pos, - cl->buf->file_last); - - ngx_debug_point(); - return NGX_ERROR; - } -#endif - - size += ngx_buf_size(cl->buf); - - if (cl->buf->flush || cl->buf->recycled) { - flush = 1; - } - - if (cl->buf->last_buf) { - last = 1; - } - } - - *ll = NULL; - - c = r->connection; - - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http write filter: l:%d f:%d s:%O", last, flush, size); - - clcf = ngx_http_get_module_loc_conf(r->main ? r->main : r, - ngx_http_core_module); - - /* - * avoid the output if there is no last buf, no flush point, - * there are the incoming bufs and the size of all bufs - * is smaller than "postpone_output" directive - */ - - if (!last && !flush && in && size < (off_t) clcf->postpone_output) { - return NGX_OK; - } - - if (c->write->delayed) { - return NGX_AGAIN; - } - - if (size == 0 && !c->buffered) { - if (last) { - return NGX_OK; - } - - if (flush) { - while ((ctx->out = ctx->out->next)) { /* void */ } - return NGX_OK; - } - - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - "the http output chain is empty"); - - ngx_debug_point(); - - return NGX_ERROR; - } - - sent = c->sent; - - chain = c->send_chain(c, ctx->out, clcf->limit_rate); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http write filter %p", chain); - - if (clcf->limit_rate) { - sent = c->sent - sent; - c->write->delayed = 1; - ngx_add_timer(r->connection->write, - (ngx_msec_t) (sent * 1000 / clcf->limit_rate)); - } - - if (chain == NGX_CHAIN_ERROR) { - return NGX_ERROR; - } - - ctx->out = chain; - - if (chain || (last && c->buffered)) { - return NGX_AGAIN; - } - - return NGX_OK; -} - - -static ngx_int_t ngx_http_write_filter_init(ngx_cycle_t *cycle) -{ - ngx_http_top_body_filter = ngx_http_write_filter; - - return NGX_OK; -} diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c new file mode 100644 --- /dev/null +++ b/src/http/ngx_http_write_filter_module.c @@ -0,0 +1,250 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include +#include + + +typedef struct { + ngx_chain_t *out; +} ngx_http_write_filter_ctx_t; + + +static ngx_int_t ngx_http_write_filter_init(ngx_cycle_t *cycle); + + +ngx_http_module_t ngx_http_write_filter_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_write_filter_module = { + NGX_MODULE, + &ngx_http_write_filter_module_ctx, /* module context */ + NULL, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + ngx_http_write_filter_init, /* init module */ + NULL /* init process */ +}; + + +ngx_int_t +ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) +{ + off_t size, sent; + ngx_uint_t last, flush; + ngx_chain_t *cl, *ln, **ll, *chain; + ngx_connection_t *c; + ngx_http_core_loc_conf_t *clcf; + ngx_http_write_filter_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r->main ? r->main : r, + ngx_http_write_filter_module); + + if (ctx == NULL) { + + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_write_filter_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_http_set_ctx(r, ctx, ngx_http_write_filter_module); + } + + size = 0; + flush = 0; + last = 0; + ll = &ctx->out; + + /* find the size, the flush point and the last link of the saved chain */ + + for (cl = ctx->out; cl; cl = cl->next) { + ll = &cl->next; + + ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, + "write old buf t:%d f:%d %p, pos %p, size: %z " + "file: %O, size: %z", + cl->buf->temporary, cl->buf->in_file, + cl->buf->start, cl->buf->pos, + cl->buf->last - cl->buf->pos, + cl->buf->file_pos, + cl->buf->file_last - cl->buf->file_pos); + +#if 1 + if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "zero size buf in writer " + "t:%d r:%d f:%d %p %p-%p %p %O-%O", + cl->buf->temporary, + cl->buf->recycled, + cl->buf->in_file, + cl->buf->start, + cl->buf->pos, + cl->buf->last, + cl->buf->file, + cl->buf->file_pos, + cl->buf->file_last); + + ngx_debug_point(); + return NGX_ERROR; + } +#endif + + size += ngx_buf_size(cl->buf); + + if (cl->buf->flush || cl->buf->recycled) { + flush = 1; + } + + if (cl->buf->last_buf) { + last = 1; + } + } + + /* add the new chain to the existent one */ + + for (ln = in; ln; ln = ln->next) { + cl = ngx_alloc_chain_link(r->pool); + if (cl == NULL) { + return NGX_ERROR; + } + + cl->buf = ln->buf; + *ll = cl; + ll = &cl->next; + + ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, + "write new buf t:%d f:%d %p, pos %p, size: %z " + "file: %O, size: %z", + cl->buf->temporary, cl->buf->in_file, + cl->buf->start, cl->buf->pos, + cl->buf->last - cl->buf->pos, + cl->buf->file_pos, + cl->buf->file_last - cl->buf->file_pos); + +#if 1 + if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "zero size buf in writer " + "t:%d r:%d f:%d %p %p-%p %p %O-%O", + cl->buf->temporary, + cl->buf->recycled, + cl->buf->in_file, + cl->buf->start, + cl->buf->pos, + cl->buf->last, + cl->buf->file, + cl->buf->file_pos, + cl->buf->file_last); + + ngx_debug_point(); + return NGX_ERROR; + } +#endif + + size += ngx_buf_size(cl->buf); + + if (cl->buf->flush || cl->buf->recycled) { + flush = 1; + } + + if (cl->buf->last_buf) { + last = 1; + } + } + + *ll = NULL; + + c = r->connection; + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http write filter: l:%d f:%d s:%O", last, flush, size); + + clcf = ngx_http_get_module_loc_conf(r->main ? r->main : r, + ngx_http_core_module); + + /* + * avoid the output if there is no last buf, no flush point, + * there are the incoming bufs and the size of all bufs + * is smaller than "postpone_output" directive + */ + + if (!last && !flush && in && size < (off_t) clcf->postpone_output) { + return NGX_OK; + } + + if (c->write->delayed) { + return NGX_AGAIN; + } + + if (size == 0 && !c->buffered) { + if (last) { + return NGX_OK; + } + + if (flush) { + do { + ctx->out = ctx->out->next; + } + while (ctx->out); + + return NGX_OK; + } + + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "the http output chain is empty"); + + ngx_debug_point(); + + return NGX_ERROR; + } + + sent = c->sent; + + chain = c->send_chain(c, ctx->out, clcf->limit_rate); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http write filter %p", chain); + + if (clcf->limit_rate) { + sent = c->sent - sent; + c->write->delayed = 1; + ngx_add_timer(r->connection->write, + (ngx_msec_t) (sent * 1000 / clcf->limit_rate)); + } + + if (chain == NGX_CHAIN_ERROR) { + return NGX_ERROR; + } + + ctx->out = chain; + + if (chain || (last && c->buffered)) { + return NGX_AGAIN; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_write_filter_init(ngx_cycle_t *cycle) +{ + ngx_http_top_body_filter = ngx_http_write_filter; + + return NGX_OK; +} diff --git a/src/os/unix/ngx_aio_read_chain.c b/src/os/unix/ngx_aio_read_chain.c --- a/src/os/unix/ngx_aio_read_chain.c +++ b/src/os/unix/ngx_aio_read_chain.c @@ -16,7 +16,6 @@ ssize_t ngx_aio_read_chain(ngx_connectio u_char *buf, *prev; size_t size; ssize_t total; - ngx_err_t err; if (c->read->pending_eof) { c->read->ready = 0; diff --git a/src/os/unix/ngx_aio_write_chain.c b/src/os/unix/ngx_aio_write_chain.c --- a/src/os/unix/ngx_aio_write_chain.c +++ b/src/os/unix/ngx_aio_write_chain.c @@ -17,7 +17,6 @@ ngx_chain_t *ngx_aio_write_chain(ngx_con off_t send, sent; size_t len; ssize_t n, size; - ngx_err_t err; ngx_chain_t *cl; /* the maximum limit size is the maximum size_t value - the page size */ diff --git a/src/os/unix/ngx_alloc.c b/src/os/unix/ngx_alloc.c --- a/src/os/unix/ngx_alloc.c +++ b/src/os/unix/ngx_alloc.c @@ -11,11 +11,13 @@ int ngx_pagesize; -void *ngx_alloc(size_t size, ngx_log_t *log) +void * +ngx_alloc(size_t size, ngx_log_t *log) { void *p; - if (!(p = malloc(size))) { + p = malloc(size); + if (p == NULL) { ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "malloc() %uz bytes failed", size); } @@ -26,7 +28,8 @@ void *ngx_alloc(size_t size, ngx_log_t * } -void *ngx_calloc(size_t size, ngx_log_t *log) +void * +ngx_calloc(size_t size, ngx_log_t *log) { void *p; @@ -42,7 +45,8 @@ void *ngx_calloc(size_t size, ngx_log_t #if (NGX_HAVE_POSIX_MEMALIGN) -void *ngx_memalign(size_t alignment, size_t size, ngx_log_t *log) +void * +ngx_memalign(size_t alignment, size_t size, ngx_log_t *log) { void *p; @@ -60,11 +64,13 @@ void *ngx_memalign(size_t alignment, siz #elif (NGX_HAVE_MEMALIGN) -void *ngx_memalign(size_t alignment, size_t size, ngx_log_t *log) +void * +ngx_memalign(size_t alignment, size_t size, ngx_log_t *log) { void *p; - if (!(p = memalign(alignment, size))) { + p = memalign(alignment, size); + if (p == NULL) { ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "memalign() %uz bytes aligned to %uz failed", size, alignment); diff --git a/src/os/unix/ngx_errno.c b/src/os/unix/ngx_errno.c --- a/src/os/unix/ngx_errno.c +++ b/src/os/unix/ngx_errno.c @@ -34,8 +34,7 @@ u_char *ngx_strerror_r(int err, u_char * u_char *ngx_strerror_r(int err, u_char *errstr, size_t size) { - char *str; - size_t len; + char *str; if (size == 0) { return 0; 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 @@ -25,7 +25,7 @@ typedef int ngx_err_t; #define NGX_ENOTDIR ENOTDIR #define NGX_EINVAL EINVAL #define NGX_EPIPE EPIPE -#define NGX_EAGAIN EWOULDBLOCK +#define NGX_EAGAIN EAGAIN #define NGX_EINPROGRESS EINPROGRESS #define NGX_EADDRINUSE EADDRINUSE #define NGX_ECONNABORTED ECONNABORTED @@ -52,10 +52,10 @@ u_char *ngx_strerror_r(int err, u_char * #else -/* Solaris has threads-safe strerror() */ +/* Solaris has thread-safe strerror() */ #define ngx_strerror_r(err, errstr, size) \ - ngx_cpystrn(errstr, (u_char *) strerror(err), size) + ngx_cpystrn(errstr, (u_char *) strerror(err), size) #endif 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 @@ -131,7 +131,6 @@ ssize_t ngx_write_chain_to_file(ngx_file u_char *prev; size_t size; ssize_t n; - ngx_err_t err; ngx_array_t vec; struct iovec *iov, iovs[NGX_IOVS]; @@ -162,7 +161,8 @@ ssize_t ngx_write_chain_to_file(ngx_file iov->iov_len += cl->buf->last - cl->buf->pos; } else { - if (!(iov = ngx_array_push(&vec))) { + iov = ngx_array_push(&vec); + if (iov == NULL) { return NGX_ERROR; } diff --git a/src/os/unix/ngx_freebsd_init.c b/src/os/unix/ngx_freebsd_init.c --- a/src/os/unix/ngx_freebsd_init.c +++ b/src/os/unix/ngx_freebsd_init.c @@ -14,6 +14,7 @@ char ngx_freebsd_kern_osrelease[128]; int ngx_freebsd_kern_osreldate; int ngx_freebsd_hw_ncpu; int ngx_freebsd_net_inet_tcp_sendspace; +int ngx_freebsd_kern_ipc_somaxconn; /* FreeBSD 4.9 */ int ngx_freebsd_machdep_hlt_logical_cpus; @@ -61,6 +62,10 @@ sysctl_t sysctls[] = { &ngx_freebsd_net_inet_tcp_sendspace, sizeof(int), 0 }, + { "kern.ipc.somaxconn", + &ngx_freebsd_kern_ipc_somaxconn, + sizeof(int), 0 }, + { "kern.ipc.zero_copy.send", &ngx_freebsd_kern_ipc_zero_copy_send, sizeof(int), 0 }, @@ -85,7 +90,7 @@ void ngx_debug_init() ngx_int_t ngx_os_init(ngx_log_t *log) { - int version; + int version, somaxconn; size_t size; ngx_err_t err; ngx_uint_t i; @@ -203,6 +208,18 @@ ngx_int_t ngx_os_init(ngx_log_t *log) ngx_ncpu = ngx_freebsd_hw_ncpu; } + if (version < 600008) { + somaxconn = 32767; + } else { + somaxconn = 65535; + } + + if (ngx_freebsd_kern_ipc_somaxconn > somaxconn) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "sysctl kern.ipc.somaxconn must be no more than %d", + somaxconn); + return NGX_ERROR; + } ngx_tcp_nodelay_and_tcp_nopush = 1; diff --git a/src/os/unix/ngx_freebsd_rfork_thread.c b/src/os/unix/ngx_freebsd_rfork_thread.c --- a/src/os/unix/ngx_freebsd_rfork_thread.c +++ b/src/os/unix/ngx_freebsd_rfork_thread.c @@ -227,13 +227,15 @@ ngx_int_t ngx_init_threads(int n, size_t /* create the thread errno' array */ - if (!(errnos = ngx_calloc(n * sizeof(int), cycle->log))) { + errnos = ngx_calloc(n * sizeof(int), cycle->log); + if (errnos == NULL) { return NGX_ERROR; } /* create the thread tids array */ - if (!(tids = ngx_calloc((n + 1) * sizeof(ngx_tid_t), cycle->log))) { + tids = ngx_calloc((n + 1) * sizeof(ngx_tid_t), cycle->log); + if (tids == NULL) { return NGX_ERROR; } @@ -264,8 +266,7 @@ ngx_int_t ngx_init_threads(int n, size_t ngx_tid_t ngx_thread_self() { - int tid; - ngx_tid_t pid; + ngx_int_t tid; tid = ngx_gettid(); @@ -305,7 +306,8 @@ ngx_mutex_t *ngx_mutex_init(ngx_log_t *l ngx_mutex_t *m; union semun op; - if (!(m = ngx_alloc(sizeof(ngx_mutex_t), log))) { + m = ngx_alloc(sizeof(ngx_mutex_t), log); + if (m == NULL) { return NULL; } @@ -353,7 +355,7 @@ void ngx_mutex_destroy(ngx_mutex_t *m) ngx_int_t ngx_mutex_dolock(ngx_mutex_t *m, ngx_int_t try) { - uint32_t lock, new, old; + uint32_t lock, old; ngx_uint_t tries; struct sembuf op; @@ -483,7 +485,7 @@ ngx_int_t ngx_mutex_dolock(ngx_mutex_t * ngx_int_t ngx_mutex_unlock(ngx_mutex_t *m) { - uint32_t lock, new, old; + uint32_t lock, old; struct sembuf op; if (!ngx_threaded) { @@ -576,7 +578,8 @@ ngx_cond_t *ngx_cond_init(ngx_log_t *log { ngx_cond_t *cv; - if (!(cv = ngx_alloc(sizeof(ngx_cond_t), log))) { + cv = ngx_alloc(sizeof(ngx_cond_t), log); + if (cv == NULL) { return NULL; } diff --git a/src/os/unix/ngx_freebsd_rfork_thread.h b/src/os/unix/ngx_freebsd_rfork_thread.h --- a/src/os/unix/ngx_freebsd_rfork_thread.h +++ b/src/os/unix/ngx_freebsd_rfork_thread.h @@ -56,7 +56,7 @@ extern char *ngx_freebsd_kern_usrstac extern size_t ngx_thread_stack_size; -static inline int ngx_gettid() +static ngx_inline ngx_int_t ngx_gettid() { char *sp; diff --git a/src/os/unix/ngx_freebsd_sendfile_chain.c b/src/os/unix/ngx_freebsd_sendfile_chain.c --- a/src/os/unix/ngx_freebsd_sendfile_chain.c +++ b/src/os/unix/ngx_freebsd_sendfile_chain.c @@ -21,19 +21,19 @@ * to postpone the sending - it not only sends a header and the first part of * the file in one packet, but also sends the file pages in the full packets. * - * But until FreeBSD 4.5 the turning TCP_NOPUSH off does not flush a pending - * data that less than MSS so that data may be sent with 5 second delay. - * So we do not use TCP_NOPUSH on FreeBSD prior to 4.5 although it can be used + * But until FreeBSD 4.5 turning TCP_NOPUSH off does not flush a pending + * data that less than MSS, so that data may be sent with 5 second delay. + * So we do not use TCP_NOPUSH on FreeBSD prior to 4.5, although it can be used * for non-keepalive HTTP connections. */ #define NGX_HEADERS 8 -#define NGX_TRAILERS 4 +#define NGX_TRAILERS 8 -ngx_chain_t *ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, - off_t limit) +ngx_chain_t * +ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) { int rc; u_char *prev; @@ -123,7 +123,8 @@ ngx_chain_t *ngx_freebsd_sendfile_chain( iov->iov_len += (size_t) size; } else { - if (!(iov = ngx_array_push(&header))) { + iov = ngx_array_push(&header); + if (iov == NULL) { return NGX_CHAIN_ERROR; } @@ -197,7 +198,8 @@ ngx_chain_t *ngx_freebsd_sendfile_chain( iov->iov_len += (size_t) size; } else { - if (!(iov = ngx_array_push(&trailer))) { + iov = ngx_array_push(&trailer); + if (iov == NULL) { return NGX_CHAIN_ERROR; } diff --git a/src/os/unix/ngx_linux_sendfile_chain.c b/src/os/unix/ngx_linux_sendfile_chain.c --- a/src/os/unix/ngx_linux_sendfile_chain.c +++ b/src/os/unix/ngx_linux_sendfile_chain.c @@ -121,7 +121,8 @@ ngx_chain_t *ngx_linux_sendfile_chain(ng iov->iov_len += (size_t) size; } else { - if (!(iov = ngx_array_push(&header))) { + iov = ngx_array_push(&header); + if (iov == NULL) { return NGX_CHAIN_ERROR; } diff --git a/src/os/unix/ngx_posix_init.c b/src/os/unix/ngx_posix_init.c --- a/src/os/unix/ngx_posix_init.c +++ b/src/os/unix/ngx_posix_init.c @@ -182,7 +182,7 @@ void ngx_signal_handler(int signo) case ngx_signal_value(NGX_NOACCEPT_SIGNAL): ngx_noaccept = 1; - action = ", stop the accepting connections"; + action = ", stop accepting connections"; break; case ngx_signal_value(NGX_RECONFIGURE_SIGNAL): diff --git a/src/os/unix/ngx_process.c b/src/os/unix/ngx_process.c --- a/src/os/unix/ngx_process.c +++ b/src/os/unix/ngx_process.c @@ -214,7 +214,6 @@ void ngx_process_get_status() ngx_err_t err; ngx_int_t i; ngx_uint_t one; - struct timeval tv; one = 0; 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 @@ -11,7 +11,7 @@ static void ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, - ngx_int_t type); + ngx_int_t type); static void ngx_start_garbage_collector(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_childs(ngx_cycle_t *cycle); @@ -23,7 +23,9 @@ static void ngx_channel_handler(ngx_even static void ngx_wakeup_worker_threads(ngx_cycle_t *cycle); static void *ngx_worker_thread_cycle(void *data); #endif +#if 0 static void ngx_garbage_collector_cycle(ngx_cycle_t *cycle, void *data); +#endif ngx_uint_t ngx_process; @@ -59,7 +61,8 @@ ngx_int_t ngx_threads_n; u_char master_process[] = "master process"; -void ngx_master_process_cycle(ngx_cycle_t *cycle) +void +ngx_master_process_cycle(ngx_cycle_t *cycle) { char *title; u_char *p; @@ -254,7 +257,8 @@ void ngx_master_process_cycle(ngx_cycle_ } -void ngx_single_process_cycle(ngx_cycle_t *cycle) +void +ngx_single_process_cycle(ngx_cycle_t *cycle) { ngx_uint_t i; @@ -300,8 +304,8 @@ void ngx_single_process_cycle(ngx_cycle_ } -static void ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, - ngx_int_t type) +static void +ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type) { ngx_int_t i; ngx_channel_t ch; @@ -359,12 +363,12 @@ static void ngx_start_worker_processes(n } -static void ngx_start_garbage_collector(ngx_cycle_t *cycle, ngx_int_t type) +static void +ngx_start_garbage_collector(ngx_cycle_t *cycle, ngx_int_t type) { - ngx_int_t i; - ngx_channel_t ch; - - return; +#if 0 + ngx_int_t i; + ngx_channel_t ch; ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start garbage collector"); @@ -397,16 +401,17 @@ static void ngx_start_garbage_collector( ngx_write_channel(ngx_processes[i].channel[0], &ch, sizeof(ngx_channel_t), cycle->log); } +#endif } -static void ngx_signal_worker_processes(ngx_cycle_t *cycle, int signo) +static void +ngx_signal_worker_processes(ngx_cycle_t *cycle, int signo) { ngx_int_t i; ngx_err_t err; ngx_channel_t ch; - switch (signo) { case ngx_signal_value(NGX_SHUTDOWN_SIGNAL): @@ -492,7 +497,8 @@ static void ngx_signal_worker_processes( } -static ngx_uint_t ngx_reap_childs(ngx_cycle_t *cycle) +static ngx_uint_t +ngx_reap_childs(ngx_cycle_t *cycle) { ngx_int_t i, n; ngx_uint_t live; @@ -619,7 +625,8 @@ static ngx_uint_t ngx_reap_childs(ngx_cy } -static void ngx_master_exit(ngx_cycle_t *cycle) +static void +ngx_master_exit(ngx_cycle_t *cycle) { ngx_delete_pidfile(cycle); @@ -631,11 +638,14 @@ static void ngx_master_exit(ngx_cycle_t } -static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data) +static void +ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data) { +#if (NGX_THREADS) ngx_int_t n; ngx_err_t err; ngx_core_conf_t *ccf; +#endif ngx_worker_process_init(cycle, 1); @@ -668,7 +678,9 @@ static void ngx_worker_process_cycle(ngx for (n = 0; n < ngx_threads_n; n++) { - if (!(ngx_threads[n].cv = ngx_cond_init(cycle->log))) { + ngx_threads[n].cv = ngx_cond_init(cycle->log); + + if (ngx_threads[n].cv == NULL) { /* fatal */ exit(2); } @@ -748,7 +760,8 @@ static void ngx_worker_process_cycle(ngx } -static void ngx_worker_process_init(ngx_cycle_t *cycle, ngx_uint_t priority) +static void +ngx_worker_process_init(ngx_cycle_t *cycle, ngx_uint_t priority) { sigset_t set; ngx_int_t n; @@ -873,7 +886,8 @@ static void ngx_worker_process_init(ngx_ } -static void ngx_channel_handler(ngx_event_t *ev) +static void +ngx_channel_handler(ngx_event_t *ev) { ngx_int_t n; ngx_channel_t ch; @@ -952,7 +966,8 @@ static void ngx_channel_handler(ngx_even #if (NGX_THREADS) -static void ngx_wakeup_worker_threads(ngx_cycle_t *cycle) +static void +ngx_wakeup_worker_threads(ngx_cycle_t *cycle) { ngx_int_t i; ngx_uint_t live; @@ -994,7 +1009,8 @@ static void ngx_wakeup_worker_threads(ng } -static void *ngx_worker_thread_cycle(void *data) +static void * +ngx_worker_thread_cycle(void *data) { ngx_thread_t *thr = data; @@ -1022,7 +1038,8 @@ static void *ngx_worker_thread_cycle(voi ngx_setthrtitle("worker thread"); - if (!(tls = ngx_calloc(sizeof(ngx_core_tls_t), cycle->log))) { + tls = ngx_calloc(sizeof(ngx_core_tls_t), cycle->log); + if (tls == NULL) { return (void *) 1; } @@ -1077,7 +1094,10 @@ static void *ngx_worker_thread_cycle(voi #endif -static void ngx_garbage_collector_cycle(ngx_cycle_t *cycle, void *data) +#if 0 + +static void +ngx_garbage_collector_cycle(ngx_cycle_t *cycle, void *data) { ngx_uint_t i; ngx_gc_t ctx; @@ -1123,3 +1143,5 @@ static void ngx_garbage_collector_cycle( ngx_process_events(cycle); } } + +#endif diff --git a/src/os/unix/ngx_pthread_thread.c b/src/os/unix/ngx_pthread_thread.c --- a/src/os/unix/ngx_pthread_thread.c +++ b/src/os/unix/ngx_pthread_thread.c @@ -75,7 +75,8 @@ ngx_mutex_t *ngx_mutex_init(ngx_log_t *l int err; ngx_mutex_t *m; - if (!(m = ngx_alloc(sizeof(ngx_mutex_t), log))) { + m = ngx_alloc(sizeof(ngx_mutex_t), log); + if (m == NULL) { return NULL; } @@ -189,7 +190,8 @@ ngx_cond_t *ngx_cond_init(ngx_log_t *log int err; ngx_cond_t *cv; - if (!(cv = ngx_alloc(sizeof(ngx_cond_t), log))) { + cv = ngx_alloc(sizeof(ngx_cond_t), log); + if (cv == NULL) { return NULL; } diff --git a/src/os/unix/ngx_readv_chain.c b/src/os/unix/ngx_readv_chain.c --- a/src/os/unix/ngx_readv_chain.c +++ b/src/os/unix/ngx_readv_chain.c @@ -9,16 +9,20 @@ #include +#define NGX_IOVS 16 + + #if (NGX_HAVE_KQUEUE) -ssize_t ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain) +ssize_t +ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain) { u_char *prev; ssize_t n, size; ngx_err_t err; - ngx_array_t io; + ngx_array_t vec; ngx_event_t *rev; - struct iovec *iov; + struct iovec *iov, iovs[NGX_IOVS]; rev = c->read; @@ -53,7 +57,11 @@ ssize_t ngx_readv_chain(ngx_connection_t iov = NULL; size = 0; - ngx_init_array(io, c->pool, 10, sizeof(struct iovec), NGX_ERROR); + vec.elts = iovs; + vec.nelts = 0; + vec.size = sizeof(struct iovec); + vec.nalloc = NGX_IOVS; + vec.pool = c->pool; /* coalesce the neighbouring bufs */ @@ -62,7 +70,11 @@ ssize_t ngx_readv_chain(ngx_connection_t iov->iov_len += chain->buf->end - chain->buf->last; } else { - ngx_test_null(iov, ngx_push_array(&io), NGX_ERROR); + iov = ngx_array_push(&vec); + if (iov == NULL) { + return NGX_ERROR; + } + iov->iov_base = (void *) chain->buf->last; iov->iov_len = chain->buf->end - chain->buf->last; } @@ -73,12 +85,12 @@ ssize_t ngx_readv_chain(ngx_connection_t } ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, - "readv: %d, last:%d", io.nelts, iov->iov_len); + "readv: %d, last:%d", vec.nelts, iov->iov_len); rev = c->read; do { - n = readv(c->fd, (struct iovec *) io.elts, io.nelts); + n = readv(c->fd, (struct iovec *) vec.elts, vec.nelts); if (n >= 0) { if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { @@ -138,20 +150,25 @@ ssize_t ngx_readv_chain(ngx_connection_t #else /* ! NGX_HAVE_KQUEUE */ -ssize_t ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain) +ssize_t +ngx_readv_chain(ngx_connection_t *c, ngx_chain_t *chain) { u_char *prev; ssize_t n, size; ngx_err_t err; - ngx_array_t io; + ngx_array_t vec; ngx_event_t *rev; - struct iovec *iov; + struct iovec *iov, iovs[NGX_IOVS]; prev = NULL; iov = NULL; size = 0; - ngx_init_array(io, c->pool, 10, sizeof(struct iovec), NGX_ERROR); + vec.elts = iovs; + vec.nelts = 0; + vec.size = sizeof(struct iovec); + vec.nalloc = NGX_IOVS; + vec.pool = c->pool; /* coalesce the neighbouring bufs */ @@ -160,7 +177,11 @@ ssize_t ngx_readv_chain(ngx_connection_t iov->iov_len += chain->buf->end - chain->buf->last; } else { - ngx_test_null(iov, ngx_push_array(&io), NGX_ERROR); + iov = ngx_array_push(&vec); + if (iov == NULL) { + return NGX_ERROR; + } + iov->iov_base = chain->buf->last; iov->iov_len = chain->buf->end - chain->buf->last; } @@ -171,12 +192,12 @@ ssize_t ngx_readv_chain(ngx_connection_t } ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, - "readv: %d:%d", io.nelts, iov->iov_len); + "readv: %d:%d", vec.nelts, iov->iov_len); rev = c->read; do { - n = readv(c->fd, (struct iovec *) io.elts, io.nelts); + n = readv(c->fd, (struct iovec *) vec.elts, vec.nelts); if (n == 0) { rev->ready = 0; diff --git a/src/os/unix/ngx_setproctitle.c b/src/os/unix/ngx_setproctitle.c --- a/src/os/unix/ngx_setproctitle.c +++ b/src/os/unix/ngx_setproctitle.c @@ -43,7 +43,8 @@ ngx_init_setproctitle(ngx_log_t *log) size += ngx_strlen(environ[i]) + 1; } - if (!(p = ngx_alloc(size, log))) { + p = ngx_alloc(size, log); + if (p == NULL) { return NGX_ERROR; } diff --git a/src/os/unix/ngx_socket.c b/src/os/unix/ngx_socket.c --- a/src/os/unix/ngx_socket.c +++ b/src/os/unix/ngx_socket.c @@ -22,7 +22,8 @@ #if (NGX_HAVE_FIONBIO) -int ngx_nonblocking(ngx_socket_t s) +int +ngx_nonblocking(ngx_socket_t s) { u_long nb; @@ -32,7 +33,8 @@ int ngx_nonblocking(ngx_socket_t s) } -int ngx_blocking(ngx_socket_t s) +int +ngx_blocking(ngx_socket_t s) { u_long nb; @@ -46,7 +48,8 @@ int ngx_blocking(ngx_socket_t s) #if (NGX_FREEBSD) -int ngx_tcp_nopush(ngx_socket_t s) +int +ngx_tcp_nopush(ngx_socket_t s) { int tcp_nopush; @@ -57,7 +60,8 @@ int ngx_tcp_nopush(ngx_socket_t s) } -int ngx_tcp_push(ngx_socket_t s) +int +ngx_tcp_push(ngx_socket_t s) { int tcp_nopush; @@ -69,7 +73,8 @@ int ngx_tcp_push(ngx_socket_t s) #elif (NGX_LINUX) -int ngx_tcp_nopush(ngx_socket_t s) +int +ngx_tcp_nopush(ngx_socket_t s) { int cork; @@ -79,7 +84,8 @@ int ngx_tcp_nopush(ngx_socket_t s) (const void *) &cork, sizeof(int)); } -int ngx_tcp_push(ngx_socket_t s) +int +ngx_tcp_push(ngx_socket_t s) { int cork; @@ -91,14 +97,16 @@ int ngx_tcp_push(ngx_socket_t s) #else -int ngx_tcp_nopush(ngx_socket_t s) +int +ngx_tcp_nopush(ngx_socket_t s) { - return NGX_OK; + return 0; } -int ngx_tcp_push(ngx_socket_t s) +int +ngx_tcp_push(ngx_socket_t s) { - return NGX_OK; + return 0; } #endif diff --git a/src/os/unix/ngx_solaris_sendfilev_chain.c b/src/os/unix/ngx_solaris_sendfilev_chain.c --- a/src/os/unix/ngx_solaris_sendfilev_chain.c +++ b/src/os/unix/ngx_solaris_sendfilev_chain.c @@ -47,7 +47,7 @@ ngx_chain_t *ngx_solaris_sendfilev_chain sendfilevec_t *sfv, sfvs[NGX_SENDFILEVECS]; ngx_array_t vec; ngx_event_t *wev; - ngx_chain_t *cl, *tail; + ngx_chain_t *cl; wev = c->write; @@ -107,7 +107,8 @@ ngx_chain_t *ngx_solaris_sendfilev_chain sfv->sfv_len += (size_t) size; } else { - if (!(sfv = ngx_array_push(&vec))) { + sfv = ngx_array_push(&vec); + if (sfv == NULL) { return NGX_CHAIN_ERROR; } @@ -140,7 +141,8 @@ ngx_chain_t *ngx_solaris_sendfilev_chain sfv->sfv_len += (size_t) size; } else { - if (!(sfv = ngx_array_push(&vec))) { + sfv = ngx_array_push(&vec); + if (sfv == NULL) { return NGX_CHAIN_ERROR; } diff --git a/src/os/unix/ngx_writev_chain.c b/src/os/unix/ngx_writev_chain.c --- a/src/os/unix/ngx_writev_chain.c +++ b/src/os/unix/ngx_writev_chain.c @@ -12,7 +12,8 @@ #define NGX_IOVS 16 -ngx_chain_t *ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) +ngx_chain_t * +ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit) { u_char *prev; ssize_t n, size, sent; @@ -88,7 +89,8 @@ ngx_chain_t *ngx_writev_chain(ngx_connec iov->iov_len += size; } else { - if (!(iov = ngx_array_push(&vec))) { + iov = ngx_array_push(&vec); + if (iov == NULL) { return NGX_CHAIN_ERROR; }