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/os/unix/ngx_errno.c b/src/os/unix/ngx_errno.c
index 0d03fa9..2faf63a 100644
--- a/src/os/unix/ngx_errno.c
+++ b/src/os/unix/ngx_errno.c
@@ -49,7 +49,8 @@
     str = strerror_r(err, errstr, size);
 
     if (str != errstr) {
-        return ngx_cpystrn(errstr, str, size) - (u_char *) errstr;
+        return ngx_cpystrn((u_char *) errstr, (u_char *) str, size)
+                                                           - (u_char *) errstr;
     }
 
     for (len = 0; len < size; len++) {
diff --git a/src/os/unix/ngx_freebsd.h b/src/os/unix/ngx_freebsd.h
index 9c89105..7a1e203 100644
--- a/src/os/unix/ngx_freebsd.h
+++ b/src/os/unix/ngx_freebsd.h
@@ -11,7 +11,6 @@
 ngx_chain_t *ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in,
                                         off_t limit);
 
-
 extern int ngx_freebsd_kern_osreldate;
 extern int ngx_freebsd_hw_ncpu;
 extern int ngx_freebsd_net_inet_tcp_sendspace;
diff --git a/src/os/unix/ngx_freebsd_config.h b/src/os/unix/ngx_freebsd_config.h
index f4616db..7961a3b 100644
--- a/src/os/unix/ngx_freebsd_config.h
+++ b/src/os/unix/ngx_freebsd_config.h
@@ -34,13 +34,13 @@
 
 #include <sys/socket.h>
 #include <netinet/in.h>
+#include <netinet/tcp.h>        /* TCP_NODELAY, TCP_NOPUSH */
 #include <arpa/inet.h>
 #include <netdb.h>
 
 #include <libutil.h>            /* setproctitle() before 4.1 */
 #include <osreldate.h>
 #include <sys/sysctl.h>
-#include <netinet/tcp.h>        /* TCP_NOPUSH */
 
 
 #if __FreeBSD_version < 400017
diff --git a/src/os/unix/ngx_freebsd_init.c b/src/os/unix/ngx_freebsd_init.c
index dcf432b..39a057b 100644
--- a/src/os/unix/ngx_freebsd_init.c
+++ b/src/os/unix/ngx_freebsd_init.c
@@ -193,6 +193,7 @@
         ngx_ncpu = ngx_freebsd_hw_ncpu;
     }
 
+
     return ngx_posix_init(log);
 }
 
@@ -221,5 +222,6 @@
         }
     }
 
+
     ngx_posix_status(log);
 }
diff --git a/src/os/unix/ngx_linux.h b/src/os/unix/ngx_linux.h
index 24034c0..4a8f8f3 100644
--- a/src/os/unix/ngx_linux.h
+++ b/src/os/unix/ngx_linux.h
@@ -8,6 +8,9 @@
 #define _NGX_LINUX_H_INCLUDED_
 
 
+ngx_int_t  ngx_init_setproctitle(ngx_log_t *log);
+void ngx_setproctitle(char *title);
+
 ngx_chain_t *ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in,
                                       off_t limit);
 
diff --git a/src/os/unix/ngx_linux_config.h b/src/os/unix/ngx_linux_config.h
index 2b23702..11427d3 100644
--- a/src/os/unix/ngx_linux_config.h
+++ b/src/os/unix/ngx_linux_config.h
@@ -39,13 +39,13 @@
 
 #include <sys/socket.h>
 #include <netinet/in.h>
+#include <netinet/tcp.h>        /* TCP_NODELAY, TCP_CORK */
 #include <arpa/inet.h>
 #include <netdb.h>
 
 #include <time.h>               /* tzset() */
 #include <sys/ioctl.h>
 #include <sys/sysctl.h>
-#include <netinet/tcp.h>        /* TCP_CORK */
 
 
 #include <ngx_auto_config.h>
@@ -94,8 +94,10 @@
 #define HAVE_SELECT_CHANGE_TIMEOUT   1
 #endif
 
-
-#define ngx_setproctitle(title)
+#ifndef NGX_SETPROCTITLE_USES_ENV
+#define NGX_SETPROCTITLE_USES_ENV    1
+#define NGX_SETPROCTITLE_PAD         '\0' 
+#endif
 
 
 #endif /* _NGX_LINUX_CONFIG_H_INCLUDED_ */
diff --git a/src/os/unix/ngx_linux_init.c b/src/os/unix/ngx_linux_init.c
index 4946e15..3c7d344 100644
--- a/src/os/unix/ngx_linux_init.c
+++ b/src/os/unix/ngx_linux_init.c
@@ -30,7 +30,8 @@
 
 ngx_int_t ngx_os_init(ngx_log_t *log)
 {
-    int  name[2], len;
+    int     name[2];
+    size_t  len;
 
     name[0] = CTL_KERN;
     name[1] = KERN_OSTYPE;
@@ -63,6 +64,8 @@
 
     }
 
+    ngx_init_setproctitle(log);
+
 
     return ngx_posix_init(log);
 }
@@ -76,5 +79,6 @@
     ngx_log_error(NGX_LOG_INFO, log, 0, "sysctl(KERN_RTSIGMAX): %d",
                   ngx_linux_rtsig_max);
 
+
     ngx_posix_status(log);
 }
diff --git a/src/os/unix/ngx_process.c b/src/os/unix/ngx_process.c
index dba949c..aff242c 100644
--- a/src/os/unix/ngx_process.c
+++ b/src/os/unix/ngx_process.c
@@ -12,10 +12,15 @@
 
 static void ngx_execute_proc(ngx_cycle_t *cycle, void *data);
 
-ngx_int_t      ngx_process_slot;
-ngx_socket_t   ngx_channel;
-ngx_int_t      ngx_last_process;
-ngx_process_t  ngx_processes[NGX_MAX_PROCESSES];
+
+int              ngx_argc;
+char           **ngx_argv;
+char           **ngx_os_argv;
+
+ngx_int_t        ngx_process_slot;
+ngx_socket_t     ngx_channel;
+ngx_int_t        ngx_last_process;
+ngx_process_t    ngx_processes[NGX_MAX_PROCESSES];
 
 
 ngx_pid_t ngx_spawn_process(ngx_cycle_t *cycle,
@@ -231,8 +236,23 @@
                 return;
             }
 
+#if (SOLARIS)
+
+            /*
+             * Solaris always calls the signal handler for each exited process
+             * despite waitpid() may be already called for this process
+             */
+
+            if (err == NGX_ECHILD) {
+                ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, errno,
+                              "waitpid() failed");
+            }
+
+#endif
+
             ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, errno,
                           "waitpid() failed");
+
             return;
         }
 
diff --git a/src/os/unix/ngx_process.h b/src/os/unix/ngx_process.h
index 816b6a6..0cea302 100644
--- a/src/os/unix/ngx_process.h
+++ b/src/os/unix/ngx_process.h
@@ -56,6 +56,9 @@
 
 #define ngx_sched_yield()  sched_yield()
 
+extern int            ngx_argc;
+extern char         **ngx_argv;
+extern char         **ngx_os_argv;
 
 extern ngx_pid_t      ngx_pid;
 extern ngx_socket_t   ngx_channel;
diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c
index 4d4db54..c43a7eb 100644
--- a/src/os/unix/ngx_process_cycle.c
+++ b/src/os/unix/ngx_process_cycle.c
@@ -14,7 +14,7 @@
                                        ngx_int_t type);
 static void ngx_signal_worker_processes(ngx_cycle_t *cycle, int signo);
 static ngx_uint_t ngx_reap_childs(ngx_cycle_t *cycle);
-static void ngx_master_exit(ngx_cycle_t *cycle, ngx_master_ctx_t *ctx);
+static void ngx_master_exit(ngx_cycle_t *cycle);
 static void ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data);
 static void ngx_channel_handler(ngx_event_t *ev);
 #if (NGX_THREADS)
@@ -55,7 +55,7 @@
 u_char  master_process[] = "master process";
 
 
-void ngx_master_process_cycle(ngx_cycle_t *cycle, ngx_master_ctx_t *ctx)
+void ngx_master_process_cycle(ngx_cycle_t *cycle)
 {
     char              *title;
     u_char            *p;
@@ -90,16 +90,16 @@
 
     size = sizeof(master_process);
 
-    for (i = 0; i < ctx->argc; i++) {
-        size += ngx_strlen(ctx->argv[i]) + 1;
+    for (i = 0; i < ngx_argc; i++) {
+        size += ngx_strlen(ngx_argv[i]) + 1;
     }
 
     title = ngx_palloc(cycle->pool, size);
 
     p = ngx_cpymem(title, master_process, sizeof(master_process) - 1);
-    for (i = 0; i < ctx->argc; i++) {
+    for (i = 0; i < ngx_argc; i++) {
         *p++ = ' ';
-        p = ngx_cpystrn(p, (u_char *) ctx->argv[i], size);
+        p = ngx_cpystrn(p, (u_char *) ngx_argv[i], size);
     }
 
     ngx_setproctitle(title);
@@ -149,7 +149,7 @@
         }
 
         if (!live && (ngx_terminate || ngx_quit)) {
-            ngx_master_exit(cycle, ctx);
+            ngx_master_exit(cycle);
         }
 
         if (ngx_terminate) {
@@ -231,7 +231,7 @@
         if (ngx_change_binary) {
             ngx_change_binary = 0;
             ngx_log_error(NGX_LOG_INFO, cycle->log, 0, "changing binary");
-            ngx_new_binary = ngx_exec_new_binary(cycle, ctx->argv);
+            ngx_new_binary = ngx_exec_new_binary(cycle, ngx_argv);
         }
 
         if (ngx_noaccept) {
@@ -244,14 +244,10 @@
 }
 
 
-void ngx_single_process_cycle(ngx_cycle_t *cycle, ngx_master_ctx_t *ctx)
+void ngx_single_process_cycle(ngx_cycle_t *cycle)
 {
     ngx_uint_t  i;
 
-#if 0
-    ngx_setproctitle("single worker process");
-#endif
-
     ngx_init_temp_number();
 
     for (i = 0; ngx_modules[i]; i++) {
@@ -269,7 +265,7 @@
         ngx_process_events(cycle);
 
         if (ngx_terminate || ngx_quit) {
-            ngx_master_exit(cycle, ctx);
+            ngx_master_exit(cycle);
         }
 
         if (ngx_reconfigure) {
@@ -547,7 +543,7 @@
 }
 
 
-static void ngx_master_exit(ngx_cycle_t *cycle, ngx_master_ctx_t *ctx)
+static void ngx_master_exit(ngx_cycle_t *cycle)
 {
     ngx_delete_pidfile(cycle);
 
diff --git a/src/os/unix/ngx_process_cycle.h b/src/os/unix/ngx_process_cycle.h
index 71aa178..16b981f 100644
--- a/src/os/unix/ngx_process_cycle.h
+++ b/src/os/unix/ngx_process_cycle.h
@@ -19,19 +19,13 @@
 #define NGX_CMD_REOPEN         5
 
 
-typedef struct {
-    int           argc;
-    char *const  *argv;
-} ngx_master_ctx_t;
-
-
 #define NGX_PROCESS_SINGLE   0
 #define NGX_PROCESS_MASTER   1
 #define NGX_PROCESS_WORKER   2
 
 
-void ngx_master_process_cycle(ngx_cycle_t *cycle, ngx_master_ctx_t *ctx);
-void ngx_single_process_cycle(ngx_cycle_t *cycle, ngx_master_ctx_t *ctx);
+void ngx_master_process_cycle(ngx_cycle_t *cycle);
+void ngx_single_process_cycle(ngx_cycle_t *cycle);
 
 
 extern ngx_uint_t      ngx_process;
diff --git a/src/os/unix/ngx_setproctitle.c b/src/os/unix/ngx_setproctitle.c
new file mode 100644
index 0000000..6ac8707
--- /dev/null
+++ b/src/os/unix/ngx_setproctitle.c
@@ -0,0 +1,143 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#if (NGX_SETPROCTITLE_USES_ENV)
+
+/*
+ * To change the process title in Linux and Solaris we have to set argv[1]
+ * to NULL and to copy the title to the same place where the argv[0] points to.
+ * However, argv[0] may be too small to hold a new title.  Fortunately, Linux
+ * and Solaris store argv[] and environ[] one after another.  So we should
+ * ensure that is the continuous memory and then we allocate the new memory
+ * for environ[] and copy it.  After this we could use the memory starting
+ * from argv[0] for our process title.
+ *
+ * The Solaris's standard /bin/ps does not show the changed process title.
+ * You have to use "/usr/ucb/ps -w" instead.  Besides, the UCB ps dos not
+ * show a new title if its length less than the origin command line length.
+ * To avoid it we append to a new title the origin command line in the
+ * parenthesis.
+ */
+
+extern char **environ;
+
+static char *ngx_os_argv_last;
+
+ngx_int_t  ngx_init_setproctitle(ngx_log_t *log)
+{
+    char        *p;
+    size_t       size;
+    ngx_uint_t   i;
+
+    size = 0;
+
+    for (i = 0; environ[i]; i++) {
+        size += ngx_strlen(environ[i]) + 1;
+    }
+
+    if (!(p = ngx_alloc(size, log))) {
+        return NGX_ERROR;
+    }
+
+    ngx_os_argv_last = ngx_os_argv[0];
+
+    for (i = 0; ngx_os_argv[i]; i++) {
+        if (ngx_os_argv_last == ngx_os_argv[i]) {
+            ngx_os_argv_last = ngx_os_argv[i] + ngx_strlen(ngx_os_argv[i]) + 1;
+        }
+    }
+
+    for (i = 0; environ[i]; i++) {
+        if (ngx_os_argv_last == environ[i]) {
+
+            size = ngx_strlen(environ[i]) + 1;
+            ngx_os_argv_last = environ[i] + size;
+
+            ngx_cpystrn(p, environ[i], size);
+            environ[i] = p;
+            p += size;
+        }
+    }
+
+    ngx_os_argv_last--;
+
+    return NGX_OK;
+}
+
+
+void ngx_setproctitle(char *title)
+{
+    u_char     *p;
+
+#if (SOLARIS)
+
+    ngx_int_t   i;
+    size_t      size;
+
+#endif
+
+    ngx_os_argv[1] = NULL;
+
+    p = ngx_cpystrn((u_char *) ngx_os_argv[0], "nginx: ",
+                    ngx_os_argv_last - ngx_os_argv[0]);
+
+    p = ngx_cpystrn(p, (u_char *) title, ngx_os_argv_last - (char *) p);
+
+#if (SOLARIS)
+
+    size = 0;
+
+    for (i = 0; i < ngx_argc; i++) {
+        size += ngx_strlen(ngx_argv[i]) + 1;
+    }
+
+    if (size > (size_t) ((char *) p - ngx_os_argv[0])) {
+
+        /*
+         * ngx_setproctitle() is too rare operation so we use
+         * the non-optimized copies
+         */
+
+        p = ngx_cpystrn(p, (u_char *) " (", ngx_os_argv_last - (char *) p);
+
+        for (i = 0; i < ngx_argc; i++) {
+            p = ngx_cpystrn(p, (u_char *) ngx_argv[i],
+                            ngx_os_argv_last - (char *) p);
+            p = ngx_cpystrn(p, (u_char *) " ", ngx_os_argv_last - (char *) p);
+        }
+
+        if (*(p - 1) == ' ') {
+            *(p - 1) = ')';
+        }
+    }
+
+#endif
+
+    if (ngx_os_argv_last - (char *) p) {
+        ngx_memset(p, NGX_SETPROCTITLE_PAD, ngx_os_argv_last - (char *) p);
+    }
+
+    ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
+                   "setproctitle: \"%s\"", ngx_os_argv[0]);
+}
+
+
+#elif !defined(ngx_setproctitle)
+
+ngx_int_t  ngx_init_setproctitle(ngx_log_t *log)
+{
+    return NGX_OK;
+}
+
+void ngx_setproctitle(char *title)
+{
+}
+
+#endif
diff --git a/src/os/unix/ngx_socket.c b/src/os/unix/ngx_socket.c
index f97ab41..3e188bd 100644
--- a/src/os/unix/ngx_socket.c
+++ b/src/os/unix/ngx_socket.c
@@ -16,7 +16,7 @@
  * ioctl() and fcntl() are syscalls on at least FreeBSD 2.x, Linux 2.2
  * and Solaris 7.
  *
- * ioctl() in Linux 2.4 and 2.6 uses BKL, however fcntl(F_SETFL) uses it too.
+ * ioctl() in Linux 2.4 and 2.6 uses BKL, however, fcntl(F_SETFL) uses it too.
  */
 
 
diff --git a/src/os/unix/ngx_solaris.h b/src/os/unix/ngx_solaris.h
index 36f3cb9..705cd57 100644
--- a/src/os/unix/ngx_solaris.h
+++ b/src/os/unix/ngx_solaris.h
@@ -8,6 +8,10 @@
 #define _NGX_SOLARIS_H_INCLUDED_
 
 
+ngx_int_t  ngx_init_setproctitle(ngx_log_t *log);
+void ngx_setproctitle(char *title);
+
+
 ngx_chain_t *ngx_solaris_sendfilev_chain(ngx_connection_t *c, ngx_chain_t *in,
                                          off_t limit);
 
diff --git a/src/os/unix/ngx_solaris_config.h b/src/os/unix/ngx_solaris_config.h
index 6cbfcc2..96c119c 100644
--- a/src/os/unix/ngx_solaris_config.h
+++ b/src/os/unix/ngx_solaris_config.h
@@ -40,10 +40,10 @@
 
 #include <sys/socket.h>
 #include <netinet/in.h>
+#include <netinet/tcp.h>        /* TCP_NODELAY */
 #include <arpa/inet.h>
 #include <netdb.h>
 
-#include <sys/sendfile.h>
 #include <sys/systeminfo.h>
 #include <limits.h>             /* IOV_MAX */
 #include <inttypes.h>
@@ -64,6 +64,11 @@
 #endif
 
 
+#if (HAVE_SENDFILE)
+#include <sys/sendfile.h>
+#endif
+
+
 #if (HAVE_AIO)
 #include <aio.h>
 #endif
@@ -80,7 +85,16 @@
 #endif
 
 
-#define ngx_setproctitle(title)
+#ifndef HAVE_SO_SNDLOWAT
+/* setsockopt(SO_SNDLOWAT) returns error "Option not supported by protocol" */
+#define HAVE_SO_SNDLOWAT         0
+#endif
+
+
+#ifndef NGX_SETPROCTITLE_USES_ENV
+#define NGX_SETPROCTITLE_USES_ENV  1
+#define NGX_SETPROCTITLE_PAD       ' '
+#endif
 
 
 #endif /* _NGX_SOLARIS_CONFIG_H_INCLUDED_ */
diff --git a/src/os/unix/ngx_solaris_init.c b/src/os/unix/ngx_solaris_init.c
index a743ab5..c671197 100644
--- a/src/os/unix/ngx_solaris_init.c
+++ b/src/os/unix/ngx_solaris_init.c
@@ -53,6 +53,9 @@
         return NGX_ERROR;
     }
 
+    ngx_init_setproctitle(log);
+
+
     return ngx_posix_init(log);
 }
 
diff --git a/src/os/unix/ngx_solaris_sendfilev_chain.c b/src/os/unix/ngx_solaris_sendfilev_chain.c
index a060dac..9430dc0 100644
--- a/src/os/unix/ngx_solaris_sendfilev_chain.c
+++ b/src/os/unix/ngx_solaris_sendfilev_chain.c
@@ -32,6 +32,10 @@
         return in;
     }
 
+    if (!c->sendfile) {
+        return ngx_writev_chain(c, in, limit);
+    }
+
     send = 0;
     complete = 0;
 
diff --git a/src/os/win32/ngx_process.c b/src/os/win32/ngx_process.c
index 7ec46f6..062c41c 100644
--- a/src/os/win32/ngx_process.c
+++ b/src/os/win32/ngx_process.c
@@ -8,6 +8,11 @@
 #include <ngx_core.h>
 
 
+int            ngx_argc;
+char         **ngx_argv;
+char         **ngx_os_argv;
+
+
 ngx_pid_t ngx_execute(ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx)
 {
     return /* STUB */ 0;
diff --git a/src/os/win32/ngx_process.h b/src/os/win32/ngx_process.h
index 402f31f..b9b4aeb 100644
--- a/src/os/win32/ngx_process.h
+++ b/src/os/win32/ngx_process.h
@@ -32,8 +32,11 @@
 #define ngx_sched_yield()  Sleep(0)
 
 
+extern int            ngx_argc;
+extern char         **ngx_argv;
+extern char         **ngx_os_argv;
 
-extern ngx_pid_t     ngx_pid;
+extern ngx_pid_t      ngx_pid;
 
 
 #endif /* _NGX_PROCESS_H_INCLUDED_ */
diff --git a/src/os/win32/ngx_process_cycle.c b/src/os/win32/ngx_process_cycle.c
index d597174..843c311 100644
--- a/src/os/win32/ngx_process_cycle.c
+++ b/src/os/win32/ngx_process_cycle.c
@@ -38,7 +38,7 @@
 
 
 
-void ngx_master_process_cycle(ngx_cycle_t *cycle, ngx_master_ctx_t *ctx)
+void ngx_master_process_cycle(ngx_cycle_t *cycle)
 {
     ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "master mode is not supported");
 
@@ -46,7 +46,7 @@
 }
 
 
-void ngx_single_process_cycle(ngx_cycle_t *cycle, ngx_master_ctx_t *ctx)
+void ngx_single_process_cycle(ngx_cycle_t *cycle)
 {
     ngx_int_t  i;
 
diff --git a/src/os/win32/ngx_process_cycle.h b/src/os/win32/ngx_process_cycle.h
index 10d6850..e80af0a 100644
--- a/src/os/win32/ngx_process_cycle.h
+++ b/src/os/win32/ngx_process_cycle.h
@@ -12,21 +12,13 @@
 #include <ngx_core.h>
 
 
-typedef struct {
-     ngx_file_t    pid;
-     u_char       *name;
-     int           argc;
-     char *const  *argv;
-} ngx_master_ctx_t;
-
-
 #define NGX_PROCESS_SINGLE   0
 #define NGX_PROCESS_MASTER   1
 #define NGX_PROCESS_WORKER   2
 
 
-void ngx_master_process_cycle(ngx_cycle_t *cycle, ngx_master_ctx_t *ctx);
-void ngx_single_process_cycle(ngx_cycle_t *cycle, ngx_master_ctx_t *ctx);
+void ngx_master_process_cycle(ngx_cycle_t *cycle);
+void ngx_single_process_cycle(ngx_cycle_t *cycle);
 
 
 extern ngx_uint_t      ngx_process;