changeset 488:829f9a66a659 NGINX_0_7_56

nginx 0.7.56 *) Feature: nginx/Windows supports IPv6 in a "listen" directive of the HTTP module. *) Bugfix: in ngx_http_image_filter_module.
author Igor Sysoev <http://sysoev.ru>
date Mon, 11 May 2009 00:00:00 +0400
parents e98b980b4fe7
children c91fb8e75a55
files CHANGES CHANGES.ru auto/cc/msvc auto/cc/owc auto/cc/sunc auto/lib/md5/conf auto/lib/openssl/conf auto/make auto/os/solaris auto/os/win32 auto/sources auto/unix configure src/core/nginx.h src/core/ngx_inet.c src/event/modules/ngx_select_module.c src/event/modules/ngx_win32_select_module.c src/http/modules/ngx_http_image_filter_module.c src/http/modules/ngx_http_xslt_filter_module.c src/http/modules/perl/nginx.pm src/http/ngx_http.h src/http/ngx_http_core_module.c src/http/ngx_http_request.c src/http/ngx_http_request.h src/http/ngx_http_special_response.c src/http/ngx_http_upstream.c src/os/unix/ngx_sunpro_x86.il src/os/unix/ngx_sunpro_x86.map
diffstat 28 files changed, 619 insertions(+), 229 deletions(-) [+]
line wrap: on
line diff
--- 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 
--- 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.
--- 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="\\"
--- 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=' '
--- 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"
     ;;
 
--- 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 <md5.h>"
-        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 <md5.h>"
+            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
--- 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
--- 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
 
--- 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
--- 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
--- 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
--- 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 <dlfcn.h>"
+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
--- 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
--- 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"
--- 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) {
--- a/src/event/modules/ngx_select_module.c
+++ b/src/event/modules/ngx_select_module.c
@@ -9,7 +9,6 @@
 #include <ngx_event.h>
 
 
-
 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");
new file mode 100644
--- /dev/null
+++ b/src/event/modules/ngx_win32_select_module.c
@@ -0,0 +1,403 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+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;
+}
--- 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 <ngx_config.h>
 #include <ngx_core.h>
 #include <ngx_http.h>
-#include "gd.h"
+
+#include <gd.h>
 
 
 #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;
 }
 
 
--- 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);
     }
 
--- 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);
--- 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);
 
 
--- 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;
--- 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;
--- 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;
--- 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;
+    }
 }
 
 
--- 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);
 
--- 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
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;