# HG changeset patch # User Igor Sysoev # Date 1133730000 -10800 # Node ID 91372f004adf35e1bd72ba5d730e185ef4cd6890 # Parent add6b1e86d3849ec107e3514c4dcabe76b6442a6 nginx 0.3.13 *) Feature: the IMAP/POP3 proxy supports STARTTLS and STLS. *) Bugfix: the IMAP/POP3 proxy did not work with the select, poll, and /dev/poll methods. *) Bugfix: in SSI handling. *) Bugfix: now Solaris sendfilev() is not used to transfer the client request body to FastCGI-server via the unix domain socket. *) Bugfix: the "auth_basic" directive did not disable the authorization; bug appeared in 0.3.11. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,19 @@ + +Changes with nginx 0.3.13 05 Dec 2005 + + *) Feature: the IMAP/POP3 proxy supports STARTTLS and STLS. + + *) Bugfix: the IMAP/POP3 proxy did not work with the select, poll, and + /dev/poll methods. + + *) Bugfix: in SSI handling. + + *) Bugfix: now Solaris sendfilev() is not used to transfer the client + request body to FastCGI-server via the unix domain socket. + + *) Bugfix: the "auth_basic" directive did not disable the + authorization; bug appeared in 0.3.11. + Changes with nginx 0.3.12 26 Nov 2005 diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,3 +1,19 @@ + +Изменения в nginx 0.3.13 05.12.2005 + + *) Добавление: IMAP/POP3 прокси поддерживает STARTTLS и STLS. + + *) Исправление: IMAP/POP3 прокси не работала с методами select, poll и + /dev/poll. + + *) Исправление: ошибки в обработке SSI. + + *) Исправление: sendfilev() в Solaris теперь не используется при + передаче тела запроса FastCGI-серверу через unix domain сокет. + + *) Исправление: директива auth_basic не запрещала аутентификацию; + ошибка появилась в 0.3.11. + Изменения в nginx 0.3.12 26.11.2005 @@ -20,7 +36,7 @@ метода rtsig; ошибка появилась в 0.3.0. *) Исправление: если клиент передал строку "Transfer-Encoding: chunked" - в заголоовке запроса, то nginx теперь выдаёт ошибку 411. + в заголовке запроса, то nginx теперь выдаёт ошибку 411. *) Исправление: при наследовании директивы auth_basic с уровня http в строке "WWW-Authenticate" заголовка ответа выводился realm без diff --git a/auto/cc/gcc b/auto/cc/gcc --- a/auto/cc/gcc +++ b/auto/cc/gcc @@ -36,7 +36,7 @@ fi case "$NGX_MACHINE" in - sun4u | sparc ) + sun4u | sparc | sparc64 ) # "-mcpu=v9" enables the "casa" assembler instruction CFLAGS="$CFLAGS -mcpu=v9" ;; diff --git a/auto/cc/msvc b/auto/cc/msvc --- a/auto/cc/msvc +++ b/auto/cc/msvc @@ -49,6 +49,8 @@ case $CPU in ;; esac +# __cdecl, use with OpenSSL +#CPU_OPT="$CPU_OPT -Gd" # __stdcall #CPU_OPT="$CPU_OPT -Gz" # __fastcall diff --git a/auto/cc/owc b/auto/cc/owc --- a/auto/cc/owc +++ b/auto/cc/owc @@ -2,7 +2,7 @@ # Copyright (C) Igor Sysoev -# Open Watcom C 1.0, 1.2 +# Open Watcom C 1.0, 1.2, 1.3 # optimizations @@ -60,7 +60,7 @@ CFLAGS="$CFLAGS -d2" CFLAGS="$CFLAGS -zq" # Open Watcom C 1.2 -#have=NGX_HAVE_C99_VARIADIC_MACROS . auto/have +have=NGX_HAVE_C99_VARIADIC_MACROS . auto/have # the precompiled headers diff --git a/auto/endianess b/auto/endianess --- a/auto/endianess +++ b/auto/endianess @@ -20,7 +20,7 @@ int main() { END -ngx_test="$CC $CC_TEST_FLAGS $CC_WARN $CC_AUX_FLAGS \ +ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS \ -o $NGX_AUTOTEST $NGX_AUTOTEST.c $NGX_LD_OPT $ngx_feature_libs" eval "$ngx_test >> $NGX_AUTOCONF_ERR 2>&1" diff --git a/auto/feature b/auto/feature --- a/auto/feature +++ b/auto/feature @@ -31,7 +31,7 @@ int main() { END -ngx_test="$CC $CC_TEST_FLAGS $CC_WARN $CC_AUX_FLAGS \ +ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS \ -o $NGX_AUTOTEST $NGX_AUTOTEST.c $NGX_LD_OPT $ngx_feature_libs" eval "$ngx_test >> $NGX_AUTOCONF_ERR 2>&1" diff --git a/auto/fmt/fmt b/auto/fmt/fmt deleted file mode 100644 --- a/auto/fmt/fmt +++ /dev/null @@ -1,98 +0,0 @@ - -# Copyright (C) Igor Sysoev - - -echo $ngx_n "checking for $ngx_type printf() format ...$ngx_c" - -cat << END >> $NGX_AUTOCONF_ERR - ----------------------------------------- -checking for $ngx_type printf() format - -END - - -ngx_format=no -ngx_comma= - - -for ngx_fmt in $ngx_formats -do - - cat << END > $NGX_AUTOTEST.c - -#include -#include -#include -#include -$NGX_INCLUDE_INTTYPES_H -$NGX_INCLUDE_AUTO_CONFIG_H - -int main() { - printf("$ngx_fmt", ($ngx_type) $ngx_max_value); - return 0; -} - -END - - ngx_test="$CC $CC_TEST_FLAGS $CC_WARN $CC_AUX_FLAGS \ - -o $NGX_AUTOTEST $NGX_AUTOTEST.c" - eval "$ngx_test >> $NGX_AUTOCONF_ERR 2>&1" - - ngx_max_val=`echo $ngx_max_value | sed -e "s/L*\$//"` - - if [ -x $NGX_AUTOTEST ]; then - - if [ "`$NGX_AUTOTEST`" = $ngx_max_val ]; then - - if [ $ngx_fmt_collect = yes ]; then - echo $ngx_n "$ngx_comma \"${ngx_fmt}\" is appropriate$ngx_c" - else - echo $ngx_n "$ngx_comma \"${ngx_fmt}\" used$ngx_c" - fi - - ngx_format=$ngx_fmt - fi - fi - - rm -f $NGX_AUTOTEST - - if [ $ngx_format != no ]; then - if [ $ngx_fmt_collect = yes ]; then - eval "ngx_${ngx_size}_fmt=\"\${ngx_${ngx_size}_fmt} \$ngx_format\"" - ngx_comma="," - continue - else - break - fi - fi - - echo $ngx_n "$ngx_comma \"${ngx_fmt}\" is not appropriate$ngx_c" - ngx_comma="," - - echo "----------" >> $NGX_AUTOCONF_ERR - cat $NGX_AUTOTEST.c >> $NGX_AUTOCONF_ERR - echo "----------" >> $NGX_AUTOCONF_ERR - echo $ngx_test >> $NGX_AUTOCONF_ERR - echo "----------" >> $NGX_AUTOCONF_ERR -done - -echo - -if [ $ngx_format = no ]; then - echo "$0: error: printf() $ngx_type format not found" - - exit 1 -fi - - -if [ $ngx_fmt_collect = no ]; then - cat << END >> $NGX_AUTO_CONFIG_H - -#ifndef $ngx_fmt_name -#define $ngx_fmt_name "$ngx_format" -#endif - -END - -fi diff --git a/auto/fmt/ptrfmt b/auto/fmt/ptrfmt deleted file mode 100644 --- a/auto/fmt/ptrfmt +++ /dev/null @@ -1,86 +0,0 @@ - -# Copyright (C) Igor Sysoev - - -echo $ngx_n "checking for $ngx_type printf() format ...$ngx_c" - -cat << END >> $NGX_AUTOCONF_ERR - ----------------------------------------- -checking for $ngx_type printf() format - -END - - -ngx_format=no -ngx_comma= -ngx_fmt_x= - -for ngx_fmt in $ngx_formats -do - - cat << END > $NGX_AUTOTEST.c - -int main() { - printf("$ngx_fmt", ($ngx_type) $ngx_max_value); - return 0; -} - -END - - ngx_test="$CC $CC_TEST_FLAGS $CC_WARN $CC_AUX_FLAGS \ - -o $NGX_AUTOTEST $NGX_AUTOTEST.c" - eval "$ngx_test >> $NGX_AUTOCONF_ERR 2>&1" - - ngx_max_val=`echo $ngx_max_value | sed -e "s/L*\$//"` - - if [ -x $NGX_AUTOTEST ]; then - if [ "`$NGX_AUTOTEST`" = $ngx_max_val ]; then - ngx_format=$ngx_fmt - fi - fi - - rm $NGX_AUTOTEST - - if [ $ngx_format != no ]; then - break - fi - - ngx_fmt_x=`echo $ngx_fmt | sed -e "s/d/X/"` - - echo $ngx_n "$ngx_comma \"${ngx_fmt_x}\" is not appropriate$ngx_c" - ngx_comma="," - - echo "----------" >> $NGX_AUTOCONF_ERR - cat $NGX_AUTOTEST.c >> $NGX_AUTOCONF_ERR - echo "----------" >> $NGX_AUTOCONF_ERR - echo $ngx_test >> $NGX_AUTOCONF_ERR - echo "----------" >> $NGX_AUTOCONF_ERR -done - - -if [ $ngx_format = no ]; then - echo "$0: error: printf() $ngx_type format not found" - - exit 1 -fi - - -if [ $ngx_ptr_size = 4 ]; then - ngx_fmt_x="%0`expr 2 \* $ngx_ptr_size`" -else - ngx_fmt_x="%" -fi - -ngx_format=`echo $ngx_format | sed -e "s/d/X/" -e "s/^%/$ngx_fmt_x/"` - -echo "$ngx_comma \"${ngx_format}\" used" - - -cat << END >> $NGX_AUTO_CONFIG_H - -#ifndef $ngx_fmt_name -#define $ngx_fmt_name "$ngx_format" -#endif - -END diff --git a/auto/fmt/xfmt b/auto/fmt/xfmt deleted file mode 100644 --- a/auto/fmt/xfmt +++ /dev/null @@ -1,11 +0,0 @@ - -# Copyright (C) Igor Sysoev - - -cat << END | sed -e 's/d"$/x"/' >> $NGX_AUTO_CONFIG_H - -#ifndef $ngx_fmt_name -#define $ngx_fmt_name "$ngx_fmt" -#endif - -END diff --git a/auto/lib/openssl/conf b/auto/lib/openssl/conf --- a/auto/lib/openssl/conf +++ b/auto/lib/openssl/conf @@ -23,29 +23,47 @@ if [ $OPENSSL != NONE ]; then else - if [ "$NGX_PLATFORM" != win32 ]; then - OPENSSL=NO + case "$NGX_PLATFORM" in - ngx_feature="OpenSSL library" - ngx_feature_name="NGX_OPENSSL" - ngx_feature_run=no - ngx_feature_incs="#include " - ngx_feature_libs="-lssl -lcrypto" - ngx_feature_test="SSL_library_init()" - . auto/feature - - if [ $ngx_found = yes ]; then + win32) + have=NGX_OPENSSL . auto/have have=NGX_SSL . auto/have - CORE_LIBS="$CORE_LIBS $ngx_feature_libs" OPENSSL=YES - case "$NGX_SYSTEM" in - SunOS) - CORE_LIBS="$CORE_LIBS -ldl" - ;; - esac - fi + CORE_INCS="$CORE_INCS c:/openssl/include" + CORE_LIBS="$CORE_LIBS c:/openssl/ssleay32.lib" + CORE_LIBS="$CORE_LIBS c:/openssl/libeay32.lib" + + # libeay32.lib requires gdi32.lib + CORE_LIBS="$CORE_LIBS gdi32.lib" + # OpenSSL 0.8's libeay32.lib requires advapi32.lib + CORE_LIBS="$CORE_LIBS advapi32.lib" + ;; + + *) + OPENSSL=NO - fi + ngx_feature="OpenSSL library" + ngx_feature_name="NGX_OPENSSL" + ngx_feature_run=no + ngx_feature_incs="#include " + ngx_feature_libs="-lssl -lcrypto" + ngx_feature_test="SSL_library_init()" + . auto/feature + + if [ $ngx_found = yes ]; then + have=NGX_SSL . auto/have + CORE_LIBS="$CORE_LIBS $ngx_feature_libs" + OPENSSL=YES + + case "$NGX_SYSTEM" in + SunOS) + CORE_LIBS="$CORE_LIBS -ldl" + ;; + esac + fi + ;; + + esac fi diff --git a/auto/lib/openssl/make b/auto/lib/openssl/make --- a/auto/lib/openssl/make +++ b/auto/lib/openssl/make @@ -1,6 +1,7 @@ # Copyright (C) Igor Sysoev + if test -n "$OPENSSL_OPT"; then NGX_OPENSSL_CONFIG="./Configure \"$OPENSSL_OPT\"" else diff --git a/auto/os/conf b/auto/os/conf --- a/auto/os/conf +++ b/auto/os/conf @@ -63,7 +63,7 @@ case "$NGX_MACHINE" in have=NGX_HAVE_NONALIGNED . auto/have ;; - sun4u | ia64 ) + sun4u | sparc | sparc64 | ia64 ) have=NGX_ALIGNMENT value=16 . auto/define ;; diff --git a/auto/os/linux b/auto/os/linux --- a/auto/os/linux +++ b/auto/os/linux @@ -110,5 +110,5 @@ ngx_feature_run=no ngx_feature_incs="#include " ngx_feature_libs= ngx_feature_test="long mask = 0; - sched_setaffinity(0, 32, &mask)" + sched_setaffinity(0, 32, (cpu_set_t *) &mask)" . auto/feature diff --git a/auto/types/sizeof b/auto/types/sizeof --- a/auto/types/sizeof +++ b/auto/types/sizeof @@ -31,7 +31,7 @@ int main() { END -ngx_test="$CC $CC_TEST_FLAGS $CC_WARN $CC_AUX_FLAGS \ +ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS \ -o $NGX_AUTOTEST $NGX_AUTOTEST.c $NGX_LD_OPT $ngx_feature_libs" eval "$ngx_test >> $NGX_AUTOCONF_ERR 2>&1" diff --git a/auto/types/typedef b/auto/types/typedef --- a/auto/types/typedef +++ b/auto/types/typedef @@ -33,7 +33,9 @@ int main() { END - ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS -o $NGX_AUTOTEST $NGX_AUTOTEST.c" + ngx_test="$CC $CC_TEST_FLAGS $CC_AUX_FLAGS \ + -o $NGX_AUTOTEST $NGX_AUTOTEST.c $NGX_LD_OPT $ngx_feature_libs" + eval "$ngx_test >> $NGX_AUTOCONF_ERR 2>&1" if [ -x $NGX_AUTOTEST ]; then diff --git a/auto/unix b/auto/unix --- a/auto/unix +++ b/auto/unix @@ -4,10 +4,7 @@ have=NGX_HAVE_UNIX_DOMAIN . auto/have - -# STUB -CC_WARN= -ngx_fmt_collect=yes +ngx_feature_libs= # C types 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.3.12" +#define NGINX_VER "nginx/0.3.13" #define NGINX_VAR "NGINX" #define NGX_OLDPID_EXT ".oldbin" 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 @@ -182,6 +182,8 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t if (filename) { + ngx_pfree(cf->pool, cf->conf_file->buffer->start); + cf->conf_file = prev; if (ngx_close_file(fd) == NGX_FILE_ERROR) { diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -140,7 +140,8 @@ struct ngx_connection_s { unsigned single_connection:1; unsigned unexpected_eof:1; unsigned timedout:1; - unsigned closed:1; + unsigned error:1; + unsigned destroyed:1; unsigned sendfile:1; unsigned sndlowat:1; diff --git a/src/core/ngx_hash.c b/src/core/ngx_hash.c --- a/src/core/ngx_hash.c +++ b/src/core/ngx_hash.c @@ -47,6 +47,10 @@ ngx_hash_init(ngx_hash_t *hash, ngx_pool n < nelts; n++, name = (ngx_str_t *) ((char *) name + hash->bucket_size)) { + if (name->data == NULL) { + continue; + } + key = 0; for (i = 0; i < name->len; i++) { @@ -104,6 +108,10 @@ ngx_hash_init(ngx_hash_t *hash, ngx_pool n < nelts; n++, name = (ngx_str_t *) ((char *) name + hash->bucket_size)) { + if (name->data == NULL) { + continue; + } + key = 0; for (i = 0; i < name->len; i++) { @@ -135,6 +143,10 @@ ngx_hash_init(ngx_hash_t *hash, ngx_pool n < nelts; n++, name = (ngx_str_t *) ((char *) name + hash->bucket_size)) { + if (name->data == NULL) { + continue; + } + key = 0; for (i = 0; i < name->len; i++) { 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 @@ -102,7 +102,7 @@ ngx_palloc(ngx_pool_t *pool, size_t size } if ((size_t) (p->end - m) < NGX_ALIGNMENT) { - p->current = p->next; + pool->current = p->next; } if (p->next == NULL) { @@ -117,8 +117,8 @@ ngx_palloc(ngx_pool_t *pool, size_t size return NULL; } - if (p->current == NULL) { - p->current = n; + if (pool->current == NULL) { + pool->current = n; } p->next = n; diff --git a/src/core/ngx_rbtree.h b/src/core/ngx_rbtree.h --- a/src/core/ngx_rbtree.h +++ b/src/core/ngx_rbtree.h @@ -29,7 +29,7 @@ struct ngx_rbtree_node_s { typedef struct ngx_rbtree_s ngx_rbtree_t; -typedef ngx_rbtree_t *(*ngx_rbtree_insert_pt) (ngx_rbtree_node_t *root, +typedef ngx_rbtree_node_t *(*ngx_rbtree_insert_pt) (ngx_rbtree_node_t *root, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); struct ngx_rbtree_s { 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 @@ -1036,3 +1036,19 @@ done: *dst = d; *src = s; } + + +#if (NGX_MEMCPY_LIMIT) + +void * +ngx_memcpy(void *dst, void *src, size_t n) +{ + if (n > NGX_MEMCPY_LIMIT) { + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "memcpy %uz bytes", n); + ngx_debug_point(); + } + + return memcpy(dst, src, n); +} + +#endif 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 @@ -63,6 +63,13 @@ typedef struct { #define ngx_memset(buf, c, n) (void) memset(buf, c, n) +#if (NGX_MEMCPY_LIMIT) + +void *ngx_memcpy(void *dst, void *src, size_t n); +#define ngx_cpymem(dst, src, n) ((u_char *) ngx_memcpy(dst, src, n)) + (n) + +#else + /* * gcc3, msvc, and icc7 compile memcpy() to the inline "rep movs". * gcc3 compiles memcpy(d, s, 4) to the inline "mov"es. @@ -71,6 +78,8 @@ typedef struct { #define ngx_memcpy(dst, src, n) (void) memcpy(dst, src, n) #define ngx_cpymem(dst, src, n) ((u_char *) memcpy(dst, src, n)) + (n) +#endif + #if ( __INTEL_COMPILER >= 800 ) 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 @@ -276,8 +276,10 @@ static ngx_int_t ngx_kqueue_add_event(ngx_event_t *ev, int event, u_int flags) { ngx_int_t rc; +#if 0 ngx_event_t *e; ngx_connection_t *c; +#endif ev->active = 1; ev->disabled = 0; @@ -285,12 +287,11 @@ ngx_kqueue_add_event(ngx_event_t *ev, in ngx_mutex_lock(list_mutex); -#if 1 +#if 0 - if (nchanges > 0 - && ev->index < (u_int) nchanges + if (ev->index < (u_int) nchanges && ((uintptr_t) change_list[ev->index].udata & (uintptr_t) ~1) - == (uintptr_t) ev) + == (uintptr_t) ev) { if (change_list[ev->index].flags == EV_DISABLE) { @@ -346,12 +347,9 @@ ngx_kqueue_del_event(ngx_event_t *ev, in ngx_mutex_lock(list_mutex); -#if 1 - - if (nchanges > 0 - && ev->index < (u_int) nchanges + if (ev->index < (u_int) nchanges && ((uintptr_t) change_list[ev->index].udata & (uintptr_t) ~1) - == (uintptr_t) ev) + == (uintptr_t) ev) { ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, "kevent deleted: %d: ft:%d", @@ -359,7 +357,9 @@ ngx_kqueue_del_event(ngx_event_t *ev, in /* if the event is still not passed to a kernel we will not pass it */ - if (ev->index < (u_int) --nchanges) { + nchanges--; + + if (ev->index < (u_int) nchanges) { e = (ngx_event_t *) ((uintptr_t) change_list[nchanges].udata & (uintptr_t) ~1); change_list[ev->index] = change_list[nchanges]; @@ -371,8 +371,6 @@ ngx_kqueue_del_event(ngx_event_t *ev, in return NGX_OK; } -#endif - /* * when the file descriptor is closed the kqueue automatically deletes * its filters so we do not need to delete explicity the event @@ -551,7 +549,9 @@ ngx_kqueue_process_events(ngx_cycle_t *c if (event_list[i].flags & EV_ERROR) { ngx_log_error(NGX_LOG_ALERT, cycle->log, event_list[i].data, - "kevent() error on %d", event_list[i].ident); + "kevent() error on %d filter:%d flags:%04Xd", + event_list[i].ident, event_list[i].filter, + event_list[i].flags); continue; } diff --git a/src/event/ngx_event_connect.c b/src/event/ngx_event_connect.c --- a/src/event/ngx_event_connect.c +++ b/src/event/ngx_event_connect.c @@ -181,6 +181,11 @@ ngx_event_connect_peer(ngx_peer_connecti if (peer->sockaddr->sa_family != AF_INET) { c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED; c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED; + +#if (NGX_SOLARIS) + /* Solaris's sendfilev() supports AF_NCA, AF_INET, and AF_INET6 */ + c->sendfile = 0; +#endif } rev = c->read; 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 @@ -301,12 +301,12 @@ ngx_ssl_handshake(ngx_connection_t *c) *d = '\0'; - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL: %s, cipher: \"%s\"", SSL_get_version(c->ssl->connection), &buf[1]); if (SSL_session_reused(c->ssl->connection)) { - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL reused session"); } @@ -630,7 +630,7 @@ ngx_ssl_send_chain(ngx_connection_t *c, for ( ;; ) { while (in && buf->last < buf->end) { - if (in->buf->last_buf) { + if (in->buf->last_buf || in->buf->flush) { flush = 1; } @@ -645,11 +645,6 @@ ngx_ssl_send_chain(ngx_connection_t *c, size = buf->end - buf->last; } - /* - * TODO: the taking in->buf->flush into account can be - * implemented using the limit on the higher level - */ - if (send + size > limit) { size = (ssize_t) (limit - send); flush = 1; @@ -943,7 +938,7 @@ ngx_ssl_connection_error(ngx_connection_ } -void +void ngx_cdecl ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, char *fmt, ...) { u_long n; @@ -958,7 +953,13 @@ ngx_ssl_error(ngx_uint_t level, ngx_log_ p = ngx_cpystrn(p, (u_char *) " (SSL:", last - p); - while (p < last && (n = ERR_get_error())) { + while (p < last) { + + n = ERR_get_error(); + + if (n == 0) { + break; + } *p++ = ' '; diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -79,7 +79,7 @@ ssize_t ngx_ssl_recv_chain(ngx_connectio ngx_chain_t *ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit); ngx_int_t ngx_ssl_shutdown(ngx_connection_t *c); -void ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, +void ngx_cdecl ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, char *fmt, ...); void ngx_ssl_cleanup_ctx(void *data); 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 @@ -407,12 +407,15 @@ ngx_event_pipe_read_upstream(ngx_event_p static ngx_int_t ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p) { - size_t bsize; - ngx_uint_t flush; - ngx_chain_t *out, **ll, *cl; + size_t bsize; + ngx_uint_t flush; + ngx_chain_t *out, **ll, *cl; + ngx_connection_t *downstream; + + downstream = p->downstream; ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, - "pipe write downstream: %d", p->downstream->write->ready); + "pipe write downstream: %d", downstream->write->ready); for ( ;; ) { if (p->downstream_error) { @@ -452,6 +455,11 @@ ngx_event_pipe_write_to_downstream(ngx_e } if (p->output_filter(p->output_ctx, p->in) == NGX_ERROR) { + + if (downstream->destroyed) { + return NGX_ABORT; + } + p->downstream_error = 1; return ngx_event_pipe_drain_chains(p); } @@ -468,9 +476,9 @@ ngx_event_pipe_write_to_downstream(ngx_e break; } - if (p->downstream->data != p->output_ctx - || !p->downstream->write->ready - || p->downstream->write->delayed) + if (downstream->data != p->output_ctx + || !downstream->write->ready + || downstream->write->delayed) { break; } diff --git a/src/http/modules/ngx_http_auth_basic_module.c b/src/http/modules/ngx_http_auth_basic_module.c --- a/src/http/modules/ngx_http_auth_basic_module.c +++ b/src/http/modules/ngx_http_auth_basic_module.c @@ -379,6 +379,8 @@ ngx_http_auth_basic(ngx_conf_t *cf, void if (ngx_strcmp(realm->data, "off") == 0) { realm->len = 0; realm->data = (u_char *) ""; + + return NGX_CONF_OK; } len = sizeof("Basic realm=\"") - 1 + realm->len + 1; diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -1419,7 +1419,8 @@ ngx_http_fastcgi_add_variables(ngx_conf_ { ngx_http_variable_t *var; - var = ngx_http_add_variable(cf, &ngx_http_fastcgi_script_name, 0); + var = ngx_http_add_variable(cf, &ngx_http_fastcgi_script_name, + NGX_HTTP_VAR_NOHASH); if (var == NULL) { return NGX_ERROR; } 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 @@ -130,18 +130,14 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_c var->handler = ngx_http_geo_variable; var->data = (uintptr_t) tree; - /* - * create the temporary pool of a huge initial size - * to process quickly a large number of geo lines - */ - - pool = ngx_create_pool(512 * 1024, cf->log); + pool = ngx_create_pool(16384, cf->log); if (pool == NULL) { return NGX_CONF_ERROR; } if (ngx_array_init(&geo.values, pool, 512, - sizeof(ngx_http_variable_value_t *)) == NGX_ERROR) + sizeof(ngx_http_variable_value_t *)) + == NGX_ERROR) { ngx_destroy_pool(pool); return NGX_CONF_ERROR; diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c --- a/src/http/modules/ngx_http_gzip_filter_module.c +++ b/src/http/modules/ngx_http_gzip_filter_module.c @@ -961,7 +961,7 @@ ngx_http_gzip_add_variables(ngx_conf_t * ngx_http_variable_t *var; ngx_http_log_op_name_t *op; - var = ngx_http_add_variable(cf, &ngx_http_gzip_ratio, 0); + var = ngx_http_add_variable(cf, &ngx_http_gzip_ratio, NGX_HTTP_VAR_NOHASH); if (var == NULL) { return NGX_ERROR; } diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -359,20 +359,20 @@ static ngx_table_elt_t ngx_http_proxy_h static ngx_http_variable_t ngx_http_proxy_vars[] = { { ngx_string("proxy_host"), ngx_http_proxy_host_variable, 0, - NGX_HTTP_VAR_CHANGABLE, 0 }, + NGX_HTTP_VAR_CHANGABLE|NGX_HTTP_VAR_NOHASH, 0 }, { ngx_string("proxy_port"), ngx_http_proxy_port_variable, 0, - NGX_HTTP_VAR_CHANGABLE, 0 }, + NGX_HTTP_VAR_CHANGABLE|NGX_HTTP_VAR_NOHASH, 0 }, { ngx_string("proxy_add_x_forwarded_for"), - ngx_http_proxy_add_x_forwarded_for_variable, 0, 0, 0 }, + ngx_http_proxy_add_x_forwarded_for_variable, 0, NGX_HTTP_VAR_NOHASH, 0 }, #if 0 - { ngx_string("proxy_add_via"), NULL, 0, 0, 0 }, + { ngx_string("proxy_add_via"), NULL, 0, NGX_HTTP_VAR_NOHASH, 0 }, #endif { ngx_string("proxy_internal_body_length"), - ngx_http_proxy_internal_body_length_variable, 0, 0, 0 }, + ngx_http_proxy_internal_body_length_variable, 0, NGX_HTTP_VAR_NOHASH, 0 }, { ngx_null_string, NULL, 0, 0, 0 } }; diff --git a/src/http/modules/ngx_http_referer_module.c b/src/http/modules/ngx_http_referer_module.c --- a/src/http/modules/ngx_http_referer_module.c +++ b/src/http/modules/ngx_http_referer_module.c @@ -217,7 +217,8 @@ ngx_http_valid_referers(ngx_conf_t *cf, name.len = sizeof("invalid_referer") - 1; name.data = (u_char *) "invalid_referer"; - var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGABLE); + var = ngx_http_add_variable(cf, &name, + NGX_HTTP_VAR_CHANGABLE|NGX_HTTP_VAR_NOHASH); if (var == NULL) { return NGX_CONF_ERROR; } diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -648,13 +648,17 @@ ngx_http_ssi_body_filter(ngx_http_reques rc = cmd->handler(r, ctx, params); - if (c->closed) { + if (c->destroyed) { return NGX_DONE; } if (rc == NGX_OK) { continue; } + + if (rc == NGX_ERROR) { + return NGX_ERROR; + } } diff --git a/src/http/modules/ngx_http_static_module.c b/src/http/modules/ngx_http_static_module.c --- a/src/http/modules/ngx_http_static_module.c +++ b/src/http/modules/ngx_http_static_module.c @@ -244,6 +244,12 @@ ngx_http_static_handler(ngx_http_request return NGX_HTTP_INTERNAL_SERVER_ERROR; } + r->allow_ranges = 1; + + if (r->header_only || (r->main != r && ngx_file_size(&fi) == 0)) { + return ngx_http_send_header(r); + } + /* we need to allocate all before the header would be sent */ b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); @@ -256,11 +262,9 @@ ngx_http_static_handler(ngx_http_request return NGX_HTTP_INTERNAL_SERVER_ERROR; } - r->allow_ranges = 1; - rc = ngx_http_send_header(r); - if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { + if (rc == NGX_ERROR || rc > NGX_OK) { return rc; } diff --git a/src/http/modules/ngx_http_userid_filter_module.c b/src/http/modules/ngx_http_userid_filter_module.c --- a/src/http/modules/ngx_http_userid_filter_module.c +++ b/src/http/modules/ngx_http_userid_filter_module.c @@ -554,7 +554,7 @@ ngx_http_userid_add_variables(ngx_conf_t ngx_http_variable_t *var; ngx_http_log_op_name_t *op; - var = ngx_http_add_variable(cf, &ngx_http_userid_got, 0); + var = ngx_http_add_variable(cf, &ngx_http_userid_got, NGX_HTTP_VAR_NOHASH); if (var == NULL) { return NGX_ERROR; } @@ -562,7 +562,7 @@ ngx_http_userid_add_variables(ngx_conf_t var->handler = ngx_http_userid_variable; var->data = offsetof(ngx_http_userid_ctx_t, uid_got); - var = ngx_http_add_variable(cf, &ngx_http_userid_set, 0); + var = ngx_http_add_variable(cf, &ngx_http_userid_set, NGX_HTTP_VAR_NOHASH); if (var == NULL) { return NGX_ERROR; } diff --git a/src/http/ngx_http_copy_filter_module.c b/src/http/ngx_http_copy_filter_module.c --- a/src/http/ngx_http_copy_filter_module.c +++ b/src/http/ngx_http_copy_filter_module.c @@ -70,11 +70,15 @@ static ngx_http_output_body_filter_pt static ngx_int_t ngx_http_copy_filter(ngx_http_request_t *r, ngx_chain_t *in) { + ngx_int_t rc; + ngx_connection_t *c; ngx_output_chain_ctx_t *ctx; ngx_http_copy_filter_conf_t *conf; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "copy filter: \"%V\"", &r->uri); + c = r->connection; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "copy filter: \"%V?%V\"", &r->uri, &r->args); ctx = ngx_http_get_module_ctx(r, ngx_http_copy_filter_module); @@ -88,7 +92,7 @@ ngx_http_copy_filter(ngx_http_request_t ngx_http_set_ctx(r, ctx, ngx_http_copy_filter_module); - ctx->sendfile = r->connection->sendfile; + ctx->sendfile = c->sendfile; ctx->need_in_memory = r->main_filter_need_in_memory || r->filter_need_in_memory; ctx->need_in_temp = r->filter_need_temporary; @@ -102,9 +106,16 @@ ngx_http_copy_filter(ngx_http_request_t } - /* the request pool may be already destroyed after ngx_output_chain()*/ + rc = ngx_output_chain(ctx, in); - return ngx_output_chain(ctx, in); +#if (NGX_DEBUG) + if (!c->destroyed) { + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "copy filter: %i \"%V?%V\"", rc, &r->uri, &r->args); + } +#endif + + return rc; } 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 @@ -966,14 +966,14 @@ ngx_http_output_filter(ngx_http_request_ { ngx_int_t rc; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http output filter \"%V\"", &r->uri); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http output filter \"%V?%V\"", &r->uri, &r->args); rc = ngx_http_top_body_filter(r, in); if (rc == NGX_ERROR) { /* NGX_ERROR may be returned by any filter */ - r->connection->closed = 1; + r->connection->error = 1; } return rc; @@ -1080,6 +1080,7 @@ ngx_int_t ngx_http_subrequest(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args, ngx_uint_t flags) { + ngx_connection_t *c; ngx_http_request_t *sr; ngx_http_core_srv_conf_t *cscf; ngx_http_postponed_request_t *pr, *p; @@ -1090,7 +1091,9 @@ ngx_http_subrequest(ngx_http_request_t * } sr->signature = NGX_HTTP_MODULE; - sr->connection = r->connection; + + c = r->connection; + sr->connection = c; sr->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module); if (sr->ctx == NULL) { @@ -1128,16 +1131,13 @@ ngx_http_subrequest(ngx_http_request_t * sr->request_line = r->request_line; sr->uri = *uri; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http subrequest \"%V\"", uri); - if (args) { sr->args = *args; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http subrequest args \"%V\"", args); } + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http subrequest \"%V?%V\"", uri, &sr->args); + if (flags & NGX_HTTP_ZERO_IN_URI) { sr->zero_in_uri = 1; } @@ -1155,8 +1155,8 @@ ngx_http_subrequest(ngx_http_request_t * sr->read_event_handler = ngx_http_request_empty_handler; sr->write_event_handler = ngx_http_request_empty_handler; - if (r->connection->data == r) { - sr->connection->data = sr; + if (c->data == r) { + c->data = sr; } sr->in_addr = r->in_addr; @@ -1192,7 +1192,12 @@ ngx_http_subrequest(ngx_http_request_t * ngx_http_handler(sr); - /* the request pool may be already destroyed */ +#if (NGX_LOG_DEBUG) + if (!c->destroyed) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http subrequest done \"%V?%V\"", uri, &sr->args); + } +#endif return NGX_OK; } @@ -1204,22 +1209,19 @@ ngx_http_internal_redirect(ngx_http_requ { ngx_http_core_srv_conf_t *cscf; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "internal redirect: \"%V\"", uri); - r->uri = *uri; if (args) { r->args = *args; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "internal redirect args: \"%V\"", args); - } else { r->args.len = 0; r->args.data = NULL; } + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "internal redirect: \"%V?%V\"", uri, &r->args); + if (ngx_http_set_exten(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } diff --git a/src/http/ngx_http_postpone_filter_module.c b/src/http/ngx_http_postpone_filter_module.c --- a/src/http/ngx_http_postpone_filter_module.c +++ b/src/http/ngx_http_postpone_filter_module.c @@ -9,6 +9,8 @@ #include +static ngx_int_t + ngx_http_postpone_filter_output_postponed_request(ngx_http_request_t *r); static ngx_int_t ngx_http_postpone_filter_init(ngx_cycle_t *cycle); @@ -53,8 +55,8 @@ ngx_http_postpone_filter(ngx_http_reques ngx_chain_t *out; ngx_http_postponed_request_t *pr, **ppr; - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http postpone filter \"%V\" %p", &r->uri, in); + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http postpone filter \"%V?%V\" %p", &r->uri, &r->args, in); if (r != r->connection->data || (r->postponed && in)) { @@ -104,14 +106,25 @@ ngx_http_postpone_filter(ngx_http_reques return NGX_OK; } - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http postpone filter out \"%V\"", &r->uri); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http postpone filter out \"%V?%V\"", &r->uri, &r->args); rc = ngx_http_next_filter(r->main, out); if (rc == NGX_ERROR) { /* NGX_ERROR may be returned by any filter */ - r->connection->closed = 1; + r->connection->error = 1; + } + + if (r->postponed == NULL) { + return rc; + } + + rc = ngx_http_postpone_filter_output_postponed_request(r); + + if (rc == NGX_ERROR) { + /* NGX_ERROR may be returned by any filter */ + r->connection->error = 1; } return rc; @@ -119,6 +132,55 @@ ngx_http_postpone_filter(ngx_http_reques static ngx_int_t +ngx_http_postpone_filter_output_postponed_request(ngx_http_request_t *r) +{ + ngx_int_t rc; + ngx_http_postponed_request_t *pr; + + for ( ;; ) { + pr = r->postponed; + + if (pr == NULL) { + return NGX_OK; + } + + if (pr->request) { + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http postpone filter handle \"%V?%V\"", + &pr->request->uri, &pr->request->args); + + if (!pr->request->done) { + r->connection->data = pr->request; + return NGX_AGAIN; + } + + rc = ngx_http_postpone_filter_output_postponed_request(pr->request); + + if (rc == NGX_AGAIN || rc == NGX_ERROR) { + return rc; + } + + r->postponed = r->postponed->next; + pr = r->postponed; + } + + if (pr->out) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http postpone filter out postponed \"%V?%V\"", + &r->uri, &r->args); + + if (ngx_http_next_filter(r->main, pr->out) == NGX_ERROR) { + return NGX_ERROR; + } + } + + r->postponed = r->postponed->next; + } +} + + +static ngx_int_t ngx_http_postpone_filter_init(ngx_cycle_t *cycle) { ngx_http_next_filter = ngx_http_top_body_filter; 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 @@ -30,7 +30,6 @@ static ngx_int_t ngx_http_find_virtual_s static void ngx_http_request_handler(ngx_event_t *ev); static ngx_int_t ngx_http_set_write_handler(ngx_http_request_t *r); static void ngx_http_writer(ngx_http_request_t *r); -static ngx_int_t ngx_http_postponed_handler(ngx_http_request_t *r); static void ngx_http_block_read(ngx_http_request_t *r); static void ngx_http_read_discarded_body_handler(ngx_http_request_t *r); @@ -404,6 +403,8 @@ void ngx_http_init_request(ngx_event_t * } c->single_connection = 1; + c->destroyed = 0; + r->connection = c; r->main = r; @@ -455,7 +456,7 @@ ngx_http_ssl_handshake(ngx_event_t *rev) return; } - n = recv(c->fd, buf, 1, MSG_PEEK); + n = recv(c->fd, (char *) buf, 1, MSG_PEEK); if (n == -1 && ngx_socket_errno == NGX_EAGAIN) { return; @@ -1448,10 +1449,11 @@ ngx_http_finalize_request(ngx_http_reque return; } - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http finalize request: %d, \"%V\"", rc, &r->uri); - - if (rc == NGX_ERROR || r->connection->closed) { + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http finalize request: %d, \"%V?%V\"", + rc, &r->uri, &r->args); + + if (rc == NGX_ERROR || r->connection->error) { ngx_http_close_request(r, 0); return; } @@ -1482,8 +1484,9 @@ ngx_http_finalize_request(ngx_http_reque r->done = 1; if (r != r->connection->data) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http finalize non-active request: \"%V\"", &r->uri); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http finalize non-active request: \"%V?%V\"", + &r->uri, &r->args); return; } @@ -1491,8 +1494,8 @@ ngx_http_finalize_request(ngx_http_reque pr = r->parent; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http parent request: \"%V\"", &pr->uri); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http parent request: \"%V?%V\"", &pr->uri, &pr->args); if (rc != NGX_AGAIN) { pr->connection->data = pr; @@ -1500,8 +1503,9 @@ ngx_http_finalize_request(ngx_http_reque if (pr->postponed) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http request: \"%V\" has postponed", &pr->uri); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http request: \"%V?%V\" has postponed", + &pr->uri, &pr->args); if (rc != NGX_AGAIN && pr->postponed->request == r) { pr->postponed = pr->postponed->next; @@ -1511,13 +1515,14 @@ ngx_http_finalize_request(ngx_http_reque } } - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http request: \"%V\" still has postponed", - &pr->uri); - - if (pr->done) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http wake parent request: \"%V\"", &pr->uri); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http request: \"%V?%V\" still has postponed", + &pr->uri, &pr->args); + + if (pr->done || pr->postponed->out) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http wake parent request: \"%V?%V\"", + &pr->uri, &pr->args); pr->write_event_handler(pr); } @@ -1619,8 +1624,8 @@ ngx_http_writer(ngx_http_request_t *r) c = r->connection; wev = c->write; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, wev->log, 0, - "http writer handler: \"%V\"", &r->uri); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, wev->log, 0, + "http writer handler: \"%V?%V\"", &r->uri, &r->args); if (wev->timedout) { if (!wev->delayed) { @@ -1661,21 +1666,15 @@ ngx_http_writer(ngx_http_request_t *r) } } - if (r->postponed) { - rc = ngx_http_postponed_handler(r); - - if (rc == NGX_DONE) { - /* the request pool may be already destroyed */ - return; - } - - } else { - rc = ngx_http_output_filter(r, NULL); - + rc = ngx_http_output_filter(r, NULL); + + if (c->destroyed) { + return; } - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http writer output filter: %d, \"%V\"", rc, &r->uri); + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http writer output filter: %d, \"%V?%V\"", + rc, &r->uri, &r->args); if (rc == NGX_AGAIN) { clcf = ngx_http_get_module_loc_conf(r->main, ngx_http_core_module); @@ -1690,67 +1689,13 @@ ngx_http_writer(ngx_http_request_t *r) return; } - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, wev->log, 0, - "http writer done: \"%V\"", &r->uri); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, wev->log, 0, + "http writer done: \"%V?%V\"", &r->uri, &r->args); ngx_http_finalize_request(r, rc); } -static ngx_int_t -ngx_http_postponed_handler(ngx_http_request_t *r) -{ - ngx_int_t rc; - ngx_http_postponed_request_t *pr; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http postpone handler \"%V\"", &r->uri); - - pr = r->postponed; - - if (pr->request == NULL) { - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http postponed data \"%V\" %p", &r->uri, pr->out); - - rc = ngx_http_output_filter(r, NULL); - - if (rc == NGX_DONE) { - /* the request pool is already destroyed */ - return NGX_DONE; - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http postponed output filter: %d", rc); - - if (rc == NGX_ERROR) { - ngx_http_close_request(r, 0); - return NGX_DONE; - } - - pr = r->postponed; - - if (pr == NULL) { - - if (rc == NGX_AGAIN) { - return NGX_AGAIN; - } - - return NGX_OK; - } - } - - r = pr->request; - r->connection->data = r; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http wake child request \"%V\"", &r->uri); - - r->write_event_handler(r); - - return NGX_DONE; -} - - static void ngx_http_block_read(ngx_http_request_t *r) { @@ -1862,7 +1807,7 @@ ngx_http_read_discarded_body(ngx_http_re if (n == NGX_ERROR) { - r->connection->closed = 1; + r->connection->error = 1; /* * if a client request body is discarded then we already set @@ -2029,20 +1974,10 @@ ngx_http_set_keepalive(ngx_http_request_ rev->handler = ngx_http_keepalive_handler; - if (wev->active) { - if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { - if (ngx_del_event(wev, NGX_WRITE_EVENT, NGX_DISABLE_EVENT) - == NGX_ERROR) - { - ngx_http_close_connection(c); - return; - } - - } else if (ngx_event_flags & NGX_USE_LEVEL_EVENT) { - if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) == NGX_ERROR) { - ngx_http_close_connection(c); - return; - } + if (wev->active && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) { + if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) == NGX_ERROR) { + ngx_http_close_connection(c); + return; } } @@ -2224,20 +2159,10 @@ ngx_http_set_lingering_close(ngx_http_re wev = c->write; wev->handler = ngx_http_empty_handler; - if (wev->active) { - if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { - if (ngx_del_event(wev, NGX_WRITE_EVENT, NGX_DISABLE_EVENT) - == NGX_ERROR) - { - ngx_http_close_request(r, 0); - return; - } - - } else if (ngx_event_flags & NGX_USE_LEVEL_EVENT) { - if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) == NGX_ERROR) { - ngx_http_close_request(r, 0); - return; - } + if (wev->active && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) { + if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) == NGX_ERROR) { + ngx_http_close_request(r, 0); + return; } } @@ -2324,7 +2249,7 @@ void ngx_http_request_empty_handler(ngx_http_request_t *r) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http requets empty handler"); + "http request empty handler"); return; } @@ -2442,6 +2367,8 @@ ngx_http_request_done(ngx_http_request_t r->request_line.len = 0; + r->connection->destroyed = 1; + ngx_destroy_pool(r->pool); } @@ -2469,6 +2396,8 @@ ngx_http_close_connection(ngx_connection ngx_atomic_fetch_add(ngx_stat_active, -1); #endif + c->destroyed = 1; + pool = c->pool; ngx_close_connection(c); 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 @@ -230,7 +230,7 @@ ngx_http_do_read_client_request_body(ngx } if (n == 0 || n == NGX_ERROR) { - c->closed = 1; + c->error = 1; return NGX_HTTP_BAD_REQUEST; } 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 @@ -234,7 +234,7 @@ ngx_module_t ngx_http_upstream_module = }; -static ngx_http_log_op_name_t ngx_http_upstream_log_fmt_ops[] = { +static ngx_http_log_op_name_t ngx_http_upstream_log_fmt_ops[] = { { ngx_string("upstream_status"), 0, NULL, ngx_http_upstream_log_status_getlen, ngx_http_upstream_log_status }, @@ -248,10 +248,10 @@ static ngx_http_log_op_name_t ngx_http_u static ngx_http_variable_t ngx_http_upstream_vars[] = { { ngx_string("upstream_status"), - ngx_http_upstream_status_variable, 0, 0, 0 }, + ngx_http_upstream_status_variable, 0, NGX_HTTP_VAR_NOHASH, 0 }, { ngx_string("upstream_response_time"), - ngx_http_upstream_response_time_variable, 0, 0, 0 }, + ngx_http_upstream_response_time_variable, 0, NGX_HTTP_VAR_NOHASH, 0 }, { ngx_null_string, NULL, 0, 0, 0 } }; @@ -387,7 +387,7 @@ ngx_http_upstream_check_broken_connectio c = r->connection; u = r->upstream; - if (c->closed) { + if (c->error) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_CLIENT_CLOSED_REQUEST); return; @@ -406,7 +406,7 @@ ngx_http_upstream_check_broken_connectio } ev->eof = 1; - c->closed = 1; + c->error = 1; if (ev->kq_errno) { ev->error = 1; @@ -473,7 +473,7 @@ ngx_http_upstream_check_broken_connectio } ev->eof = 1; - c->closed = 1; + c->error = 1; if (!u->cachable && u->peer.connection) { ngx_log_error(NGX_LOG_INFO, ev->log, err, @@ -1125,12 +1125,14 @@ ngx_http_upstream_process_header(ngx_eve static void ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) { + int tcp_nodelay; ssize_t size; ngx_int_t rc; ngx_uint_t i, key; ngx_list_part_t *part; ngx_table_elt_t *h; ngx_event_pipe_t *p; + ngx_connection_t *c; ngx_pool_cleanup_t *cl; ngx_pool_cleanup_file_t *clf; ngx_http_core_loc_conf_t *clcf; @@ -1209,6 +1211,8 @@ ngx_http_upstream_send_response(ngx_http } } + c = r->connection; + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); if (u->pipe == NULL) { @@ -1231,6 +1235,23 @@ ngx_http_upstream_send_response(ngx_http return; } + if (clcf->tcp_nodelay && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay"); + + tcp_nodelay = 1; + + if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, + (const void *) &tcp_nodelay, sizeof(int)) == -1) + { + ngx_connection_error(c, ngx_socket_errno, + "setsockopt(TCP_NODELAY) failed"); + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + + c->tcp_nodelay = NGX_TCP_NODELAY_SET; + } + size = u->buffer.last - u->buffer.pos; if (size) { @@ -1241,7 +1262,7 @@ ngx_http_upstream_send_response(ngx_http return; } - ngx_http_upstream_process_non_buffered_body(r->connection->write); + ngx_http_upstream_process_non_buffered_body(c->write); } else { u->buffer.pos = u->buffer.start; @@ -1262,7 +1283,7 @@ ngx_http_upstream_send_response(ngx_http if (u->cache && u->cache->ctx.file.fd != NGX_INVALID_FILE) { if (ngx_close_file(u->cache->ctx.file.fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, + ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, ngx_close_file_n " \"%s\" failed", u->cache->ctx.file.name.data); } @@ -1292,9 +1313,9 @@ ngx_http_upstream_send_response(ngx_http p->bufs = u->conf->bufs; p->busy_size = u->conf->busy_buffers_size; p->upstream = u->peer.connection; - p->downstream = r->connection; + p->downstream = c; p->pool = r->pool; - p->log = r->connection->log; + p->log = c->log; p->cachable = u->cachable; @@ -1305,7 +1326,7 @@ ngx_http_upstream_send_response(ngx_http } p->temp_file->file.fd = NGX_INVALID_FILE; - p->temp_file->file.log = r->connection->log; + p->temp_file->file.log = c->log; p->temp_file->path = u->conf->temp_path; p->temp_file->pool = r->pool; @@ -1364,7 +1385,7 @@ ngx_http_upstream_send_response(ngx_http */ p->cyclic_temp_file = 1; - r->connection->sendfile = 0; + c->sendfile = 0; } else { p->cyclic_temp_file = 0; @@ -1394,8 +1415,9 @@ ngx_http_upstream_process_non_buffered_b size_t size; ssize_t n; ngx_buf_t *b; + ngx_int_t rc; ngx_uint_t do_write; - ngx_connection_t *c; + ngx_connection_t *c, *client; ngx_http_request_t *r; ngx_http_upstream_t *u; ngx_http_core_loc_conf_t *clcf; @@ -1426,6 +1448,7 @@ ngx_http_upstream_process_non_buffered_b r = c->data; u = r->upstream; + client = r->connection; b = &u->buffer; @@ -1438,7 +1461,13 @@ ngx_http_upstream_process_non_buffered_b if (do_write) { if (u->out_bufs || u->busy_bufs) { - if (ngx_http_output_filter(r, u->out_bufs) == NGX_ERROR) { + rc = ngx_http_output_filter(r, u->out_bufs); + + if (client->destroyed) { + return; + } + + if (rc == NGX_ERROR) { ngx_http_upstream_finalize_request(r, u, 0); return; } @@ -1490,18 +1519,20 @@ ngx_http_upstream_process_non_buffered_b break; } - if (ngx_handle_write_event(r->connection->write, clcf->send_lowat) - == NGX_ERROR) - { - ngx_http_upstream_finalize_request(r, u, 0); - return; + if (client->data == r) { + if (ngx_handle_write_event(client->write, clcf->send_lowat) + == NGX_ERROR) + { + ngx_http_upstream_finalize_request(r, u, 0); + return; + } } - if (r->connection->write->active) { - ngx_add_timer(r->connection->write, clcf->send_timeout); - - } else if (r->connection->write->timer_set) { - ngx_del_timer(r->connection->write); + if (client->write->active) { + ngx_add_timer(client->write, clcf->send_timeout); + + } else if (client->write->timer_set) { + ngx_del_timer(client->write); } if (ngx_handle_read_event(u->peer.connection->read, 0) == NGX_ERROR) { @@ -1512,8 +1543,8 @@ ngx_http_upstream_process_non_buffered_b if (u->peer.connection->read->active) { ngx_add_timer(u->peer.connection->read, u->conf->read_timeout); - } else if (r->connection->read->timer_set) { - ngx_del_timer(r->connection->read); + } else if (u->peer.connection->read->timer_set) { + ngx_del_timer(u->peer.connection->read); } } @@ -1577,13 +1608,14 @@ static void ngx_http_upstream_process_body(ngx_event_t *ev) { ngx_event_pipe_t *p; - ngx_connection_t *c; + ngx_connection_t *c, *downstream; ngx_http_request_t *r; ngx_http_upstream_t *u; c = ev->data; r = c->data; u = r->upstream; + downstream = r->connection; if (ev->write) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, @@ -1618,6 +1650,11 @@ ngx_http_upstream_process_body(ngx_event } if (ngx_event_pipe(p, ev->write) == NGX_ABORT) { + + if (downstream->destroyed) { + return; + } + ngx_http_upstream_finalize_request(r, u, 0); return; } @@ -1648,6 +1685,11 @@ ngx_http_upstream_process_body(ngx_event } if (ngx_event_pipe(p, ev->write) == NGX_ABORT) { + + if (downstream->destroyed) { + return; + } + ngx_http_upstream_finalize_request(r, u, 0); return; } @@ -1761,7 +1803,7 @@ ngx_http_upstream_next(ngx_http_request_ } } - if (r->connection->closed) { + if (r->connection->error) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_CLIENT_CLOSED_REQUEST); 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 @@ -843,6 +843,13 @@ ngx_http_variables_init_vars(ngx_conf_t "http variables: %ui", cmcf->variables.nelts); + for (n = 0; n < cmcf->all_variables.nelts; n++) { + if (av[n].flags & NGX_HTTP_VAR_NOHASH) { + av[n].name.data = NULL; + } + } + + /* init the all http variables hash */ cmcf->variables_hash.max_size = 500; 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 @@ -35,6 +35,7 @@ typedef ngx_int_t (*ngx_http_get_variabl #define NGX_HTTP_VAR_CHANGABLE 1 #define NGX_HTTP_VAR_NOCACHABLE 2 #define NGX_HTTP_VAR_INDEXED 4 +#define NGX_HTTP_VAR_NOHASH 8 struct ngx_http_variable_s { diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c --- a/src/http/ngx_http_write_filter_module.c +++ b/src/http/ngx_http_write_filter_module.c @@ -55,7 +55,7 @@ ngx_http_write_filter(ngx_http_request_t c = r->connection; - if (c->closed) { + if (c->error) { return NGX_ERROR; } @@ -220,7 +220,7 @@ ngx_http_write_filter(ngx_http_request_t } if (chain == NGX_CHAIN_ERROR) { - c->closed = 1; + c->error = 1; return NGX_ERROR; } diff --git a/src/imap/ngx_imap.h b/src/imap/ngx_imap.h --- a/src/imap/ngx_imap.h +++ b/src/imap/ngx_imap.h @@ -20,13 +20,13 @@ typedef struct { - void **main_conf; - void **srv_conf; + void **main_conf; + void **srv_conf; } ngx_imap_conf_ctx_t; typedef struct { - ngx_array_t servers; /* ngx_imap_core_srv_conf_t */ + ngx_array_t servers; /* ngx_imap_core_srv_conf_t */ } ngx_imap_core_main_conf_t; @@ -34,17 +34,20 @@ typedef struct { #define NGX_IMAP_IMAP_PROTOCOL 1 typedef struct { - ngx_msec_t timeout; + ngx_msec_t timeout; - size_t imap_client_buffer_size; + size_t imap_client_buffer_size; - ngx_uint_t protocol; + ngx_uint_t protocol; - ngx_buf_t *pop3_capability; - ngx_buf_t *imap_capability; + ngx_str_t pop3_capability; + ngx_str_t pop3_starttls_capability; + ngx_str_t imap_capability; + ngx_str_t imap_starttls_capability; + ngx_str_t imap_starttls_only_capability; - ngx_array_t pop3_capabilities; - ngx_array_t imap_capabilities; + ngx_array_t pop3_capabilities; + ngx_array_t imap_capabilities; /* server ctx */ ngx_imap_conf_ctx_t *ctx; @@ -52,11 +55,12 @@ typedef struct { typedef struct { - void *(*create_main_conf)(ngx_conf_t *cf); - char *(*init_main_conf)(ngx_conf_t *cf, void *conf); + void *(*create_main_conf)(ngx_conf_t *cf); + char *(*init_main_conf)(ngx_conf_t *cf, void *conf); - void *(*create_srv_conf)(ngx_conf_t *cf); - char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf); + void *(*create_srv_conf)(ngx_conf_t *cf); + char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, + void *conf); } ngx_imap_module_t; @@ -126,8 +130,8 @@ typedef struct { typedef struct { - ngx_str_t *client; - ngx_imap_session_t *session; + ngx_str_t *client; + ngx_imap_session_t *session; } ngx_imap_log_ctx_t; @@ -136,22 +140,24 @@ typedef struct { #define NGX_POP3_CAPA 3 #define NGX_POP3_QUIT 4 #define NGX_POP3_NOOP 5 -#define NGX_POP3_APOP 6 -#define NGX_POP3_STAT 7 -#define NGX_POP3_LIST 8 -#define NGX_POP3_RETR 9 -#define NGX_POP3_DELE 10 -#define NGX_POP3_RSET 11 -#define NGX_POP3_TOP 12 -#define NGX_POP3_UIDL 13 +#define NGX_POP3_STLS 6 +#define NGX_POP3_APOP 7 +#define NGX_POP3_STAT 8 +#define NGX_POP3_LIST 9 +#define NGX_POP3_RETR 10 +#define NGX_POP3_DELE 11 +#define NGX_POP3_RSET 12 +#define NGX_POP3_TOP 13 +#define NGX_POP3_UIDL 14 #define NGX_IMAP_LOGIN 1 #define NGX_IMAP_LOGOUT 2 #define NGX_IMAP_CAPABILITY 3 #define NGX_IMAP_NOOP 4 +#define NGX_IMAP_STARTTLS 5 -#define NGX_IMAP_NEXT 5 +#define NGX_IMAP_NEXT 6 #define NGX_IMAP_PARSE_INVALID_COMMAND 20 diff --git a/src/imap/ngx_imap_auth_http_module.c b/src/imap/ngx_imap_auth_http_module.c --- a/src/imap/ngx_imap_auth_http_module.c +++ b/src/imap/ngx_imap_auth_http_module.c @@ -727,7 +727,7 @@ ngx_imap_auth_sleep_handler(ngx_event_t ngx_imap_send(s->connection->write); - if (c->closed) { + if (c->destroyed) { return; } @@ -1181,6 +1181,8 @@ ngx_imap_auth_http(ngx_conf_t *cf, ngx_c return NGX_CONF_ERROR; } + ahcf->peers->number = 1; + ahcf->host_header = inet_upstream.host_header; ahcf->uri = inet_upstream.uri; } diff --git a/src/imap/ngx_imap_core_module.c b/src/imap/ngx_imap_core_module.c --- a/src/imap/ngx_imap_core_module.c +++ b/src/imap/ngx_imap_core_module.c @@ -181,8 +181,8 @@ ngx_imap_core_merge_srv_conf(ngx_conf_t ngx_imap_core_srv_conf_t *prev = parent; ngx_imap_core_srv_conf_t *conf = child; + u_char *p; size_t size; - ngx_buf_t *b; ngx_str_t *c, *d; ngx_uint_t i; @@ -218,22 +218,40 @@ ngx_imap_core_merge_srv_conf(ngx_conf_t size += c[i].len + sizeof(CRLF) - 1; } - b = ngx_create_temp_buf(cf->pool, size); - if (b == NULL) { + p = ngx_palloc(cf->pool, size); + if (p == NULL) { return NGX_CONF_ERROR; } - b->last = ngx_cpymem(b->last, "+OK Capability list follows" CRLF, - sizeof("+OK Capability list follows" CRLF) - 1); + conf->pop3_capability.len = size; + conf->pop3_capability.data = p; + + p = ngx_cpymem(p, "+OK Capability list follows" CRLF, + sizeof("+OK Capability list follows" CRLF) - 1); for (i = 0; i < conf->pop3_capabilities.nelts; i++) { - b->last = ngx_cpymem(b->last, c[i].data, c[i].len); - *b->last++ = CR; *b->last++ = LF; + p = ngx_cpymem(p, c[i].data, c[i].len); + *p++ = CR; *p++ = LF; } - *b->last++ = '.'; *b->last++ = CR; *b->last++ = LF; + *p++ = '.'; *p++ = CR; *p = LF; + + + size += sizeof("STLS" CRLF) - 1; - conf->pop3_capability = b; + p = ngx_palloc(cf->pool, size); + if (p == NULL) { + return NGX_CONF_ERROR; + } + + conf->pop3_starttls_capability.len = size; + conf->pop3_starttls_capability.data = p; + + p = ngx_cpymem(p, conf->pop3_capability.data, + conf->pop3_capability.len - (sizeof("." CRLF) - 1)); + + p = ngx_cpymem(p, "STLS" CRLF, sizeof("STLS" CRLF) - 1); + *p++ = '.'; *p++ = CR; *p = LF; if (conf->imap_capabilities.nelts == 0) { @@ -259,21 +277,55 @@ ngx_imap_core_merge_srv_conf(ngx_conf_t size += 1 + c[i].len; } - b = ngx_create_temp_buf(cf->pool, size); - if (b == NULL) { + p = ngx_palloc(cf->pool, size); + if (p == NULL) { + return NGX_CONF_ERROR; + } + + conf->imap_capability.len = size; + conf->imap_capability.data = p; + + p = ngx_cpymem(p, "* CAPABILITY", sizeof("* CAPABILITY") - 1); + + for (i = 0; i < conf->imap_capabilities.nelts; i++) { + *p++ = ' '; + p = ngx_cpymem(p, c[i].data, c[i].len); + } + + *p++ = CR; *p = LF; + + + size += sizeof(" STARTTLS") - 1; + + p = ngx_palloc(cf->pool, size); + if (p == NULL) { return NGX_CONF_ERROR; } - b->last = ngx_cpymem(b->last, "* CAPABILITY", sizeof("* CAPABILITY") - 1); + conf->imap_starttls_capability.len = size; + conf->imap_starttls_capability.data = p; - for (i = 0; i < conf->imap_capabilities.nelts; i++) { - *b->last++ = ' '; - b->last = ngx_cpymem(b->last, c[i].data, c[i].len); + p = ngx_cpymem(p, conf->imap_capability.data, + conf->imap_capability.len - (sizeof(CRLF) - 1)); + p = ngx_cpymem(p, " STARTTLS", sizeof(" STARTTLS") - 1); + *p++ = CR; *p = LF; + + + size += sizeof(" LOGINDISABLED") - 1; + + p = ngx_palloc(cf->pool, size); + if (p == NULL) { + return NGX_CONF_ERROR; } - *b->last++ = CR; *b->last++ = LF; + conf->imap_starttls_only_capability.len = size; + conf->imap_starttls_only_capability.data = p; - conf->imap_capability = b; + p = ngx_cpymem(p, conf->imap_starttls_capability.data, + conf->imap_starttls_capability.len - (sizeof(CRLF) - 1)); + p = ngx_cpymem(p, " LOGINDISABLED", sizeof(" LOGINDISABLED") - 1); + *p++ = CR; *p = LF; + return NGX_CONF_OK; } diff --git a/src/imap/ngx_imap_handler.c b/src/imap/ngx_imap_handler.c --- a/src/imap/ngx_imap_handler.c +++ b/src/imap/ngx_imap_handler.c @@ -16,6 +16,7 @@ static ngx_int_t ngx_imap_read_command(n static u_char *ngx_imap_log_error(ngx_log_t *log, u_char *buf, size_t len); #if (NGX_IMAP_SSL) +static void ngx_imap_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c); static void ngx_imap_ssl_handshake_handler(ngx_connection_t *c); #endif @@ -43,11 +44,10 @@ static u_char imap_invalid_command[] = void ngx_imap_init_connection(ngx_connection_t *c) { - ngx_imap_log_ctx_t *lctx; + ngx_imap_log_ctx_t *lctx; #if (NGX_IMAP_SSL) - ngx_imap_conf_ctx_t *ctx; - ngx_imap_ssl_conf_t *sslcf; - ngx_imap_core_srv_conf_t *cscf; + ngx_imap_conf_ctx_t *ctx; + ngx_imap_ssl_conf_t *sslcf; #endif ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%ui client %V connected to %V", @@ -75,23 +75,7 @@ ngx_imap_init_connection(ngx_connection_ sslcf = ngx_imap_get_module_srv_conf(ctx, ngx_imap_ssl_module); if (sslcf->enable) { - if (ngx_ssl_create_connection(&sslcf->ssl, c, 0) == NGX_ERROR) { - ngx_imap_close_connection(c); - return; - } - - if (ngx_ssl_handshake(c) == NGX_AGAIN) { - - cscf = ngx_imap_get_module_srv_conf(ctx, ngx_imap_core_module); - - ngx_add_timer(c->read, cscf->timeout); - - c->ssl->handler = ngx_imap_ssl_handshake_handler; - - return; - } - - ngx_imap_ssl_handshake_handler(c); + ngx_imap_ssl_init_connection(&sslcf->ssl, c); return; } @@ -104,15 +88,69 @@ ngx_imap_init_connection(ngx_connection_ #if (NGX_IMAP_SSL) static void +ngx_imap_starttls_handler(ngx_event_t *rev) +{ + ngx_connection_t *c; + ngx_imap_session_t *s; + ngx_imap_ssl_conf_t *sslcf; + + c = rev->data; + s = c->data; + + c->log->action = "in starttls state"; + + sslcf = ngx_imap_get_module_srv_conf(s, ngx_imap_ssl_module); + + ngx_imap_ssl_init_connection(&sslcf->ssl, c); +} + + +static void +ngx_imap_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c) +{ + ngx_imap_conf_ctx_t *ctx; + ngx_imap_core_srv_conf_t *cscf; + + if (ngx_ssl_create_connection(ssl, c, 0) == NGX_ERROR) { + ngx_imap_close_connection(c); + return; + } + + if (ngx_ssl_handshake(c) == NGX_AGAIN) { + + ctx = c->ctx; + cscf = ngx_imap_get_module_srv_conf(ctx, ngx_imap_core_module); + + ngx_add_timer(c->read, cscf->timeout); + + c->ssl->handler = ngx_imap_ssl_handshake_handler; + + return; + } + + ngx_imap_ssl_handshake_handler(c); +} + + +static void ngx_imap_ssl_handshake_handler(ngx_connection_t *c) { if (c->ssl->handshaked) { + + if (c->data) { + c->read->handler = ngx_imap_init_protocol; + c->write->handler = ngx_imap_send; + + ngx_imap_init_protocol(c->read); + + return; + } + ngx_imap_init_session(c); return; } ngx_imap_close_connection(c); - return; } #endif @@ -253,11 +291,6 @@ ngx_imap_init_protocol(ngx_event_t *rev) s = c->data; - if (ngx_array_init(&s->args, c->pool, 2, sizeof(ngx_str_t)) == NGX_ERROR) { - ngx_imap_session_internal_server_error(s); - return; - } - if (s->protocol == NGX_IMAP_POP3_PROTOCOL) { size = 128; s->imap_state = ngx_pop3_start; @@ -270,10 +303,19 @@ ngx_imap_init_protocol(ngx_event_t *rev) c->read->handler = ngx_imap_auth_state; } - s->buffer = ngx_create_temp_buf(c->pool, size); if (s->buffer == NULL) { - ngx_imap_session_internal_server_error(s); - return; + if (ngx_array_init(&s->args, c->pool, 2, sizeof(ngx_str_t)) + == NGX_ERROR) + { + ngx_imap_session_internal_server_error(s); + return; + } + + s->buffer = ngx_create_temp_buf(c->pool, size); + if (s->buffer == NULL) { + ngx_imap_session_internal_server_error(s); + return; + } } c->read->handler(rev); @@ -291,6 +333,9 @@ ngx_imap_auth_state(ngx_event_t *rev) ngx_connection_t *c; ngx_imap_session_t *s; ngx_imap_core_srv_conf_t *cscf; +#if (NGX_IMAP_SSL) + ngx_imap_ssl_conf_t *sslcf; +#endif c = rev->data; s = c->data; @@ -357,6 +402,19 @@ ngx_imap_auth_state(ngx_event_t *rev) switch (s->command) { case NGX_IMAP_LOGIN: + +#if (NGX_IMAP_SSL) + + if (c->ssl == NULL) { + sslcf = ngx_imap_get_module_srv_conf(s, ngx_imap_ssl_module); + + if (sslcf->starttls == NGX_IMAP_STARTTLS_ONLY) { + rc = NGX_IMAP_PARSE_INVALID_COMMAND; + break; + } + } +#endif + arg = s->args.elts; if (s->args.nelts == 2 && arg[0].len) { @@ -410,8 +468,28 @@ ngx_imap_auth_state(ngx_event_t *rev) case NGX_IMAP_CAPABILITY: cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module); - text = cscf->imap_capability->pos; - text_len = cscf->imap_capability->last - cscf->imap_capability->pos; + +#if (NGX_IMAP_SSL) + + if (c->ssl == NULL) { + sslcf = ngx_imap_get_module_srv_conf(s, ngx_imap_ssl_module); + + if (sslcf->starttls == NGX_IMAP_STARTTLS_ON) { + text_len = cscf->imap_starttls_capability.len; + text = cscf->imap_starttls_capability.data; + break; + } + + if (sslcf->starttls == NGX_IMAP_STARTTLS_ONLY) { + text_len = cscf->imap_starttls_only_capability.len; + text = cscf->imap_starttls_only_capability.data; + break; + } + } +#endif + + text_len = cscf->imap_capability.len; + text = cscf->imap_capability.data; break; case NGX_IMAP_LOGOUT: @@ -423,6 +501,21 @@ ngx_imap_auth_state(ngx_event_t *rev) case NGX_IMAP_NOOP: break; +#if (NGX_IMAP_SSL) + + case NGX_IMAP_STARTTLS: + if (c->ssl == NULL) { + sslcf = ngx_imap_get_module_srv_conf(s, ngx_imap_ssl_module); + if (sslcf->starttls) { + c->read->handler = ngx_imap_starttls_handler; + break; + } + } + + rc = NGX_IMAP_PARSE_INVALID_COMMAND; + break; +#endif + default: rc = NGX_IMAP_PARSE_INVALID_COMMAND; break; @@ -492,6 +585,9 @@ ngx_pop3_auth_state(ngx_event_t *rev) ngx_connection_t *c; ngx_imap_session_t *s; ngx_imap_core_srv_conf_t *cscf; +#if (NGX_IMAP_SSL) + ngx_imap_ssl_conf_t *sslcf; +#endif c = rev->data; s = c->data; @@ -554,8 +650,22 @@ ngx_pop3_auth_state(ngx_event_t *rev) case NGX_POP3_CAPA: cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module); - text = cscf->pop3_capability->pos; - size = cscf->pop3_capability->last - cscf->pop3_capability->pos; + +#if (NGX_IMAP_SSL) + + if (c->ssl == NULL) { + sslcf = ngx_imap_get_module_srv_conf(s, + ngx_imap_ssl_module); + if (sslcf->starttls) { + size = cscf->pop3_starttls_capability.len; + text = cscf->pop3_starttls_capability.data; + break; + } + } +#endif + + size = cscf->pop3_capability.len; + text = cscf->pop3_capability.data; break; case NGX_POP3_QUIT: @@ -565,6 +675,22 @@ ngx_pop3_auth_state(ngx_event_t *rev) case NGX_POP3_NOOP: break; +#if (NGX_IMAP_SSL) + + case NGX_POP3_STLS: + if (c->ssl == NULL) { + sslcf = ngx_imap_get_module_srv_conf(s, + ngx_imap_ssl_module); + if (sslcf->starttls) { + c->read->handler = ngx_imap_starttls_handler; + break; + } + } + + rc = NGX_IMAP_PARSE_INVALID_COMMAND; + break; +#endif + default: s->imap_state = ngx_pop3_start; rc = NGX_IMAP_PARSE_INVALID_COMMAND; @@ -616,8 +742,8 @@ ngx_pop3_auth_state(ngx_event_t *rev) case NGX_POP3_CAPA: cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module); - text = cscf->pop3_capability->pos; - size = cscf->pop3_capability->last - cscf->pop3_capability->pos; + size = cscf->pop3_capability.len; + text = cscf->pop3_capability.data; break; case NGX_POP3_QUIT: @@ -735,7 +861,7 @@ ngx_imap_close_connection(ngx_connection #endif - c->closed = 1; + c->destroyed = 1; pool = c->pool; diff --git a/src/imap/ngx_imap_parse.c b/src/imap/ngx_imap_parse.c --- a/src/imap/ngx_imap_parse.c +++ b/src/imap/ngx_imap_parse.c @@ -119,6 +119,25 @@ ngx_int_t ngx_imap_parse_command(ngx_ima } break; +#if (NGX_IMAP_SSL) + case 8: + if ((c[0] == 'S'|| c[0] == 's') + && (c[1] == 'T'|| c[1] == 't') + && (c[2] == 'A'|| c[2] == 'a') + && (c[3] == 'R'|| c[3] == 'r') + && (c[4] == 'T'|| c[4] == 't') + && (c[5] == 'T'|| c[5] == 't') + && (c[6] == 'L'|| c[6] == 'l') + && (c[7] == 'S'|| c[7] == 's')) + { + s->command = NGX_IMAP_STARTTLS; + + } else { + goto invalid; + } + break; +#endif + case 10: if ((c[0] == 'C'|| c[0] == 'c') && (c[1] == 'A'|| c[1] == 'a') @@ -421,7 +440,11 @@ ngx_int_t ngx_pop3_parse_command(ngx_ima } else if (c0 == 'N' && c1 == 'O' && c2 == 'O' && c3 == 'P') { s->command = NGX_POP3_NOOP; - +#if (NGX_IMAP_SSL) + } else if (c0 == 'S' && c1 == 'T' && c2 == 'L' && c3 == 'S') + { + s->command = NGX_POP3_STLS; +#endif } else { goto invalid; } diff --git a/src/imap/ngx_imap_proxy_module.c b/src/imap/ngx_imap_proxy_module.c --- a/src/imap/ngx_imap_proxy_module.c +++ b/src/imap/ngx_imap_proxy_module.c @@ -286,8 +286,6 @@ ngx_imap_proxy_imap_handler(ngx_event_t c->log->action = NULL; ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in"); - - c->log->action = "proxying"; } } @@ -405,16 +403,24 @@ ngx_imap_proxy_pop3_handler(ngx_event_t c->log->action = NULL; ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in"); - - c->log->action = "proxying"; } } static void -ngx_imap_proxy_dummy_handler(ngx_event_t *ev) +ngx_imap_proxy_dummy_handler(ngx_event_t *wev) { - ngx_log_debug0(NGX_LOG_DEBUG_IMAP, ev->log, 0, "imap proxy dummy handler"); + ngx_connection_t *c; + ngx_imap_session_t *s; + + ngx_log_debug0(NGX_LOG_DEBUG_IMAP, wev->log, 0, "imap proxy dummy handler"); + + if (ngx_handle_write_event(wev, 0) == NGX_ERROR) { + c = wev->data; + s = c->data; + + ngx_imap_proxy_close_session(s); + } } @@ -487,11 +493,11 @@ ngx_imap_proxy_read_response(ngx_imap_se static void ngx_imap_proxy_handler(ngx_event_t *ev) { - char *action; + char *action, *recv_action, *send_action; size_t size; ssize_t n; ngx_buf_t *b; - ngx_uint_t again, do_write; + ngx_uint_t do_write; ngx_connection_t *c, *src, *dst; ngx_imap_session_t *s; ngx_imap_proxy_conf_t *pcf; @@ -500,6 +506,8 @@ ngx_imap_proxy_handler(ngx_event_t *ev) s = c->data; if (ev->timedout) { + c->log->action = "proxying"; + if (c == s->connection) { ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); @@ -516,11 +524,15 @@ ngx_imap_proxy_handler(ngx_event_t *ev) if (c == s->connection) { if (ev->write) { + recv_action = "proxying and reading from upstream"; + send_action = "proxying and sending to client"; src = s->proxy->upstream.connection; dst = c; b = s->proxy->buffer; } else { + recv_action = "proxying and reading from client"; + send_action = "proxying and sending to upstream"; src = c; dst = s->proxy->upstream.connection; b = s->buffer; @@ -528,11 +540,15 @@ ngx_imap_proxy_handler(ngx_event_t *ev) } else { if (ev->write) { + recv_action = "proxying and reading from upstream"; + send_action = "proxying and sending to client"; src = s->connection; dst = c; b = s->buffer; } else { + recv_action = "proxying and reading from client"; + send_action = "proxying and sending to upstream"; src = c; dst = s->connection; b = s->proxy->buffer; @@ -545,14 +561,15 @@ ngx_imap_proxy_handler(ngx_event_t *ev) "imap proxy handler: %d, #%d > #%d", do_write, src->fd, dst->fd); - do { - again = 0; + for ( ;; ) { - if (do_write == 1) { + if (do_write) { size = b->last - b->pos; if (size && dst->write->ready) { + c->log->action = send_action; + n = dst->send(dst, b->pos, size); if (n == NGX_ERROR) { @@ -561,7 +578,6 @@ ngx_imap_proxy_handler(ngx_event_t *ev) } if (n > 0) { - again = 1; b->pos += n; if (b->pos == b->last) { @@ -569,58 +585,74 @@ ngx_imap_proxy_handler(ngx_event_t *ev) b->last = b->start; } } - - if (n == NGX_AGAIN || n < (ssize_t) size) { - if (ngx_handle_write_event(dst->write, /* TODO: LOWAT */ 0) - == NGX_ERROR) - { - ngx_imap_proxy_close_session(s); - return; - } - } } } size = b->end - b->last; if (size && src->read->ready) { + c->log->action = recv_action; + n = src->recv(src, b->last, size); - if (n == NGX_ERROR) { - ngx_imap_proxy_close_session(s); - return; - } - - if (n == 0) { - action = c->log->action; - c->log->action = NULL; - ngx_log_error(NGX_LOG_INFO, c->log, 0, "proxied session done"); - c->log->action = action; - - ngx_imap_proxy_close_session(s); - return; + if (n == NGX_AGAIN || n == 0) { + break; } if (n > 0) { - again = 1; do_write = 1; b->last += n; + + continue; } - if (n == NGX_AGAIN || n < (ssize_t) size) { - if (ngx_handle_read_event(src->read, 0) == NGX_ERROR) { - ngx_imap_proxy_close_session(s); - return; - } - } - - if (c == s->connection) { - pcf = ngx_imap_get_module_srv_conf(s, ngx_imap_proxy_module); - ngx_add_timer(c->read, pcf->timeout); + if (n == NGX_ERROR) { + src->read->eof = 1; } } - } while (again); + break; + } + + c->log->action = "proxying"; + + if ((s->connection->read->eof || s->proxy->upstream.connection->read->eof) + && s->buffer->pos == s->buffer->last + && s->proxy->buffer->pos == s->proxy->buffer->last) + { + action = c->log->action; + c->log->action = NULL; + ngx_log_error(NGX_LOG_INFO, c->log, 0, "proxied session done"); + c->log->action = action; + + ngx_imap_proxy_close_session(s); + return; + } + + if (ngx_handle_write_event(dst->write, 0) == NGX_ERROR) { + ngx_imap_proxy_close_session(s); + return; + } + + if (ngx_handle_read_event(dst->read, 0) == NGX_ERROR) { + ngx_imap_proxy_close_session(s); + return; + } + + if (ngx_handle_write_event(src->write, 0) == NGX_ERROR) { + ngx_imap_proxy_close_session(s); + return; + } + + if (ngx_handle_read_event(src->read, 0) == NGX_ERROR) { + ngx_imap_proxy_close_session(s); + return; + } + + if (c == s->connection) { + pcf = ngx_imap_get_module_srv_conf(s, ngx_imap_proxy_module); + ngx_add_timer(c->read, pcf->timeout); + } } diff --git a/src/imap/ngx_imap_ssl_module.c b/src/imap/ngx_imap_ssl_module.c --- a/src/imap/ngx_imap_ssl_module.c +++ b/src/imap/ngx_imap_ssl_module.c @@ -27,6 +27,15 @@ static char ngx_imap_ssl_openssl097[] = #endif +static ngx_conf_enum_t ngx_http_starttls_state[] = { + { ngx_string("off"), NGX_IMAP_STARTTLS_OFF }, + { ngx_string("on"), NGX_IMAP_STARTTLS_ON }, + { ngx_string("only"), NGX_IMAP_STARTTLS_ONLY }, + { ngx_null_string, 0 } +}; + + + static ngx_conf_bitmask_t ngx_imap_ssl_protocols[] = { { ngx_string("SSLv2"), NGX_SSL_SSLv2 }, { ngx_string("SSLv3"), NGX_SSL_SSLv3 }, @@ -44,6 +53,13 @@ static ngx_command_t ngx_imap_ssl_comma offsetof(ngx_imap_ssl_conf_t, enable), NULL }, + { ngx_string("starttls"), + NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_enum_slot, + NGX_IMAP_SRV_CONF_OFFSET, + offsetof(ngx_imap_ssl_conf_t, starttls), + ngx_http_starttls_state }, + { ngx_string("ssl_certificate"), NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_slot, @@ -146,6 +162,7 @@ ngx_imap_ssl_create_conf(ngx_conf_t *cf) */ scf->enable = NGX_CONF_UNSET; + scf->starttls = NGX_CONF_UNSET; scf->session_timeout = NGX_CONF_UNSET; scf->prefer_server_ciphers = NGX_CONF_UNSET; @@ -162,8 +179,9 @@ ngx_imap_ssl_merge_conf(ngx_conf_t *cf, ngx_pool_cleanup_t *cln; ngx_conf_merge_value(conf->enable, prev->enable, 0); + ngx_conf_merge_value(conf->starttls, prev->starttls, NGX_IMAP_STARTTLS_OFF); - if (conf->enable == 0) { + if (conf->enable == 0 && conf->starttls == NGX_IMAP_STARTTLS_OFF) { return NGX_CONF_OK; } diff --git a/src/imap/ngx_imap_ssl_module.h b/src/imap/ngx_imap_ssl_module.h --- a/src/imap/ngx_imap_ssl_module.h +++ b/src/imap/ngx_imap_ssl_module.h @@ -13,12 +13,18 @@ #include +#define NGX_IMAP_STARTTLS_OFF 0 +#define NGX_IMAP_STARTTLS_ON 1 +#define NGX_IMAP_STARTTLS_ONLY 2 + + typedef struct { ngx_flag_t enable; ngx_ssl_t ssl; ngx_flag_t prefer_server_ciphers; + ngx_flag_t starttls; ngx_uint_t protocols; diff --git a/src/os/unix/ngx_recv.c b/src/os/unix/ngx_recv.c --- a/src/os/unix/ngx_recv.c +++ b/src/os/unix/ngx_recv.c @@ -60,7 +60,7 @@ ssize_t ngx_unix_recv(ngx_connection_t * rev->available -= n; /* - * rev->available can be negative here because some additional + * rev->available may be negative here because some additional * bytes can be received between kevent() and recv() */