nginx-0.1.1-RELEASE import

    *) Feature: the gzip_types directive.

    *) Feature: the tcp_nodelay directive.

    *) Feature: the send_lowat directive is working not only on OSes that
       support kqueue NOTE_LOWAT, but also on OSes that support SO_SNDLOWAT.

    *) Feature: the setproctitle() emulation for Linux and Solaris.

    *) Bugfix: the "Location" header rewrite bug fixed while the proxying.

    *) Bugfix: the ngx_http_chunked_module module may get caught in an
       endless loop.

    *) Bugfix: the /dev/poll module bugs fixed.

    *) Bugfix: the responses were corrupted when the temporary files were
       used while the proxying.

    *) Bugfix: the unescaped requests were passed to the backend.

    *) Bugfix: while the build configuration on Linux 2.4 the
       --with-poll_module parameter was required.
diff --git a/src/event/modules/ngx_devpoll_module.c b/src/event/modules/ngx_devpoll_module.c
index 7d68884..ea1d19b 100644
--- a/src/event/modules/ngx_devpoll_module.c
+++ b/src/event/modules/ngx_devpoll_module.c
@@ -202,13 +202,7 @@
 #endif
 
 #if (NGX_READ_EVENT != POLLIN)
-    if (event == NGX_READ_EVENT) {
-        event = POLLOUT;
-#if (NGX_WRITE_EVENT != POLLOUT)
-    } else {
-        event = POLLIN;
-#endif
-    }
+    event = (event == NGX_READ_EVENT) ? POLLIN : POLLOUT;
 #endif
 
 #if (NGX_DEBUG)
@@ -218,6 +212,7 @@
 #endif
 
     ev->active = 1;
+
     return ngx_devpoll_set_event(ev, event, 0);
 }
 
@@ -229,6 +224,10 @@
 
     c = ev->data;
 
+#if (NGX_READ_EVENT != POLLIN)
+    event = (event == NGX_READ_EVENT) ? POLLIN : POLLOUT;
+#endif
+
     ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
                    "devpoll del event: fd:%d ev:%04X", c->fd, event);
 
@@ -242,13 +241,9 @@
         return NGX_OK;
     }
 
-    /* we need to restore the second event if it exists */
+    /* restore the paired event if it exists */
 
-    if (event == NGX_READ_EVENT) {
-        if (ev->accept) {
-            return NGX_OK;
-        }
-
+    if (event == POLLIN) {
         e = c->write;
         event = POLLOUT;
 
@@ -257,7 +252,7 @@
         event = POLLIN;
     }
 
-    if (e) {
+    if (e && e->active) {
         return ngx_devpoll_set_event(e, event, 0);
     }
 
@@ -273,7 +268,7 @@
     c = ev->data;
 
     ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
-                   "devpoll fd:%d ev:%d fl:%d", c->fd, event, flags);
+                   "devpoll fd:%d ev:%04X fl:%04X", c->fd, event, flags);
 
     if (nchanges >= max_changes) {
         ngx_log_error(NGX_LOG_WARN, ev->log, 0,
diff --git a/src/event/modules/ngx_rtsig_module.c b/src/event/modules/ngx_rtsig_module.c
index 26b2c81..72c5b7c 100644
--- a/src/event/modules/ngx_rtsig_module.c
+++ b/src/event/modules/ngx_rtsig_module.c
@@ -131,10 +131,6 @@
 {
     ngx_rtsig_conf_t  *rtscf;
 
-    if (ngx_poll_module_ctx.actions.init(cycle) == NGX_ERROR) {
-        return NGX_ERROR;
-    }
-
     rtscf = ngx_event_get_conf(cycle->conf_ctx, ngx_rtsig_module);
 
     sigemptyset(&set);
@@ -170,7 +166,9 @@
 
 static void ngx_rtsig_done(ngx_cycle_t *cycle)
 {
-    ngx_poll_module_ctx.actions.done(cycle);
+    ngx_free(overflow_list);
+
+    overflow_list = NULL;
 }
 
 
@@ -697,7 +695,7 @@
                  * the new overflow.
                  *
                  * Learn the /proc/sys/kernel/rtsig-max value because
-                 * it can be changed sisnce the last checking.
+                 * it can be changed since the last checking.
                  */
 
                 name[0] = CTL_KERN;
diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c
index 3d7e15c..4718dcd 100644
--- a/src/event/ngx_event.c
+++ b/src/event/ngx_event.c
@@ -461,6 +461,39 @@
 }
 
 
+ngx_int_t ngx_send_lowat(ngx_connection_t *c, size_t lowat)
+{
+    int  sndlowat;
+
+#if (HAVE_LOWAT_EVENT)
+
+    if (ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) {
+        c->write->available = lowat;
+        return NGX_OK;
+    }
+
+#endif
+    
+    if (lowat == 0 || c->sndlowat) {
+        return NGX_OK;
+    }
+
+    sndlowat = (int) lowat;
+
+    if (setsockopt(c->fd, SOL_SOCKET, SO_SNDLOWAT,
+                                  (const void *) &sndlowat, sizeof(int)) == -1)
+    {
+        ngx_connection_error(c, ngx_socket_errno,
+                             "setsockopt(SO_SNDLOWAT) failed");
+        return NGX_ERROR;
+    }
+
+    c->sndlowat = 1;
+
+    return NGX_OK;
+}
+
+
 static char *ngx_events_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     int                    m;
diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h
index 7237bd4..c173adc 100644
--- a/src/event/ngx_event.h
+++ b/src/event/ngx_event.h
@@ -207,7 +207,7 @@
     ngx_int_t  (*add_conn)(ngx_connection_t *c);
     ngx_int_t  (*del_conn)(ngx_connection_t *c, u_int flags);
 
-    ngx_int_t  (*process_changes)(ngx_cycle_t *cycle, ngx_uint_t try);
+    ngx_int_t  (*process_changes)(ngx_cycle_t *cycle, ngx_uint_t nowait);
     ngx_int_t  (*process_events)(ngx_cycle_t *cycle);
 
     ngx_int_t  (*init)(ngx_cycle_t *cycle);
@@ -479,6 +479,9 @@
 #endif
 
 
+ngx_int_t ngx_send_lowat(ngx_connection_t *c, size_t lowat);
+
+
 /* used in ngx_log_debugX() */
 #define ngx_event_ident(p)  ((ngx_connection_t *) (p))->fd
 
@@ -497,7 +500,7 @@
 {
     if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
 
-        /* kqueue */
+        /* kqueue, epoll */
 
         if (!rev->active && !rev->ready) {
             if (ngx_add_event(rev, NGX_READ_EVENT, NGX_CLEAR_EVENT)
@@ -531,7 +534,7 @@
         }
     }
 
-    /* aio, iocp, epoll, rtsig */
+    /* aio, iocp, rtsig */
 
     return NGX_OK;
 }
@@ -563,14 +566,25 @@
 }
 
 
-ngx_inline static int ngx_handle_write_event(ngx_event_t *wev, u_int flags)
+ngx_inline static int ngx_handle_write_event(ngx_event_t *wev, size_t lowat)
 {
+    ngx_connection_t  *c;
+
+    if (lowat) {
+        c = wev->data;
+
+        if (ngx_send_lowat(c, lowat) == NGX_ERROR) {
+            return NGX_ERROR;
+        }
+    }
+
     if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
 
-        /* kqueue */
+        /* kqueue, epoll */
 
         if (!wev->active && !wev->ready) {
-            if (ngx_add_event(wev, NGX_WRITE_EVENT, NGX_CLEAR_EVENT|flags)
+            if (ngx_add_event(wev, NGX_WRITE_EVENT,
+                              NGX_CLEAR_EVENT | (lowat ? NGX_LOWAT_EVENT : 0))
                                                                   == NGX_ERROR)
             {
                 return NGX_ERROR;
@@ -602,7 +616,7 @@
         }
     }
 
-    /* aio, iocp, epoll, rtsig */
+    /* aio, iocp, rtsig */
 
     return NGX_OK;
 }
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
index 8c48a7a..151cc42 100644
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -72,6 +72,13 @@
         return n;
     }
 
+    if (!SSL_is_init_finished(c->ssl->ssl)) {
+        handshake = "in SSL handshake";
+
+    } else {
+        handshake = "";
+    }
+
     sslerr = SSL_get_error(c->ssl->ssl, n);
 
     err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0;
@@ -91,13 +98,6 @@
 #endif
     }
 
-    if (!SSL_is_init_finished(c->ssl->ssl)) {
-        handshake = "in SSL handshake";
-
-    } else {
-        handshake = "";
-    }
-
     c->ssl->no_rcv_shut = 1;
 
     if (sslerr == SSL_ERROR_ZERO_RETURN || ERR_peek_error() == 0) {
@@ -240,8 +240,9 @@
 
 static ngx_int_t ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size)
 {
-    int        n, sslerr;
-    ngx_err_t  err;
+    int         n, sslerr;
+    ngx_err_t   err;
+    char       *handshake;
 
     ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL to write: %d", size);
 
@@ -265,13 +266,21 @@
     }
 
     if (sslerr == SSL_ERROR_WANT_READ) {
+
+        if (!SSL_is_init_finished(c->ssl->ssl)) {
+            handshake = "in SSL handshake";
+
+        } else {
+            handshake = "";
+        }
+
         ngx_log_error(NGX_LOG_ALERT, c->log, err,
                       "SSL wants to read%s", handshake);
         return NGX_ERROR;
 #if 0
         return NGX_AGAIN;
-    }
 #endif
+    }
 
     c->ssl->no_rcv_shut = 1;
 
diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c
index c1982fd..71fc500 100644
--- a/src/event/ngx_event_pipe.c
+++ b/src/event/ngx_event_pipe.c
@@ -64,8 +64,7 @@
 
     if (p->downstream->fd != -1) {
         wev = p->downstream->write;
-        wev->available = p->send_lowat;
-        if (ngx_handle_write_event(wev, NGX_LOWAT_EVENT) == NGX_ERROR) {
+        if (ngx_handle_write_event(wev, p->send_lowat) == NGX_ERROR) {
             return NGX_ABORT;
         }
 
@@ -302,16 +301,41 @@
         ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe buf");
     }
 
-    for (cl = p->in; cl; cl = cl->next) {
+    for (cl = p->busy; cl; cl = cl->next) {
         ngx_log_debug3(NGX_LOG_DEBUG_EVENT, p->log, 0,
-                       "pipe buf in " PTR_FMT ", pos " PTR_FMT ", size: %d",
+                       "pipe buf busy " PTR_FMT ", pos " PTR_FMT ", size: %d",
                        cl->buf->start, cl->buf->pos,
                        cl->buf->last - cl->buf->pos);
     }
 
-    for (cl = p->busy; cl; cl = cl->next) {
+    for (cl = p->out; cl; cl = cl->next) {
+        if (cl->buf->in_file && cl->buf->temporary) {
+            ngx_log_debug5(NGX_LOG_DEBUG_EVENT, p->log, 0,
+                           "pipe buf out shadow "
+                           PTR_FMT ", pos " PTR_FMT ", size: %d "
+                           "file: " OFF_T_FMT ", size: %d",
+                           cl->buf->start, cl->buf->pos,
+                           cl->buf->last - cl->buf->pos,
+                           cl->buf->file_pos,
+                           cl->buf->file_last - cl->buf->file_pos);
+
+        } else if (cl->buf->in_file) {
+            ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
+                           "pipe buf out file " OFF_T_FMT ", size: %d",
+                           cl->buf->file_pos,
+                           cl->buf->file_last - cl->buf->file_pos);
+        } else {
+            ngx_log_debug3(NGX_LOG_DEBUG_EVENT, p->log, 0,
+                           "pipe buf out " PTR_FMT ", pos " PTR_FMT
+                           ", size: %d",
+                           cl->buf->start, cl->buf->pos,
+                           cl->buf->last - cl->buf->pos);
+        }
+    }
+
+    for (cl = p->in; cl; cl = cl->next) {
         ngx_log_debug3(NGX_LOG_DEBUG_EVENT, p->log, 0,
-                       "pipe buf busy " PTR_FMT ", pos " PTR_FMT ", size: %d",
+                       "pipe buf in " PTR_FMT ", pos " PTR_FMT ", size: %d",
                        cl->buf->start, cl->buf->pos,
                        cl->buf->last - cl->buf->pos);
     }
@@ -337,7 +361,9 @@
 
         if (p->free_bufs) {
             for (cl = p->free_raw_bufs; cl; cl = cl->next) {
-                ngx_pfree(p->pool, cl->buf->start); 
+                if (cl->buf->shadow == NULL) {
+                    ngx_pfree(p->pool, cl->buf->start); 
+                }
             }
         }
     }
@@ -597,8 +623,11 @@
         ngx_chain_add_link(p->out, p->last_out, cl);
 
         if (b->last_shadow) {
-            b->shadow->last = b->shadow->pos = b->shadow->start;
+            b->shadow->pos = b->shadow->start;
+            b->shadow->last = b->shadow->start;
+
             ngx_alloc_link_and_set_buf(tl, b->shadow, p->pool, NGX_ABORT);
+
             *last_free = tl;
             last_free = &tl->next;
         }
@@ -650,28 +679,24 @@
 {
     ngx_buf_t  *b, *next;
 
-    if (buf->shadow == NULL) {
+    b = buf->shadow;
+
+    if (b == NULL) {
         return;
     }
 
-    b = buf->shadow;
-
     while (!b->last_shadow) {
         next = b->shadow;
 
-        b->in_file = 0;
-        b->temp_file = 0;
-        b->flush = 0;
-        b->zerocopy_busy = 0;
+        b->temporary = 0;
+        b->recycled = 0;
 
         b->shadow = NULL;
         b = next;
     }
 
-    b->in_file = 0;
-    b->temp_file = 0;
-    b->flush = 0;
-    b->zerocopy_busy = 0;
+    b->temporary = 0;
+    b->recycled = 0;
     b->last_shadow = 0;
 
     b->shadow = NULL;