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/core/nginx.c b/src/core/nginx.c
index 18f3ccc..9d91080 100644
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -11,7 +11,8 @@
 
 
 static ngx_int_t ngx_add_inherited_sockets(ngx_cycle_t *cycle);
-static ngx_int_t ngx_getopt(ngx_master_ctx_t *ctx, ngx_cycle_t *cycle);
+static ngx_int_t ngx_getopt(ngx_cycle_t *cycle, int argc, char *const *argv);
+static ngx_int_t ngx_save_argv(ngx_cycle_t *cycle, int argc, char *const *argv);
 static void *ngx_core_module_create_conf(ngx_cycle_t *cycle);
 static char *ngx_core_module_init_conf(ngx_cycle_t *cycle, void *conf);
 static char *ngx_set_user(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
@@ -96,13 +97,12 @@
 ngx_uint_t  ngx_max_module;
 
 
-int main(int argc, char *const *argv)
+int main(int argc, char *const *argv, char *const *envp)
 {
-    ngx_int_t          i;
-    ngx_log_t         *log;
-    ngx_cycle_t       *cycle, init_cycle;
-    ngx_core_conf_t   *ccf;
-    ngx_master_ctx_t   ctx;
+    ngx_int_t         i;
+    ngx_log_t        *log;
+    ngx_cycle_t      *cycle, init_cycle;
+    ngx_core_conf_t  *ccf;
 
 #if defined __FreeBSD__
     ngx_debug_init();
@@ -132,15 +132,15 @@
     init_cycle.log = log;
     ngx_cycle = &init_cycle;
 
-    ngx_memzero(&ctx, sizeof(ngx_master_ctx_t));
-    ctx.argc = argc;
-    ctx.argv = argv;
-
     if (!(init_cycle.pool = ngx_create_pool(1024, log))) {
         return 1;
     }
 
-    if (ngx_getopt(&ctx, &init_cycle) == NGX_ERROR) {
+    if (ngx_getopt(&init_cycle, argc, argv) == NGX_ERROR) {
+        return 1;
+    }
+
+    if (ngx_save_argv(&init_cycle, argc, argv) == NGX_ERROR) {
         return 1;
     }
 
@@ -219,10 +219,10 @@
 #endif
 
     if (ngx_process == NGX_PROCESS_MASTER) {
-        ngx_master_process_cycle(cycle, &ctx);
+        ngx_master_process_cycle(cycle);
 
     } else {
-        ngx_single_process_cycle(cycle, &ctx);
+        ngx_single_process_cycle(cycle);
     }
 
     return 0;
@@ -276,7 +276,7 @@
 
 ngx_pid_t ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv)
 {
-    char             *env[2], *var, *p;
+    char             *env[3], *var, *p;
     ngx_uint_t        i;
     ngx_pid_t         pid;
     ngx_exec_ctx_t    ctx;
@@ -300,7 +300,25 @@
     ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, "inherited: %s", var);
 
     env[0] = var;
+
+#if (NGX_SETPROCTITLE_USES_ENV)
+
+    /* allocate spare 300 bytes for the new binary process title */
+
+    env[1] = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+             "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+             "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+             "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+             "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
+
+    env[2] = NULL;
+
+#else
+
     env[1] = NULL;
+
+#endif
+
     ctx.envp = (char *const *) &env;
 
     pid = ngx_execute(cycle, &ctx);
@@ -311,38 +329,38 @@
 }
 
 
-static ngx_int_t ngx_getopt(ngx_master_ctx_t *ctx, ngx_cycle_t *cycle)
+static ngx_int_t ngx_getopt(ngx_cycle_t *cycle, int argc, char *const *argv)
 {
     ngx_int_t  i;
 
-    for (i = 1; i < ctx->argc; i++) {
-        if (ctx->argv[i][0] != '-') {
+    for (i = 1; i < argc; i++) {
+        if (argv[i][0] != '-') {
             ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
-                          "invalid option: \"%s\"", ctx->argv[i]);
+                          "invalid option: \"%s\"", argv[i]);
             return NGX_ERROR;
         }
 
-        switch (ctx->argv[i][1]) {
+        switch (argv[i][1]) {
 
         case 't':
             ngx_test_config = 1;
             break;
 
         case 'c':
-            if (ctx->argv[i + 1] == NULL) {
+            if (argv[i + 1] == NULL) {
                 ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
                               "the option: \"%s\" requires file name",
-                              ctx->argv[i]);
+                              argv[i]);
                 return NGX_ERROR;
             }
 
-            cycle->conf_file.data = (u_char *) ctx->argv[++i];
+            cycle->conf_file.data = (u_char *) argv[++i];
             cycle->conf_file.len = ngx_strlen(cycle->conf_file.data);
             break;
 
         default:
             ngx_log_error(NGX_LOG_EMERG, cycle->log, 0,
-                          "invalid option: \"%s\"", ctx->argv[i]);
+                          "invalid option: \"%s\"", argv[i]);
             return NGX_ERROR;
         }
     }
@@ -360,6 +378,43 @@
 }
 
 
+static ngx_int_t ngx_save_argv(ngx_cycle_t *cycle, int argc, char *const *argv)
+{
+    size_t     len;
+    ngx_int_t  i;
+
+    ngx_os_argv = (char **) argv;
+
+    ngx_argc = argc;
+
+#if __FreeBSD__
+
+    ngx_argv = (char **) argv;
+
+#else
+
+    if (!(ngx_argv = ngx_alloc((argc + 1) * sizeof(char *), cycle->log))) {
+        return NGX_ERROR;
+    }
+
+    for (i = 0; i < argc; i++) {
+        len = ngx_strlen(argv[i]) + 1;
+
+        if (!(ngx_argv[i] = ngx_alloc(len, cycle->log))) {
+            return NGX_ERROR;
+        }
+
+        ngx_cpystrn((u_char *) ngx_argv[i], (u_char *) argv[i], len);
+    }
+
+    ngx_argv[i] = NULL;
+
+#endif
+
+    return NGX_OK;
+}
+
+
 static void *ngx_core_module_create_conf(ngx_cycle_t *cycle)
 {
     ngx_core_conf_t  *ccf;
@@ -407,6 +462,7 @@
 
 #if !(WIN32)
 
+#if 0
     if (ccf->user == (uid_t) NGX_CONF_UNSET) {
 
         pwd = getpwnam("nobody");
@@ -427,10 +483,11 @@
 
         ccf->group = grp->gr_gid;
     }
+#endif
 
     if (ccf->pid.len == 0) {
         ccf->pid.len = sizeof(NGX_PID_PATH) - 1;
-        ccf->pid.data = NGX_PID_PATH;
+        ccf->pid.data = (u_char *) NGX_PID_PATH;
     }
 
     if (ngx_conf_full_name(cycle, &ccf->pid) == NGX_ERROR) {
@@ -478,7 +535,7 @@
     pwd = getpwnam((const char *) value[1].data);
     if (pwd == NULL) {
         ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
-                           "getpwnam(%s) failed", value[1].data);
+                           "getpwnam(\"%s\") failed", value[1].data);
         return NGX_CONF_ERROR;
     }
 
@@ -491,7 +548,7 @@
     grp = getgrnam((const char *) value[2].data);
     if (grp == NULL) {
         ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
-                           "getgrnam(%s) failed", value[1].data);
+                           "getgrnam(\"%s\") failed", value[2].data);
         return NGX_CONF_ERROR;
     }
 
diff --git a/src/core/nginx.h b/src/core/nginx.h
index 66b5c33..82545e5 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VER          "nginx/0.1.0"
+#define NGINX_VER          "nginx/0.1.1"
 
 #define NGINX_VAR          "NGINX"
 #define NGX_NEWPID_EXT     ".newbin"
diff --git a/src/core/ngx_buf.c b/src/core/ngx_buf.c
index 72b558b..a536c04 100644
--- a/src/core/ngx_buf.c
+++ b/src/core/ngx_buf.c
@@ -152,7 +152,8 @@
             continue;
         }
 
-        (*busy)->buf->pos = (*busy)->buf->last = (*busy)->buf->start;
+        (*busy)->buf->pos = (*busy)->buf->start;
+        (*busy)->buf->last = (*busy)->buf->start;
 
         tl = *busy;
         *busy = (*busy)->next;
diff --git a/src/core/ngx_conf_file.h b/src/core/ngx_conf_file.h
index fc05337..3a3db52 100644
--- a/src/core/ngx_conf_file.h
+++ b/src/core/ngx_conf_file.h
@@ -57,7 +57,7 @@
 
 
 #define NGX_CONF_OK          NULL
-#define NGX_CONF_ERROR       (void *) -1
+#define NGX_CONF_ERROR       (char *) -1
 
 #define NGX_CONF_BLOCK_DONE  1
 #define NGX_CONF_FILE_DONE   2
diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c
index 698342f..19f5629 100644
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -313,18 +313,6 @@
         ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed");
         return;
     }
-    
-#if (NGX_OPENSSL)
-
-    if (c->ssl) {
-        if (ngx_ssl_shutdown(c) == NGX_AGAIN) {
-            c->read->event_handler = ngx_ssl_close_handler;
-            c->write->event_handler = ngx_ssl_close_handler;
-            return;
-        }
-    }
-    
-#endif
 
     if (c->read->timer_set) {
         ngx_del_timer(c->read);
diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h
index 7a03450..57c7a33 100644
--- a/src/core/ngx_connection.h
+++ b/src/core/ngx_connection.h
@@ -120,7 +120,12 @@
     unsigned            single_connection:1;
     unsigned            unexpected_eof:1;
     unsigned            timedout:1;
+
+    unsigned            sendfile:1;
+    unsigned            sndlowat:1;
+    unsigned            tcp_nodelay:1;
     signed              tcp_nopush:2;
+
 #if (HAVE_IOCP)
     unsigned            accept_context_updated:1;
 #endif
diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c
index ed4d60f..38f4ad5 100644
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -615,6 +615,9 @@
     ngx_uint_t        i;
     ngx_list_part_t  *part;
     ngx_open_file_t  *file;
+#if !(WIN32)
+    ngx_file_info_t   fi;
+#endif
 
     part = &cycle->open_files.part;
     file = part->elts;
@@ -672,6 +675,35 @@
                                   file[i].name.data);
                 }
             }
+
+            if (ngx_file_info((const char *) file[i].name.data, &fi) == -1) {
+                ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+                              ngx_file_info_n " \"%s\" failed",
+                              file[i].name.data);
+
+                if (ngx_close_file(fd) == NGX_FILE_ERROR) {
+                    ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+                                  ngx_close_file_n " \"%s\" failed",
+                                  file[i].name.data);
+                }
+            }
+
+            if ((fi.st_mode & (S_IRUSR|S_IWUSR)) != (S_IRUSR|S_IWUSR)) {
+
+                fi.st_mode |= (S_IRUSR|S_IWUSR);
+
+                if (chmod((const char *) file[i].name.data, fi.st_mode) == -1) {
+                    ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+                                  "chmod \"%s\" failed",
+                                  file[i].name.data);
+
+                    if (ngx_close_file(fd) == NGX_FILE_ERROR) {
+                        ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
+                                      ngx_close_file_n " \"%s\" failed",
+                                      file[i].name.data);
+                    }
+                }
+            }
         }
 
         if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c
index f0d66cb..74e38e1 100644
--- a/src/core/ngx_output_chain.c
+++ b/src/core/ngx_output_chain.c
@@ -228,8 +228,15 @@
         src->pos += size;
         dst->last += size;
 
-        if (src->in_file) {
+        if (src->in_file && sendfile) {
+            dst->in_file = 1;
+            dst->file = src->file;
+            dst->file_pos = src->file_pos;
             src->file_pos += size;
+            dst->file_last = src->file_pos;
+
+        } else {
+            dst->in_file = 0;
         }
 
         if (src->last_buf && src->pos == src->last) {
@@ -258,11 +265,18 @@
             }
         }
 
-        src->file_pos += n;
         dst->last += n;
 
-        if (!sendfile) {
+        if (sendfile) {
+            dst->in_file = 1;
+            dst->file = src->file;
+            dst->file_pos = src->file_pos;
+            src->file_pos += size;
+            dst->file_last = src->file_pos;
+
+        } else {
             dst->in_file = 0;
+            src->file_pos += n;
         }
 
         if (src->last_buf && src->file_pos == src->file_last) {
diff --git a/src/core/ngx_palloc.c b/src/core/ngx_palloc.c
index ee4d224..e41e971 100644
--- a/src/core/ngx_palloc.c
+++ b/src/core/ngx_palloc.c
@@ -77,13 +77,14 @@
     ngx_pool_large_t  *large, *last;
 
     if (size <= (size_t) NGX_MAX_ALLOC_FROM_POOL
-        && size <= (size_t) (pool->end - (char *) pool) - sizeof(ngx_pool_t))
+        && size <= (size_t) (pool->end - (char *) pool)
+                                     - (size_t) ngx_align(sizeof(ngx_pool_t)))
     {
         for (p = pool, n = pool->next; /* void */; p = n, n = n->next) {
             m = ngx_align(p->last);
 
             if ((size_t) (p->end - m) >= size) {
-                p->last = m + size ;
+                p->last = m + size;
 
                 return m;
             }
@@ -100,8 +101,8 @@
         }
 
         p->next = n;
-        m = n->last;
-        n->last += size;
+        m = ngx_align(n->last);
+        n->last = m + size;
 
         return m;
     }
diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c
index 3d6a9eb..32a4079 100644
--- a/src/core/ngx_string.c
+++ b/src/core/ngx_string.c
@@ -128,7 +128,7 @@
 }
 
 
-void ngx_encode_base64(ngx_str_t *src, ngx_str_t *dst)
+void ngx_encode_base64(ngx_str_t *dst, ngx_str_t *src)
 {
     u_char         *d, *s;
     size_t          len;
@@ -168,7 +168,7 @@
 }
 
 
-ngx_int_t ngx_decode_base64(ngx_str_t *src, ngx_str_t *dst)
+ngx_int_t ngx_decode_base64(ngx_str_t *dst, ngx_str_t *src)
 {
     size_t          len;
     u_char         *d, *s;
@@ -231,54 +231,55 @@
 }
 
 
-#if 0
-char *ngx_psprintf(ngx_pool_t *p, const char *fmt, ...)
+ngx_int_t ngx_escape_uri(u_char *dst, u_char *src, size_t size)
 {
-    va_list    args;
+    ngx_int_t         n;
+    ngx_uint_t        i;
+    static u_char     hex[] = "0123456789abcdef";
+    static uint32_t   escape[] =
+        { 0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
 
-    va_start(args, fmt);
+                      /* ?>=< ;:98 7654 3210  /.-, +*)( '&%$ #"!  */
+          0x80000021, /* 1000 0000 0000 0000  0000 0000 0010 0001 */
 
-    while (*fmt) {
-         switch(*fmt++) {
-         case '%':
-             switch(*fmt++) {
-             case 's':
-                 s = va_arg(args, char *);
-                 n += ngx_strlen(s);
-                 break;
+                      /* _^]\ [ZYX WVUT SRQP  ONML KJIH GFED CBA@ */
+          0x00000000, /* 0000 0000 0000 0000  0000 0000 0000 0000 */
 
-             default:
-                 n++;
-         }
-         default:
-             n++;
-         }
+                      /*  ~}| {zyx wvut srqp  onml kjih gfed cba` */
+          0x80000000, /* 1000 0000 0000 0000  0000 0000 0000 0000 */
+
+          0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
+          0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
+          0xffffffff, /* 1111 1111 1111 1111  1111 1111 1111 1111 */
+          0xffffffff  /* 1111 1111 1111 1111  1111 1111 1111 1111 */ };
+
+    if (dst == NULL) {
+
+        /* find the number of the characters to be escaped */
+
+        n  = 0;
+
+        for (i = 0; i < size; i++) {
+            if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
+                n++;
+            }
+            src++;
+        }
+
+        return n;
     }
 
-    str = ngx_palloc(p, n);
+    for (i = 0; i < size; i++) {
+        if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
+            *dst++ = '%';
+            *dst++ = hex[*src >> 4];
+            *dst++ = hex[*src & 0xf];
+            src++;
 
-    va_start(args, fmt);
-
-    for (i = 0; i < n; i++) {
-         switch(*fmt++) {
-         case '%':
-             switch(*fmt++) {
-             case 's':
-                 s = va_arg(args, char *);
-                 while (str[i++] = s);
-                 break;
-
-             default:
-                 n++;
-         }
-         default:
-             str[i] = *fmt;
-         }
+        } else {
+            *dst++ = *src++;
+        }
     }
 
-    len += ngx_vsnprintf(errstr + len, sizeof(errstr) - len - 1, fmt, args);
-
-    va_end(args);
-
+    return NGX_OK;
 }
-#endif
diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h
index fbc8875..e8e69c0 100644
--- a/src/core/ngx_string.h
+++ b/src/core/ngx_string.h
@@ -60,6 +60,7 @@
  * icc may also inline several mov's of a zeroed register for small blocks.
  */
 #define ngx_memzero(buf, n)       memset(buf, 0, n)
+#define ngx_memset(buf, c, n)     memset(buf, c, n)
 
 /* msvc and icc compile memcpy() to the inline "rep movs" */
 #define ngx_memcpy(dst, src, n)   memcpy(dst, src, n)
@@ -80,8 +81,9 @@
 #define ngx_base64_encoded_length(len)  (((len + 2) / 3) * 4)
 #define ngx_base64_decoded_length(len)  (((len + 3) / 4) * 3)
 
-void ngx_encode_base64(ngx_str_t *src, ngx_str_t *dst);
-ngx_int_t ngx_decode_base64(ngx_str_t *src, ngx_str_t *dst);
+void ngx_encode_base64(ngx_str_t *dst, ngx_str_t *src);
+ngx_int_t ngx_decode_base64(ngx_str_t *dst, ngx_str_t *src);
+ngx_int_t ngx_escape_uri(u_char *dst, u_char *src, size_t size);
 
 
 #define  ngx_qsort                qsort