# HG changeset patch # User Igor Sysoev # Date 1241985600 -14400 # Node ID 829f9a66a65923d1765961bf1c5075869d421633 # Parent e98b980b4fe7c8f56d53de6584588147f44bd0f7 nginx 0.7.56 *) Feature: nginx/Windows supports IPv6 in a "listen" directive of the HTTP module. *) Bugfix: in ngx_http_image_filter_module. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,12 @@ +Changes with nginx 0.7.56 11 May 2009 + + *) Feature: nginx/Windows supports IPv6 in a "listen" directive of the + HTTP module. + + *) Bugfix: in ngx_http_image_filter_module. + + Changes with nginx 0.7.55 06 May 2009 *) Bugfix: the http_XXX parameters in "proxy_cache_use_stale" and @@ -7,7 +15,7 @@ Changes with nginx 0.7.55 *) Bugfix: fastcgi cache did not cache header only responses. *) Bugfix: of "select() failed (9: Bad file descriptor)" error in - nginx/Unix and "select() failed (10022: ...)" error in nginx/Windows. + nginx/Unix and "select() failed (10038: ...)" error in nginx/Windows. *) Bugfix: a segmentation fault might occur in worker process, if an "debug_connection" directive was used; the bug had appeared in diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,12 @@ +Изменения в nginx 0.7.56 11.05.2009 + + *) Добавление: nginx/Windows поддерживает IPv6 в директиве listen + модуля HTTP. + + *) Исправление: в модуле ngx_http_image_filter_module. + + Изменения в nginx 0.7.55 06.05.2009 *) Исправление: параметры http_XXX в директиве proxy_cache_use_stale и @@ -8,7 +16,7 @@ заголовка. *) Исправление: ошибки "select() failed (9: Bad file descriptor)" в - nginx/Unix и "select() failed (10022: ...)" в nginx/Windows. + nginx/Unix и "select() failed (10038: ...)" в nginx/Windows. *) Исправление: при использовании директивы debug_connection в рабочем процессе мог произойти segmentation fault; ошибка появилась в 0.7.54. diff --git a/auto/cc/msvc b/auto/cc/msvc --- a/auto/cc/msvc +++ b/auto/cc/msvc @@ -124,25 +124,14 @@ ngx_binout="-Fe" ngx_objext="obj" ngx_binext=".exe" -if [ "$BMAKE" = nmake ]; then - # MS nmake - - ngx_long_start='@<< +ngx_long_start='@<< ' - ngx_long_end='<<' - ngx_long_regex_cont=' \ +ngx_long_end='<<' +ngx_long_regex_cont=' \ ' - ngx_long_cont=' +ngx_long_cont=' ' -else - # Borland make - - ngx_long_start='@&&| - ' - ngx_long_end='|' -fi - # MSVC understand / in path #ngx_regex_dirsep='\\' #ngx_dirsep="\\" diff --git a/auto/cc/owc b/auto/cc/owc --- a/auto/cc/owc +++ b/auto/cc/owc @@ -87,3 +87,9 @@ ngx_binext=".exe" ngx_regex_dirsep='\\' ngx_dirsep="\\" + +ngx_regex_cont=' ' +ngx_long_regex_cont=' ' +ngx_cont=' ' +ngx_long_cont=' ' +ngx_tab=' ' diff --git a/auto/cc/sunc b/auto/cc/sunc --- a/auto/cc/sunc +++ b/auto/cc/sunc @@ -45,21 +45,6 @@ fi case "$NGX_MACHINE" in i86pc) - ngx_feature="PAUSE hardware capability bug" - ngx_feature_name= - ngx_feature_run=bug - ngx_feature_incs= - ngx_feature_path= - ngx_feature_libs= - ngx_feature_test='__asm ("pause")' - - . auto/feature - - if [ $ngx_found = yes ]; then - # disable [ PAUSE ] hwcap for Sun Studio 11 - CORE_LINK="$CORE_LINK -Msrc/os/unix/ngx_sunpro_x86.map" - fi - NGX_AUX=" src/os/unix/ngx_sunpro_x86.il" ;; diff --git a/auto/lib/md5/conf b/auto/lib/md5/conf --- a/auto/lib/md5/conf +++ b/auto/lib/md5/conf @@ -46,30 +46,30 @@ else if [ "$NGX_PLATFORM" != win32 ]; then - MD5=NO + MD5=NO - # Solaris 8/9 + # FreeBSD, Solaris 10 - ngx_feature="rsaref md5 library" - ngx_feature_name= - ngx_feature_run=no - ngx_feature_incs="#include " - ngx_feature_path= - ngx_feature_libs="-lmd5" - ngx_feature_test="MD5_CTX md5; MD5Init(&md5)" - . auto/feature + ngx_feature="system md library" + ngx_feature_name= + ngx_feature_run=no + ngx_feature_incs="#include " + ngx_feature_path= + ngx_feature_libs="-lmd" + ngx_feature_test="MD5_CTX md5; MD5Init(&md5)" + . auto/feature - ngx_md5_lib="system md5" + ngx_md5_lib="system md" if [ $ngx_found = no ]; then - # FreeBSD + # Solaris 8/9 - ngx_feature="rsaref md library" - ngx_feature_libs="-lmd" + ngx_feature="system md5 library" + ngx_feature_libs="-lmd5" . auto/feature - ngx_md5_lib="system md" + ngx_md5_lib="system md5" fi if [ $ngx_found = no ]; then diff --git a/auto/lib/openssl/conf b/auto/lib/openssl/conf --- a/auto/lib/openssl/conf +++ b/auto/lib/openssl/conf @@ -31,7 +31,7 @@ if [ $OPENSSL != NONE ]; then case "$NGX_SYSTEM" in SunOS|Linux) - CORE_LIBS="$CORE_LIBS -ldl" + CORE_LIBS="$CORE_LIBS $NGX_LIBDL" ;; esac @@ -72,7 +72,7 @@ else case "$NGX_SYSTEM" in SunOS) - CORE_LIBS="$CORE_LIBS -ldl" + CORE_LIBS="$CORE_LIBS $NGX_LIBDL" ;; esac fi diff --git a/auto/make b/auto/make --- a/auto/make +++ b/auto/make @@ -2,6 +2,8 @@ # Copyright (C) Igor Sysoev +echo "creating $NGX_MAKEFILE" + mkdir -p $NGX_OBJS/src/core $NGX_OBJS/src/event $NGX_OBJS/src/event/modules \ $NGX_OBJS/src/os/unix $NGX_OBJS/src/os/win32 \ $NGX_OBJS/src/http $NGX_OBJS/src/http/modules \ @@ -23,22 +25,12 @@ LINK = $LINK END + if test -n "$NGX_PERL_CFLAGS"; then echo NGX_PERL_CFLAGS = $NGX_PERL_CFLAGS >> $NGX_MAKEFILE echo NGX_PM_CFLAGS = $NGX_PM_CFLAGS >> $NGX_MAKEFILE fi -if [ "$BMAKE" = wmake ]; then - echo MAKE = wmake >> $NGX_MAKEFILE - - ngx_regex_cont=' ' - ngx_long_regex_cont=' ' - ngx_cont=' ' - ngx_long_cont=' ' - ngx_tab=' ' - -fi - # ALL_INCS, required by the addons and by OpenWatcom C precompiled headers diff --git a/auto/os/solaris b/auto/os/solaris --- a/auto/os/solaris +++ b/auto/os/solaris @@ -7,14 +7,14 @@ have=NGX_SOLARIS . auto/have_headers CORE_INCS="$UNIX_INCS" CORE_DEPS="$UNIX_DEPS $SOLARIS_DEPS" CORE_SRCS="$UNIX_SRCS $SOLARIS_SRCS " -CORE_LIBS="$CORE_LIBS -lsocket -lnsl -lrt" +CORE_LIBS="$CORE_LIBS -lsocket -lnsl" NGX_RPATH=YES # Solaris's make does not support a blank line between target and rules ngx_spacer= -CC_AUX_FLAGS="$CC_AUX_FLAGS -D_FILE_OFFSET_BITS=64 -lsocket -lnsl -lrt" +CC_AUX_FLAGS="$CC_AUX_FLAGS -D_FILE_OFFSET_BITS=64 -lsocket -lnsl" if [ $ZLIB_ASM != NO ]; then diff --git a/auto/os/win32 b/auto/os/win32 --- a/auto/os/win32 +++ b/auto/os/win32 @@ -10,6 +10,7 @@ CORE_SRCS="$WIN32_SRCS $IOCP_SRCS" OS_CONFIG="$WIN32_CONFIG" CORE_LIBS="$CORE_LIBS advapi32.lib ws2_32.lib" NGX_ICONS="$NGX_WIN32_ICONS" +SELECT_SRCS=$WIN32_SELECT_SRCS EVENT_MODULES="$EVENT_MODULES $IOCP_MODULE" EVENT_FOUND=YES @@ -19,5 +20,9 @@ if [ $EVENT_SELECT = NO ]; then EVENT_MODULES="$EVENT_MODULES $SELECT_MODULE" fi +if [ $NGX_IPV6 = YES ]; then + have=NGX_HAVE_INET6 . auto/have +fi + have=NGX_HAVE_AIO . auto/have have=NGX_HAVE_IOCP . auto/have diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -95,6 +95,7 @@ EVENT_SRCS="src/event/ngx_event.c \ SELECT_MODULE=ngx_select_module SELECT_SRCS=src/event/modules/ngx_select_module.c +WIN32_SELECT_SRCS=src/event/modules/ngx_win32_select_module.c POLL_MODULE=ngx_poll_module POLL_SRCS=src/event/modules/ngx_poll_module.c diff --git a/auto/unix b/auto/unix --- a/auto/unix +++ b/auto/unix @@ -173,6 +173,40 @@ ngx_feature_test="sched_yield()" . auto/feature +if [ $ngx_found != yes ]; then + + ngx_feature="sched_yield() in librt" + ngx_feature_libs="-lrt" + . auto/feature + + if [ $ngx_found = yes ]; then + CORE_LIBS="$CORE_LIBS -lrt" + fi +fi + + +ngx_feature="dlopen()" +ngx_feature_name= +ngx_feature_run=no +ngx_feature_incs="#include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="dlopen(NULL, 0)" +. auto/feature + + +if [ $ngx_found != yes ]; then + + ngx_feature="dlopen() in libdl" + ngx_feature_libs="-ldl" + . auto/feature + + if [ $ngx_found = yes ]; then + NGX_LIBDL="-ldl" + fi +fi + + ngx_feature="mmap(MAP_ANON|MAP_SHARED)" ngx_feature_name="NGX_HAVE_MAP_ANON" ngx_feature_run=yes diff --git a/configure b/configure --- a/configure +++ b/configure @@ -31,6 +31,12 @@ if test -z "$NGX_PLATFORM"; then NGX_PLATFORM="$NGX_SYSTEM:$NGX_RELEASE:$NGX_MACHINE"; + case "$NGX_SYSTEM" in + MINGW32_*) + NGX_PLATFORM=win32 + ;; + esac + else echo "building for $NGX_PLATFORM" NGX_SYSTEM=$NGX_PLATFORM diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,8 +8,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 7055 -#define NGINX_VERSION "0.7.55" +#define nginx_version 7056 +#define NGINX_VERSION "0.7.56" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" 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 @@ -649,8 +649,22 @@ ngx_parse_inet6_url(ngx_pool_t *pool, ng (void) ngx_cpystrn(p, host, len); +#if (NGX_WIN32) + + rc = WSAStringToAddress((char *) p, AF_INET6, NULL, + (SOCKADDR *) sin6, &u->socklen); + rc = !rc; + + if (u->port) { + sin6->sin6_port = htons(u->port); + } + +#else + rc = inet_pton(AF_INET6, (const char *) p, &sin6->sin6_addr); +#endif + ngx_free(p); if (rc == 0) { 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 @@ -9,7 +9,6 @@ #include - static ngx_int_t ngx_select_init(ngx_cycle_t *cycle, ngx_msec_t timer); static void ngx_select_done(ngx_cycle_t *cycle); static ngx_int_t ngx_select_add_event(ngx_event_t *ev, ngx_int_t event, @@ -27,13 +26,7 @@ static fd_set master_write_fd_se static fd_set work_read_fd_set; static fd_set work_write_fd_set; -#if (NGX_WIN32) -static ngx_uint_t max_read; -static ngx_uint_t max_write; -#else static ngx_int_t max_fd; -#endif - static ngx_uint_t nevents; static ngx_event_t **event_index; @@ -112,11 +105,7 @@ ngx_select_init(ngx_cycle_t *cycle, ngx_ ngx_event_flags = NGX_USE_LEVEL_EVENT; -#if (NGX_WIN32) - max_read = max_write = 0; -#else max_fd = -1; -#endif return NGX_OK; } @@ -156,29 +145,6 @@ ngx_select_add_event(ngx_event_t *ev, ng return NGX_ERROR; } - -#if (NGX_WIN32) - - if ((event == NGX_READ_EVENT) && (max_read >= FD_SETSIZE) - || (event == NGX_WRITE_EVENT) && (max_write >= FD_SETSIZE)) - { - ngx_log_error(NGX_LOG_ERR, ev->log, 0, - "maximum number of descriptors " - "supported by select() is %d", FD_SETSIZE); - return NGX_ERROR; - } - - if (event == NGX_READ_EVENT) { - FD_SET(c->fd, &master_read_fd_set); - max_read++; - - } else if (event == NGX_WRITE_EVENT) { - FD_SET(c->fd, &master_write_fd_set); - max_write++; - } - -#else - if (event == NGX_READ_EVENT) { FD_SET(c->fd, &master_read_fd_set); @@ -190,8 +156,6 @@ ngx_select_add_event(ngx_event_t *ev, ng max_fd = c->fd; } -#endif - ev->active = 1; event_index[nevents] = ev; @@ -219,19 +183,6 @@ ngx_select_del_event(ngx_event_t *ev, ng ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, "select del event fd:%d ev:%i", c->fd, event); -#if (NGX_WIN32) - - if (event == NGX_READ_EVENT) { - FD_CLR(c->fd, &master_read_fd_set); - max_read--; - - } else if (event == NGX_WRITE_EVENT) { - FD_CLR(c->fd, &master_write_fd_set); - max_write--; - } - -#else - if (event == NGX_READ_EVENT) { FD_CLR(c->fd, &master_read_fd_set); @@ -243,8 +194,6 @@ ngx_select_del_event(ngx_event_t *ev, ng max_fd = -1; } -#endif - if (ev->index < --nevents) { e = event_index[nevents]; event_index[ev->index] = e; @@ -268,8 +217,6 @@ ngx_select_process_events(ngx_cycle_t *c struct timeval tv, *tp; ngx_connection_t *c; -#if !(NGX_WIN32) - if (max_fd == -1) { for (i = 0; i < nevents; i++) { c = event_index[i]->data; @@ -282,8 +229,6 @@ ngx_select_process_events(ngx_cycle_t *c "change max_fd: %d", max_fd); } -#endif - #if (NGX_DEBUG) if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) { for (i = 0; i < nevents; i++) { @@ -293,10 +238,8 @@ ngx_select_process_events(ngx_cycle_t *c "select event: fd:%d wr:%d", c->fd, ev->write); } -#if !(NGX_WIN32) ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "max_fd: %d", max_fd); -#endif } #endif @@ -315,30 +258,8 @@ ngx_select_process_events(ngx_cycle_t *c work_read_fd_set = master_read_fd_set; work_write_fd_set = master_write_fd_set; -#if (NGX_WIN32) - - if (max_read || max_write) { - ready = select(0, &work_read_fd_set, &work_write_fd_set, NULL, tp); - - } else { - - /* - * Winsock select() requires that at least one descriptor set must be - * be non-null, and any non-null descriptor set must contain at least - * one handle to a socket. Otherwise select() returns WSAEINVAL. - */ - - ngx_msleep(timer); - - ready = 0; - } - -#else - ready = select(max_fd + 1, &work_read_fd_set, &work_write_fd_set, NULL, tp); -#endif - if (ready == -1) { err = ngx_socket_errno; } else { @@ -352,20 +273,6 @@ ngx_select_process_events(ngx_cycle_t *c ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "select ready %d", ready); -#if (NGX_WIN32) - - if (err) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, err, "select() failed"); - - if (err == WSAENOTSOCK) { - ngx_select_repair_fd_sets(cycle); - } - - return NGX_ERROR; - } - -#else - if (err) { ngx_uint_t level; @@ -391,8 +298,6 @@ ngx_select_process_events(ngx_cycle_t *c return NGX_ERROR; } -#endif - if (ready == 0) { if (timer != NGX_TIMER_INFINITE) { return NGX_OK; @@ -459,41 +364,6 @@ ngx_select_repair_fd_sets(ngx_cycle_t *c ngx_err_t err; ngx_socket_t s; -#if (NGX_WIN32) - u_int i; - - for (i = 0; i < master_read_fd_set.fd_count; i++) { - - s = master_read_fd_set.fd_array[i]; - len = sizeof(int); - - if (getsockopt(s, SOL_SOCKET, SO_TYPE, (char *) &n, &len) == -1) { - err = ngx_socket_errno; - - ngx_log_error(NGX_LOG_ALERT, cycle->log, err, - "invalid descriptor #%d in read fd_set", s); - - FD_CLR(s, &master_read_fd_set); - } - } - - for (i = 0; i < master_write_fd_set.fd_count; i++) { - - s = master_write_fd_set.fd_array[i]; - len = sizeof(int); - - if (getsockopt(s, SOL_SOCKET, SO_TYPE, (char *) &n, &len) == -1) { - err = ngx_socket_errno; - - ngx_log_error(NGX_LOG_ALERT, cycle->log, err, - "invalid descriptor #%d in write fd_set", s); - - FD_CLR(s, &master_write_fd_set); - } - } - -#else - for (s = 0; s <= max_fd; s++) { if (FD_ISSET(s, &master_read_fd_set) == 0) { @@ -531,8 +401,6 @@ ngx_select_repair_fd_sets(ngx_cycle_t *c } max_fd = -1; - -#endif } @@ -549,8 +417,6 @@ ngx_select_init_conf(ngx_cycle_t *cycle, /* disable warning: the default FD_SETSIZE is 1024U in FreeBSD 5.x */ -#if !(NGX_WIN32) - if (cycle->connection_n > FD_SETSIZE) { ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "the maximum number of files " @@ -558,9 +424,7 @@ ngx_select_init_conf(ngx_cycle_t *cycle, return NGX_CONF_ERROR; } -#endif - -#if (NGX_THREADS) && !(NGX_WIN32) +#if (NGX_THREADS) ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "select() is not supported in the threaded mode"); diff --git a/src/event/modules/ngx_win32_select_module.c b/src/event/modules/ngx_win32_select_module.c new file mode 100644 --- /dev/null +++ b/src/event/modules/ngx_win32_select_module.c @@ -0,0 +1,403 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +static ngx_int_t ngx_select_init(ngx_cycle_t *cycle, ngx_msec_t timer); +static void ngx_select_done(ngx_cycle_t *cycle); +static ngx_int_t ngx_select_add_event(ngx_event_t *ev, ngx_int_t event, + ngx_uint_t flags); +static ngx_int_t ngx_select_del_event(ngx_event_t *ev, ngx_int_t event, + ngx_uint_t flags); +static ngx_int_t ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, + ngx_uint_t flags); +static void ngx_select_repair_fd_sets(ngx_cycle_t *cycle); +static char *ngx_select_init_conf(ngx_cycle_t *cycle, void *conf); + + +static fd_set master_read_fd_set; +static fd_set master_write_fd_set; +static fd_set work_read_fd_set; +static fd_set work_write_fd_set; + +static ngx_uint_t max_read; +static ngx_uint_t max_write; +static ngx_uint_t nevents; + +static ngx_event_t **event_index; + + +static ngx_str_t select_name = ngx_string("select"); + +ngx_event_module_t ngx_select_module_ctx = { + &select_name, + NULL, /* create configuration */ + ngx_select_init_conf, /* init configuration */ + + { + ngx_select_add_event, /* add an event */ + ngx_select_del_event, /* delete an event */ + ngx_select_add_event, /* enable an event */ + ngx_select_del_event, /* disable an event */ + NULL, /* add an connection */ + NULL, /* delete an connection */ + NULL, /* process the changes */ + ngx_select_process_events, /* process the events */ + ngx_select_init, /* init the events */ + ngx_select_done /* done the events */ + } + +}; + +ngx_module_t ngx_select_module = { + NGX_MODULE_V1, + &ngx_select_module_ctx, /* module context */ + NULL, /* module directives */ + NGX_EVENT_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_int_t +ngx_select_init(ngx_cycle_t *cycle, ngx_msec_t timer) +{ + ngx_event_t **index; + + if (event_index == NULL) { + FD_ZERO(&master_read_fd_set); + FD_ZERO(&master_write_fd_set); + nevents = 0; + } + + if (ngx_process == NGX_PROCESS_WORKER + || cycle->old_cycle == NULL + || cycle->old_cycle->connection_n < cycle->connection_n) + { + 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); + ngx_free(event_index); + } + + event_index = index; + } + + ngx_io = ngx_os_io; + + ngx_event_actions = ngx_select_module_ctx.actions; + + ngx_event_flags = NGX_USE_LEVEL_EVENT; + + max_read = 0; + max_write = 0; + + return NGX_OK; +} + + +static void +ngx_select_done(ngx_cycle_t *cycle) +{ + ngx_free(event_index); + + event_index = NULL; +} + + +static ngx_int_t +ngx_select_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) +{ + ngx_connection_t *c; + + c = ev->data; + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, + "select add event fd:%d ev:%i", c->fd, event); + + if (ev->index != NGX_INVALID_INDEX) { + ngx_log_error(NGX_LOG_ALERT, ev->log, 0, + "select event fd:%d ev:%i is already set", c->fd, event); + return NGX_OK; + } + + if ((event == NGX_READ_EVENT && ev->write) + || (event == NGX_WRITE_EVENT && !ev->write)) + { + ngx_log_error(NGX_LOG_ALERT, ev->log, 0, + "invalid select %s event fd:%d ev:%i", + ev->write ? "write" : "read", c->fd, event); + return NGX_ERROR; + } + + if ((event == NGX_READ_EVENT) && (max_read >= FD_SETSIZE) + || (event == NGX_WRITE_EVENT) && (max_write >= FD_SETSIZE)) + { + ngx_log_error(NGX_LOG_ERR, ev->log, 0, + "maximum number of descriptors " + "supported by select() is %d", FD_SETSIZE); + return NGX_ERROR; + } + + if (event == NGX_READ_EVENT) { + FD_SET(c->fd, &master_read_fd_set); + max_read++; + + } else if (event == NGX_WRITE_EVENT) { + FD_SET(c->fd, &master_write_fd_set); + max_write++; + } + + ev->active = 1; + + event_index[nevents] = ev; + ev->index = nevents; + nevents++; + + return NGX_OK; +} + + +static ngx_int_t +ngx_select_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags) +{ + ngx_event_t *e; + ngx_connection_t *c; + + c = ev->data; + + ev->active = 0; + + if (ev->index == NGX_INVALID_INDEX) { + return NGX_OK; + } + + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0, + "select del event fd:%d ev:%i", c->fd, event); + + if (event == NGX_READ_EVENT) { + FD_CLR(c->fd, &master_read_fd_set); + max_read--; + + } else if (event == NGX_WRITE_EVENT) { + FD_CLR(c->fd, &master_write_fd_set); + max_write--; + } + + if (ev->index < --nevents) { + e = event_index[nevents]; + event_index[ev->index] = e; + e->index = ev->index; + } + + ev->index = NGX_INVALID_INDEX; + + return NGX_OK; +} + + +static ngx_int_t +ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, + ngx_uint_t flags) +{ + int ready, nready; + ngx_err_t err; + ngx_uint_t i, found; + ngx_event_t *ev, **queue; + struct timeval tv, *tp; + ngx_connection_t *c; + +#if (NGX_DEBUG) + if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) { + for (i = 0; i < nevents; i++) { + ev = event_index[i]; + c = ev->data; + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "select event: fd:%d wr:%d", c->fd, ev->write); + } + } +#endif + + if (timer == NGX_TIMER_INFINITE) { + tp = NULL; + + } else { + tv.tv_sec = (long) (timer / 1000); + tv.tv_usec = (long) ((timer % 1000) * 1000); + tp = &tv; + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "select timer: %M", timer); + + work_read_fd_set = master_read_fd_set; + work_write_fd_set = master_write_fd_set; + + if (max_read || max_write) { + ready = select(0, &work_read_fd_set, &work_write_fd_set, NULL, tp); + + } else { + + /* + * Winsock select() requires that at least one descriptor set must be + * be non-null, and any non-null descriptor set must contain at least + * one handle to a socket. Otherwise select() returns WSAEINVAL. + */ + + ngx_msleep(timer); + + ready = 0; + } + + if (ready == -1) { + err = ngx_socket_errno; + } else { + err = 0; + } + + if (flags & NGX_UPDATE_TIME) { + ngx_time_update(0, 0); + } + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "select ready %d", ready); + + if (err) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, err, "select() failed"); + + if (err == WSAENOTSOCK) { + ngx_select_repair_fd_sets(cycle); + } + + return NGX_ERROR; + } + + if (ready == 0) { + if (timer != NGX_TIMER_INFINITE) { + return NGX_OK; + } + + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "select() returned no events without timeout"); + return NGX_ERROR; + } + + ngx_mutex_lock(ngx_posted_events_mutex); + + nready = 0; + + for (i = 0; i < nevents; i++) { + ev = event_index[i]; + c = ev->data; + found = 0; + + if (ev->write) { + if (FD_ISSET(c->fd, &work_write_fd_set)) { + found = 1; + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "select write %d", c->fd); + } + + } else { + if (FD_ISSET(c->fd, &work_read_fd_set)) { + found = 1; + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, + "select read %d", c->fd); + } + } + + if (found) { + ev->ready = 1; + + queue = (ngx_event_t **) (ev->accept ? &ngx_posted_accept_events: + &ngx_posted_events); + ngx_locked_post_event(ev, queue); + + nready++; + } + } + + ngx_mutex_unlock(ngx_posted_events_mutex); + + if (ready != nready) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "select ready != events: %d:%d", ready, nready); + + ngx_select_repair_fd_sets(cycle); + } + + return NGX_OK; +} + + +static void +ngx_select_repair_fd_sets(ngx_cycle_t *cycle) +{ + int n; + u_int i; + socklen_t len; + ngx_err_t err; + ngx_socket_t s; + + for (i = 0; i < master_read_fd_set.fd_count; i++) { + + s = master_read_fd_set.fd_array[i]; + len = sizeof(int); + + if (getsockopt(s, SOL_SOCKET, SO_TYPE, (char *) &n, &len) == -1) { + err = ngx_socket_errno; + + ngx_log_error(NGX_LOG_ALERT, cycle->log, err, + "invalid descriptor #%d in read fd_set", s); + + FD_CLR(s, &master_read_fd_set); + } + } + + for (i = 0; i < master_write_fd_set.fd_count; i++) { + + s = master_write_fd_set.fd_array[i]; + len = sizeof(int); + + if (getsockopt(s, SOL_SOCKET, SO_TYPE, (char *) &n, &len) == -1) { + err = ngx_socket_errno; + + ngx_log_error(NGX_LOG_ALERT, cycle->log, err, + "invalid descriptor #%d in write fd_set", s); + + FD_CLR(s, &master_write_fd_set); + } + } +} + + +static char * +ngx_select_init_conf(ngx_cycle_t *cycle, void *conf) +{ + ngx_event_conf_t *ecf; + + ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module); + + if (ecf->use != ngx_select_module.ctx_index) { + return NGX_CONF_OK; + } + + return NGX_CONF_OK; +} diff --git a/src/http/modules/ngx_http_image_filter_module.c b/src/http/modules/ngx_http_image_filter_module.c --- a/src/http/modules/ngx_http_image_filter_module.c +++ b/src/http/modules/ngx_http_image_filter_module.c @@ -7,7 +7,8 @@ #include #include #include -#include "gd.h" + +#include #define NGX_HTTP_IMAGE_OFF 0 @@ -20,7 +21,8 @@ #define NGX_HTTP_IMAGE_START 0 #define NGX_HTTP_IMAGE_READ 1 #define NGX_HTTP_IMAGE_PROCESS 2 -#define NGX_HTTP_IMAGE_DONE 3 +#define NGX_HTTP_IMAGE_PASS 3 +#define NGX_HTTP_IMAGE_DONE 4 #define NGX_HTTP_IMAGE_NONE 0 @@ -55,6 +57,8 @@ typedef struct { } ngx_http_image_filter_ctx_t; +static ngx_int_t ngx_http_image_send(ngx_http_request_t *r, + ngx_http_image_filter_ctx_t *ctx, ngx_chain_t *in); static ngx_uint_t ngx_http_image_test(ngx_http_request_t *r, ngx_chain_t *in); static ngx_int_t ngx_http_image_read(ngx_http_request_t *r, ngx_chain_t *in); static ngx_buf_t *ngx_http_image_process(ngx_http_request_t *r); @@ -177,6 +181,13 @@ ngx_http_image_header_filter(ngx_http_re return NGX_ERROR; } + ctx = ngx_http_get_module_ctx(r, ngx_http_image_filter_module); + + if (ctx) { + ngx_http_set_ctx(r, NULL, ngx_http_image_filter_module); + return ngx_http_next_header_filter(r); + } + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_image_filter_ctx_t)); if (ctx == NULL) { return NGX_ERROR; @@ -247,13 +258,14 @@ ngx_http_image_body_filter(ngx_http_requ if (out.buf) { out.next = NULL; - in = &out; + ctx->phase = NGX_HTTP_IMAGE_DONE; - break; + return ngx_http_image_send(r, ctx, &out); } } return ngx_http_filter_finalize_request(r, + &ngx_http_image_filter_module, NGX_HTTP_UNSUPPORTED_MEDIA_TYPE); } @@ -264,7 +276,9 @@ ngx_http_image_body_filter(ngx_http_requ r->headers_out.content_type = *ct; if (conf->filter == NGX_HTTP_IMAGE_TEST) { - break; + ctx->phase = NGX_HTTP_IMAGE_PASS; + + return ngx_http_image_send(r, ctx, in); } ctx->phase = NGX_HTTP_IMAGE_READ; @@ -281,6 +295,7 @@ ngx_http_image_body_filter(ngx_http_requ if (rc == NGX_ERROR) { return ngx_http_filter_finalize_request(r, + &ngx_http_image_filter_module, NGX_HTTP_UNSUPPORTED_MEDIA_TYPE); } @@ -292,28 +307,49 @@ ngx_http_image_body_filter(ngx_http_requ if (out.buf == NULL) { return ngx_http_filter_finalize_request(r, + &ngx_http_image_filter_module, NGX_HTTP_UNSUPPORTED_MEDIA_TYPE); } out.next = NULL; - in = &out; + ctx->phase = NGX_HTTP_IMAGE_PASS; + + return ngx_http_image_send(r, ctx, &out); - break; + case NGX_HTTP_IMAGE_PASS: + + return ngx_http_next_body_filter(r, in); default: /* NGX_HTTP_IMAGE_DONE */ - return ngx_http_next_body_filter(r, in); + rc = ngx_http_next_body_filter(r, NULL); + + /* NGX_ERROR resets any pending data */ + return (rc == NGX_OK) ? NGX_ERROR : rc; } +} - ctx->phase = NGX_HTTP_IMAGE_DONE; + +static ngx_int_t +ngx_http_image_send(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx, + ngx_chain_t *in) +{ + ngx_int_t rc; rc = ngx_http_next_header_filter(r); if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { - return rc; + return NGX_ERROR; } - return ngx_http_next_body_filter(r, in); + rc = ngx_http_next_body_filter(r, in); + + if (ctx->phase == NGX_HTTP_IMAGE_DONE) { + /* NGX_ERROR resets any pending data */ + return (rc == NGX_OK) ? NGX_ERROR : rc; + } + + return rc; } diff --git a/src/http/modules/ngx_http_xslt_filter_module.c b/src/http/modules/ngx_http_xslt_filter_module.c --- a/src/http/modules/ngx_http_xslt_filter_module.c +++ b/src/http/modules/ngx_http_xslt_filter_module.c @@ -319,7 +319,7 @@ ngx_http_xslt_send(ngx_http_request_t *r ctx->done = 1; if (b == NULL) { - return ngx_http_filter_finalize_request(r, + return ngx_http_filter_finalize_request(r, NULL, NGX_HTTP_INTERNAL_SERVER_ERROR); } @@ -327,7 +327,7 @@ ngx_http_xslt_send(ngx_http_request_t *r if (cln == NULL) { ngx_free(b->pos); - return ngx_http_filter_finalize_request(r, + return ngx_http_filter_finalize_request(r, NULL, NGX_HTTP_INTERNAL_SERVER_ERROR); } diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm --- a/src/http/modules/perl/nginx.pm +++ b/src/http/modules/perl/nginx.pm @@ -47,7 +47,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '0.7.55'; +our $VERSION = '0.7.56'; require XSLoader; XSLoader::load('nginx', $VERSION); 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 @@ -104,7 +104,7 @@ ngx_int_t ngx_http_send_header(ngx_http_ ngx_int_t ngx_http_special_response_handler(ngx_http_request_t *r, ngx_int_t error); ngx_int_t ngx_http_filter_finalize_request(ngx_http_request_t *r, - ngx_int_t error); + ngx_module_t *m, ngx_int_t error); void ngx_http_clean_header(ngx_http_request_t *r); 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 @@ -1652,16 +1652,24 @@ ngx_http_send_header(ngx_http_request_t ngx_int_t ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *in) { - ngx_int_t rc; - - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + ngx_int_t rc; + ngx_connection_t *c; + + c = r->connection; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, "http output filter \"%V?%V\"", &r->uri, &r->args); rc = ngx_http_top_body_filter(r, in); if (rc == NGX_ERROR) { + + if (c->destroyed) { + return NGX_DONE; + } + /* NGX_ERROR may be returned by any filter */ - r->connection->error = 1; + c->error = 1; } return rc; 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 @@ -1815,6 +1815,11 @@ ngx_http_finalize_request(ngx_http_reque "http finalize request: %d, \"%V?%V\" %d", rc, &r->uri, &r->args, r == c->data); + if (rc == NGX_OK && r->filter_finalize) { + c->error = 1; + return; + } + if (rc == NGX_DECLINED) { r->content_handler = NULL; r->write_event_handler = ngx_http_core_run_phases; 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 @@ -478,6 +478,7 @@ struct ngx_http_request_s { unsigned discard_body:1; unsigned internal:1; unsigned error_page:1; + unsigned filter_finalize:1; unsigned post_action:1; unsigned request_complete:1; unsigned request_output:1; 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 @@ -446,20 +446,42 @@ ngx_http_special_response_handler(ngx_ht ngx_int_t -ngx_http_filter_finalize_request(ngx_http_request_t *r, ngx_int_t error) +ngx_http_filter_finalize_request(ngx_http_request_t *r, ngx_module_t *m, + ngx_int_t error) { - ngx_int_t rc; + void *ctx; + ngx_int_t rc; ngx_http_clean_header(r); + ctx = NULL; + + if (m) { + ctx = r->ctx[m->ctx_index]; + } + /* clear the modules contexts */ ngx_memzero(r->ctx, sizeof(void *) * ngx_http_max_module); + if (m) { + r->ctx[m->ctx_index] = ctx; + } + + r->filter_finalize = 1; + rc = ngx_http_special_response_handler(r, error); /* NGX_ERROR resets any pending data */ - return (rc == NGX_OK) ? NGX_ERROR : rc; + switch (rc) { + + case NGX_OK: + case NGX_DONE: + return NGX_ERROR; + + default: + return rc; + } } 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 @@ -1483,7 +1483,6 @@ ngx_http_upstream_process_header(ngx_htt static ngx_int_t ngx_http_upstream_test_next(ngx_http_request_t *r, ngx_http_upstream_t *u) { - ngx_int_t rc; ngx_uint_t status; ngx_http_upstream_next_t *un; @@ -1503,6 +1502,7 @@ ngx_http_upstream_test_next(ngx_http_req #if (NGX_HTTP_CACHE) if (u->stale_cache && (u->conf->cache_use_stale & un->mask)) { + ngx_int_t rc; rc = u->reinit_request(r); diff --git a/src/os/unix/ngx_sunpro_x86.il b/src/os/unix/ngx_sunpro_x86.il --- a/src/os/unix/ngx_sunpro_x86.il +++ b/src/os/unix/ngx_sunpro_x86.il @@ -5,7 +5,7 @@ / ngx_atomic_uint_t ngx_atomic_cmp_set(ngx_atomic_t *lock, / ngx_atomic_uint_t old, ngx_atomic_uint_t set); / -/ the arguments are passed on the stack (%esp), 4(%esp), 8(%esp) +/ the arguments are passed on stack (%esp), 4(%esp), 8(%esp) .inline ngx_atomic_cmp_set,0 movl (%esp), %ecx @@ -21,7 +21,7 @@ / ngx_atomic_int_t ngx_atomic_fetch_add(ngx_atomic_t *value, / ngx_atomic_int_t add); / -/ the arguments are passed on the stack (%esp), 4(%esp) +/ the arguments are passed on stack (%esp), 4(%esp) .inline ngx_atomic_fetch_add,0 movl (%esp), %ecx @@ -32,7 +32,12 @@ / ngx_cpu_pause() +/ +/ the "rep; nop" is used instead of "pause" to avoid the "[ PAUSE ]" hardware +/ capability added by linker because Solaris/i386 does not know about it: +/ +/ ld.so.1: nginx: fatal: hardware capability unsupported: 0x2000 [ PAUSE ] .inline ngx_cpu_pause,0 - pause + rep; nop .end diff --git a/src/os/unix/ngx_sunpro_x86.map b/src/os/unix/ngx_sunpro_x86.map deleted file mode 100644 --- a/src/os/unix/ngx_sunpro_x86.map +++ /dev/null @@ -1,2 +0,0 @@ -# disable { PAUSE ] hwcap for Sun Studio 11 -hwcap_1 = OVERRIDE;