changeset 278:704622b2528a NGINX_0_5_9

nginx 0.5.9 *) Change: now the ngx_http_memcached_module uses the $memcached_key variable value as a key. *) Feature: the $memcached_key variable. *) Feature: the "clean" parameter in the "client_body_in_file_only" directive. *) Feature: the "env" directive. *) Feature: the "sendfile" directive is available inside the "if" block. *) Feature: now on failure of the writing to access nginx logs a message to error_log, but not more often than once a minute. *) Bugfix: the "access_log off" directive did not always turn off the logging.
author Igor Sysoev <http://sysoev.ru>
date Thu, 25 Jan 2007 00:00:00 +0300
parents b3aec7787b8e
children 0188c538bd60
files CHANGES CHANGES.ru src/core/nginx.c src/core/nginx.h src/core/ngx_cycle.h src/core/ngx_file.c src/core/ngx_file.h src/core/ngx_palloc.c src/core/ngx_palloc.h src/http/modules/ngx_http_dav_module.c src/http/modules/ngx_http_log_module.c src/http/modules/ngx_http_memcached_module.c src/http/modules/perl/nginx.pm src/http/modules/perl/nginx.xs src/http/modules/perl/ngx_http_perl_module.c src/http/ngx_http_core_module.c src/http/ngx_http_request.h src/http/ngx_http_request_body.c src/os/unix/ngx_process_cycle.c
diffstat 19 files changed, 439 insertions(+), 158 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,25 @@
 
+Changes with nginx 0.5.9                                         25 Jan 2007
+
+    *) Change: now the ngx_http_memcached_module uses the $memcached_key 
+       variable value as a key.
+
+    *) Feature: the $memcached_key variable.
+
+    *) Feature: the "clean" parameter in the "client_body_in_file_only" 
+       directive.
+
+    *) Feature: the "env" directive.
+
+    *) Feature: the "sendfile" directive is available inside the "if" block.
+
+    *) Feature: now on failure of the writing to access nginx logs a 
+       message to error_log, but not more often than once a minute.
+
+    *) Bugfix: the "access_log off" directive did not always turn off the 
+       logging.
+
+
 Changes with nginx 0.5.8                                         19 Jan 2007
 
     *) Bugfix: a segmentation fault might occur if 
@@ -737,7 +758,7 @@ Changes with nginx 0.3.38               
 
     *) Feature: the "client_body_in_file_only" directive.
 
-    *) Workaround: no on disk overflow nginx tries to write access logs 
+    *) Workaround: now on disk overflow nginx tries to write access logs 
        once a second only.
        Thanks to Anton Yuzhaninov and Maxim Dounin.
 
@@ -834,7 +855,7 @@ Changes with nginx 0.3.31               
 
     *) Workaround: for MacOSX 64-bit kernel kqueue millisecond timeout 
        bug.
-       Thanks Andrei Nigmatulin.
+       Thanks to Andrei Nigmatulin.
 
     *) Bugfix: if there were several "listen" directives listening one 
        various addresses inside one server, then server names like 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,24 @@
 
+Изменения в nginx 0.5.9                                           25.01.2007
+
+    *) Изменение: модуль ngx_http_memcached_module теперь в качестве ключа 
+       использует значение переменной $memcached_key.
+
+    *) Добавление: переменная $memcached_key.
+
+    *) Добавление: параметр clean в директиве client_body_in_file_only.
+
+    *) Добавление: директива env.
+
+    *) Добавление: директива sendfile работает внутри блока if.
+
+    *) Добавление: теперь при ошибке записи в access_log nginx записывает 
+       сообщение в error_log, но не чаще одного раза в минуту.
+
+    *) Исправление: директива "access_log off" не всегда запрещала запись в 
+       лог.
+
+
 Изменения в nginx 0.5.8                                           19.01.2007
 
     *) Исправление: если использовалась директива 
@@ -11,8 +31,9 @@
        делался переход к следующему бэкенду.
 
     *) Исправление: если при использовании директивы "proxy_buffering off" 
-       соединение с клиентом было неактивно, то оно закрывалось по таймуту, 
-       заданному директивой send_timeout; ошибка появилась в 0.4.7.
+       соединение с клиентом было неактивно, то оно закрывалось по 
+       таймауту, заданному директивой send_timeout; ошибка появилась в 
+       0.4.7.
 
     *) Исправление: если при использовании метода epoll клиент закрывал 
        преждевременно соединение со своей стороны, то nginx закрывал это 
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -16,6 +16,7 @@ static ngx_int_t ngx_save_argv(ngx_cycle
 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);
+static char *ngx_set_env(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 static char *ngx_set_priority(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 static char *ngx_set_cpu_affinity(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
@@ -128,6 +129,13 @@ static ngx_command_t  ngx_core_commands[
       offsetof(ngx_core_conf_t, working_directory),
       NULL },
 
+    { ngx_string("env"),
+      NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
+      ngx_set_env,
+      0,
+      0,
+      NULL },
+
 #if (NGX_THREADS)
 
     { ngx_string("worker_threads"),
@@ -178,7 +186,7 @@ ngx_uint_t  ngx_max_module;
 static ngx_uint_t  ngx_show_version;
 static ngx_uint_t  ngx_show_configure;
 
-static char  *ngx_null_environ = NULL;
+static char **ngx_os_environ;
 
 
 int ngx_cdecl
@@ -275,8 +283,6 @@ main(int argc, char *const *argv)
         return 1;
     }
 
-    environ = &ngx_null_environ;
-
     ngx_max_module = 0;
     for (i = 0; ngx_modules[i]; i++) {
         ngx_modules[i]->index = ngx_max_module++;
@@ -407,21 +413,128 @@ ngx_add_inherited_sockets(ngx_cycle_t *c
 }
 
 
+char **
+ngx_set_environment(ngx_cycle_t *cycle, ngx_uint_t *last)
+{
+    char             **p, **env;
+    ngx_str_t         *var;
+    ngx_uint_t         i, n;
+    ngx_core_conf_t   *ccf;
+
+    ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
+
+    if (last) {
+        n = *last;
+
+    } else {
+        if (ccf->environment) {
+            return ccf->environment;
+        }
+
+        n = 0;
+    }
+
+    var = ccf->env.elts;
+
+    for (i = 0; i < ccf->env.nelts; i++) {
+        if (ngx_strcmp(var[i].data, "TZ") == 0
+            || ngx_strncmp(var[i].data, "TZ=", 3) == 0)
+        {
+            goto tz_found;
+        }
+    }
+
+    var = ngx_array_push(&ccf->env);
+
+    var->len = 2;
+    var->data = (u_char *) "TZ";
+
+    var = ccf->env.elts;
+
+tz_found:
+
+    for (i = 0; i < ccf->env.nelts; i++) {
+
+        if (var[i].data[var[i].len] == '=') {
+            n++;
+            continue;
+        }
+
+        for (p = ngx_os_environ; *p; p++) {
+
+            if (ngx_strncmp(*p, var[i].data, var[i].len) == 0
+                && (*p)[var[i].len] == '=')
+            {
+                n++;
+                break;
+            }
+        }
+    }
+
+    if (last) {
+        *last = n;
+        env = ngx_alloc((n + 1) * sizeof(char *), cycle->log);
+
+    } else {
+        env = ngx_palloc(cycle->pool, (n + 1) * sizeof(char *));
+    }
+
+    if (env == NULL) {
+        return NULL;
+    }
+
+    n = 0;
+
+    for (i = 0; i < ccf->env.nelts; i++) {
+
+        if (var[i].data[var[i].len] == '=') {
+            env[n++] = (char *) var[i].data;
+            continue;
+        }
+
+        for (p = ngx_os_environ; *p; p++) {
+
+            if (ngx_strncmp(*p, var[i].data, var[i].len) == 0
+                && (*p)[var[i].len] == '=')
+            {
+                env[n++] = *p;
+                break;
+            }
+        }
+    }
+
+    env[n] = NULL;
+
+    if (last == NULL) {
+        ccf->environment = env;
+        environ = env;
+    }
+
+    return env;
+}
+
+
 ngx_pid_t
 ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv)
 {
-    char             *env[3], *var;
-    u_char           *p;
-    ngx_uint_t        i;
-    ngx_pid_t         pid;
-    ngx_exec_ctx_t    ctx;
-    ngx_core_conf_t  *ccf;
-    ngx_listening_t  *ls;
+    char             **env, *var;
+    u_char            *p;
+    ngx_uint_t         i, n;
+    ngx_pid_t          pid;
+    ngx_exec_ctx_t     ctx;
+    ngx_core_conf_t   *ccf;
+    ngx_listening_t   *ls;
 
     ctx.path = argv[0];
     ctx.name = "new binary process";
     ctx.argv = argv;
 
+    n = 2;
+    env = ngx_set_environment(cycle, &n);
+    if (env == NULL) {
+        return NGX_INVALID_PID;
+    }
+
     var = ngx_alloc(sizeof(NGINX_VAR)
                     + cycle->listening.nelts * (NGX_INT32_LEN + 1) + 2,
                     cycle->log);
@@ -435,40 +548,42 @@ ngx_exec_new_binary(ngx_cycle_t *cycle, 
 
     *p = '\0';
 
-    ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, "inherited: %s", var);
-
-    env[0] = var;
+    env[n++] = var;
 
 #if (NGX_SETPROCTITLE_USES_ENV)
 
     /* allocate the spare 300 bytes for the new binary process title */
 
-    env[1] = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
-             "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
-             "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
-             "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
-             "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
-
-    env[2] = NULL;
-
-#else
-
-    env[1] = NULL;
+    env[n++] = "SPARE=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+               "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+               "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+               "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+               "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
 
 #endif
 
-    ctx.envp = (char *const *) &env;
+    env[n] = NULL;
+
+#if (NGX_DEBUG)
+    {
+    char  **e;
+    for (e = env; *e; e++) {
+        ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0, "env: %s", *e);
+    }
+    }
+#endif
+
+    ctx.envp = (char *const *) env;
 
     ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
 
-    if (ngx_rename_file(ccf->pid.data, ccf->oldpid.data)
-        != NGX_OK)
-    {
+    if (ngx_rename_file(ccf->pid.data, ccf->oldpid.data) != NGX_OK) {
         ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                       ngx_rename_file_n " %s to %s failed "
                       "before executing new binary process \"%s\"",
                       ccf->pid.data, ccf->oldpid.data, argv[0]);
 
+        ngx_free(env);
         ngx_free(var);
 
         return NGX_INVALID_PID;
@@ -477,16 +592,15 @@ ngx_exec_new_binary(ngx_cycle_t *cycle, 
     pid = ngx_execute(cycle, &ctx);
 
     if (pid == NGX_INVALID_PID) {
-        if (ngx_rename_file(ccf->oldpid.data, ccf->pid.data)
-            != NGX_OK)
-        {
+        if (ngx_rename_file(ccf->oldpid.data, ccf->pid.data) != NGX_OK) {
             ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
-                          ngx_rename_file_n " %s back to %s failed "
-                          "after try to executing new binary process \"%s\"",
+                          ngx_rename_file_n " %s back to %s failed after "
+                          "the try to execute the new binary process \"%s\"",
                           ccf->oldpid.data, ccf->pid.data, argv[0]);
         }
     }
 
+    ngx_free(env);
     ngx_free(var);
 
     return pid;
@@ -588,6 +702,8 @@ ngx_save_argv(ngx_cycle_t *cycle, int ar
 
 #endif
 
+    ngx_os_environ = environ;
+
     return NGX_OK;
 }
 
@@ -631,6 +747,12 @@ ngx_core_module_create_conf(ngx_cycle_t 
     ccf->thread_stack_size = NGX_CONF_UNSET_SIZE;
 #endif
 
+    if (ngx_array_init(&ccf->env, cycle->pool, 1, sizeof(ngx_str_t))
+        != NGX_OK)
+    {
+        return NULL;
+    }
+
     return ccf;
 }
 
@@ -641,9 +763,9 @@ ngx_core_module_init_conf(ngx_cycle_t *c
     ngx_core_conf_t  *ccf = conf;
 
 #if !(NGX_WIN32)
-    ngx_str_t         lock_file;
-    struct passwd    *pwd;
-    struct group     *grp;
+    ngx_str_t       lock_file;
+    struct group   *grp;
+    struct passwd  *pwd;
 #endif
 
     ngx_conf_init_value(ccf->daemon, 1);
@@ -830,6 +952,36 @@ ngx_set_user(ngx_conf_t *cf, ngx_command
 
 
 static char *
+ngx_set_env(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_core_conf_t  *ccf = conf;
+
+    ngx_str_t   *value, *var;
+    ngx_uint_t   i;
+
+    var = ngx_array_push(&ccf->env);
+    if (var == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    value = cf->args->elts;
+    *var = value[1];
+
+    for (i = 0; i < value[1].len; i++) {
+
+        if (value[1].data[i] == '=') {
+
+            var->len = i;
+
+            return NGX_CONF_OK;
+        }
+    }
+
+    return NGX_CONF_OK;
+}
+
+
+static char *
 ngx_set_priority(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     ngx_core_conf_t  *ccf = conf;
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VERSION      "0.5.8"
+#define NGINX_VERSION      "0.5.9"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_cycle.h
+++ b/src/core/ngx_cycle.h
@@ -93,6 +93,9 @@ typedef struct {
      ngx_str_t                pid;
      ngx_str_t                oldpid;
 
+     ngx_array_t              env;
+     char                   **environment;
+
 #if (NGX_THREADS)
      ngx_int_t                worker_threads;
      size_t                   thread_stack_size;
@@ -113,6 +116,7 @@ ngx_cycle_t *ngx_init_cycle(ngx_cycle_t 
 ngx_int_t ngx_create_pidfile(ngx_str_t *name, ngx_log_t *log);
 void ngx_delete_pidfile(ngx_cycle_t *cycle);
 void ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user);
+char **ngx_set_environment(ngx_cycle_t *cycle, ngx_uint_t *last);
 ngx_pid_t ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv);
 u_long ngx_get_cpu_affinity(ngx_uint_t n);
 ngx_shm_zone_t *ngx_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name,
--- a/src/core/ngx_file.c
+++ b/src/core/ngx_file.c
@@ -19,7 +19,7 @@ ngx_write_chain_to_temp_file(ngx_temp_fi
 
     if (tf->file.fd == NGX_INVALID_FILE) {
         rc = ngx_create_temp_file(&tf->file, tf->path, tf->pool,
-                                  tf->persistent, tf->access);
+                                  tf->persistent, tf->clean, tf->access);
 
         if (rc == NGX_ERROR || rc == NGX_AGAIN) {
             return rc;
@@ -37,7 +37,7 @@ ngx_write_chain_to_temp_file(ngx_temp_fi
 
 ngx_int_t
 ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path, ngx_pool_t *pool,
-    ngx_uint_t persistent, ngx_uint_t access)
+    ngx_uint_t persistent, ngx_uint_t clean, ngx_uint_t access)
 {
     ngx_err_t                 err;
     ngx_atomic_uint_t         n;
@@ -79,7 +79,7 @@ ngx_create_temp_file(ngx_file_t *file, n
 
         if (file->fd != NGX_INVALID_FILE) {
 
-            cln->handler = ngx_pool_cleanup_file;
+            cln->handler = clean ? ngx_pool_delete_file : ngx_pool_cleanup_file;
             clnf = cln->data;
 
             clnf->fd = file->fd;
--- a/src/core/ngx_file.h
+++ b/src/core/ngx_file.h
@@ -53,6 +53,7 @@ typedef struct {
 
     unsigned            log_level:8;
     unsigned            persistent:1;
+    unsigned            clean:1;
 } ngx_temp_file_t;
 
 
@@ -81,7 +82,8 @@ struct ngx_tree_ctx_s {
 
 ssize_t ngx_write_chain_to_temp_file(ngx_temp_file_t *tf, ngx_chain_t *chain);
 ngx_int_t ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path,
-    ngx_pool_t *pool, ngx_uint_t persistent,ngx_uint_t access);
+    ngx_pool_t *pool, ngx_uint_t persistent, ngx_uint_t clean,
+    ngx_uint_t access);
 void ngx_create_hashed_filename(ngx_file_t *file, ngx_path_t *path);
 ngx_int_t ngx_create_path(ngx_file_t *file, ngx_path_t *path);
 ngx_err_t ngx_create_full_path(u_char *dir, ngx_uint_t access);
--- a/src/core/ngx_palloc.c
+++ b/src/core/ngx_palloc.c
@@ -243,6 +243,32 @@ ngx_pool_cleanup_file(void *data)
 }
 
 
+void
+ngx_pool_delete_file(void *data)
+{
+    ngx_pool_cleanup_file_t  *c = data;
+
+    ngx_err_t  err;
+
+    ngx_log_debug3(NGX_LOG_DEBUG_ALLOC, c->log, 0, "run cleanup: %p, fd:%d %s",
+                   c, c->fd, c->name);
+
+    if (ngx_delete_file(c->name) == NGX_FILE_ERROR) {
+        err = ngx_errno;
+
+        if (err != NGX_ENOENT) {
+            ngx_log_error(NGX_LOG_CRIT, c->log, err,
+                          ngx_delete_file_n " \"%s\" failed", c->name);
+        }
+    }
+
+    if (ngx_close_file(c->fd) == NGX_FILE_ERROR) {
+        ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
+                      ngx_close_file_n " \"%s\" failed", c->name);
+    }
+}
+
+
 #if 0
 
 static void *
--- a/src/core/ngx_palloc.h
+++ b/src/core/ngx_palloc.h
@@ -60,7 +60,6 @@ typedef struct {
 } ngx_pool_cleanup_file_t;
 
 
-
 void *ngx_alloc(size_t size, ngx_log_t *log);
 void *ngx_calloc(size_t size, ngx_log_t *log);
 
@@ -74,6 +73,7 @@ ngx_int_t ngx_pfree(ngx_pool_t *pool, vo
 
 ngx_pool_cleanup_t *ngx_pool_cleanup_add(ngx_pool_t *p, size_t size);
 void ngx_pool_cleanup_file(void *data);
+void ngx_pool_delete_file(void *data);
 
 
 #endif /* _NGX_PALLOC_H_INCLUDED_ */
--- a/src/http/modules/ngx_http_dav_module.c
+++ b/src/http/modules/ngx_http_dav_module.c
@@ -135,7 +135,7 @@ ngx_http_dav_handler(ngx_http_request_t 
 
         r->request_body_in_file_only = 1;
         r->request_body_in_persistent_file = 1;
-        r->request_body_delete_incomplete_file = 1;
+        r->request_body_in_clean_file = 1;
         r->request_body_file_group_access = 1;
         r->request_body_file_log_level = 0;
 
--- a/src/http/modules/ngx_http_log_module.c
+++ b/src/http/modules/ngx_http_log_module.c
@@ -42,6 +42,7 @@ typedef struct {
 typedef struct {
     ngx_open_file_t            *file;
     time_t                      disk_full_time;
+    time_t                      error_log_time;
     ngx_array_t                *ops;        /* array of ngx_http_log_op_t */
 } ngx_http_log_t;
 
@@ -59,6 +60,9 @@ typedef struct {
 } ngx_http_log_var_t;
 
 
+static void ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log,
+    u_char *buf, size_t len);
+
 static u_char *ngx_http_log_connection(ngx_http_request_t *r, u_char *buf,
     ngx_http_log_op_t *op);
 static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf,
@@ -151,7 +155,7 @@ ngx_module_t  ngx_http_log_module = {
 };
 
 
-static ngx_str_t  http_access_log = ngx_string(NGX_HTTP_LOG_PATH);
+static ngx_str_t  ngx_http_access_log = ngx_string(NGX_HTTP_LOG_PATH);
 
 
 static ngx_str_t  ngx_http_combined_fmt =
@@ -183,9 +187,9 @@ static ngx_http_log_var_t  ngx_http_log_
 ngx_int_t
 ngx_http_log_handler(ngx_http_request_t *r)
 {
-    ngx_uint_t                i, l;
     u_char                   *line, *p;
     size_t                    len;
+    ngx_uint_t                i, l;
     ngx_http_log_t           *log;
     ngx_open_file_t          *file;
     ngx_http_log_op_t        *op;
@@ -206,9 +210,9 @@ ngx_http_log_handler(ngx_http_request_t 
         if (ngx_time() == log[l].disk_full_time) {
 
             /*
-             * On FreeBSD writing to a full filesystem with enabled softupdates
+             * on FreeBSD writing to a full filesystem with enabled softupdates
              * may block process for much longer time than writing to non-full
-             * filesystem, so we skip writing the log for one second.
+             * filesystem, so we skip writing to a log for one second
              */
 
             continue;
@@ -233,13 +237,8 @@ ngx_http_log_handler(ngx_http_request_t 
 
             if (len > (size_t) (file->last - file->pos)) {
 
-                if (ngx_write_fd(file->fd, file->buffer,
-                                 file->pos - file->buffer)
-                    == -1
-                    && ngx_errno == NGX_ENOSPC)
-                {
-                    log[l].disk_full_time = ngx_time();
-                }
+                ngx_http_log_write(r, &log[l], file->buffer,
+                                   file->pos - file->buffer);
 
                 file->pos = file->buffer;
             }
@@ -273,17 +272,57 @@ ngx_http_log_handler(ngx_http_request_t 
 
         ngx_linefeed(p);
 
-        if (ngx_write_fd(file->fd, line, p - line) == -1
-            && ngx_errno == NGX_ENOSPC)
-        {
-            log[l].disk_full_time = ngx_time();
-        }
+        ngx_http_log_write(r, &log[l], line, p - line);
     }
 
     return NGX_OK;
 }
 
 
+static void
+ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, u_char *buf,
+    size_t len)
+{
+    time_t     now;
+    ssize_t    n;
+    ngx_err_t  err;
+
+    n = ngx_write_fd(log->file->fd, buf, len);
+
+    if (n == (ssize_t) len) {
+        return;
+    }
+
+    now = ngx_time();
+
+    if (n == -1) {
+        err = ngx_errno;
+
+        if (err == NGX_ENOSPC) {
+            log->disk_full_time = now;
+        }
+
+        if (now - log->error_log_time > 60) {
+            ngx_log_error(NGX_LOG_ALERT, r->connection->log, err,
+                          ngx_write_fd_n " to \"%V\" failed",
+                          &log->file->name);
+
+            log->error_log_time = now;
+        }
+
+        return;
+    }
+
+    if (now - log->error_log_time > 60) {
+        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+                      ngx_write_fd_n " to \"%V\" was incomplete: %z of %uz",
+                      &log->file->name, n, len);
+
+        log->error_log_time = now;
+    }
+}
+
+
 static u_char *
 ngx_http_log_copy_short(ngx_http_request_t *r, u_char *buf,
     ngx_http_log_op_t *op)
@@ -515,47 +554,40 @@ ngx_http_log_merge_loc_conf(ngx_conf_t *
     ngx_http_log_fmt_t        *fmt;
     ngx_http_log_main_conf_t  *lmcf;
 
-    if (conf->logs == NULL) {
+    if (conf->logs || conf->off) {
+        return NGX_CONF_OK;
+    }
 
-        if (conf->off) {
-            return NGX_CONF_OK;
-        }
-
-        if (prev->logs) {
-            conf->logs = prev->logs;
+    *conf = *prev;
 
-        } else {
+    if (conf->logs || conf->off) {
+        return NGX_CONF_OK;
+    }
 
-            if (prev->off) {
-                conf->off = prev->off;
-                return NGX_CONF_OK;
-            }
-
-            conf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t));
-            if (conf->logs == NULL) {
-                return NGX_CONF_ERROR;
-            }
+    conf->logs = ngx_array_create(cf->pool, 2, sizeof(ngx_http_log_t));
+    if (conf->logs == NULL) {
+        return NGX_CONF_ERROR;
+    }
 
-            log = ngx_array_push(conf->logs);
-            if (log == NULL) {
-                return NGX_CONF_ERROR;
-            }
+    log = ngx_array_push(conf->logs);
+    if (log == NULL) {
+        return NGX_CONF_ERROR;
+    }
 
-            log->file = ngx_conf_open_file(cf->cycle, &http_access_log);
-            if (log->file == NULL) {
-                return NGX_CONF_ERROR;
-            }
+    log->file = ngx_conf_open_file(cf->cycle, &ngx_http_access_log);
+    if (log->file == NULL) {
+        return NGX_CONF_ERROR;
+    }
 
-            log->disk_full_time = 0;
-
-            lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
-            fmt = lmcf->formats.elts;
+    log->disk_full_time = 0;
+    log->error_log_time = 0;
 
-            /* the default "combined" format */
-            log->ops = fmt[0].ops;
-            lmcf->combined_used = 1;
-        }
-    }
+    lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_log_module);
+    fmt = lmcf->formats.elts;
+
+    /* the default "combined" format */
+    log->ops = fmt[0].ops;
+    lmcf->combined_used = 1;
 
     return NGX_CONF_OK;
 }
@@ -600,6 +632,7 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx
     }
 
     log->disk_full_time = 0;
+    log->error_log_time = 0;
 
     if (cf->args->nelts >= 3) {
         name = value[2];
--- a/src/http/modules/ngx_http_memcached_module.c
+++ b/src/http/modules/ngx_http_memcached_module.c
@@ -12,6 +12,7 @@
 
 typedef struct {
     ngx_http_upstream_conf_t   upstream;
+    ngx_int_t                  index;
 } ngx_http_memcached_loc_conf_t;
 
 
@@ -147,6 +148,9 @@ ngx_module_t  ngx_http_memcached_module 
 };
 
 
+static ngx_str_t  ngx_http_memcached_key = ngx_string("memcached_key");
+
+
 #define NGX_HTTP_MEMCACHED_END   (sizeof(ngx_http_memcached_end) - 1)
 static u_char  ngx_http_memcached_end[] = CRLF "END" CRLF;
 
@@ -221,14 +225,26 @@ ngx_http_memcached_handler(ngx_http_requ
 static ngx_int_t
 ngx_http_memcached_create_request(ngx_http_request_t *r)
 {
-    size_t                     len;
-    ngx_buf_t                 *b;
-    ngx_chain_t               *cl;
-    ngx_http_memcached_ctx_t  *ctx;
+    size_t                          len;
+    ngx_buf_t                      *b;
+    ngx_chain_t                    *cl;
+    ngx_http_memcached_ctx_t       *ctx;
+    ngx_http_variable_value_t      *vv;
+    ngx_http_memcached_loc_conf_t  *mlcf;
+
+    mlcf = ngx_http_get_module_loc_conf(r, ngx_http_memcached_module);
 
-    len = sizeof("get ") - 1 + r->uri.len + sizeof(" " CRLF) - 1;
-    if (r->args.len) {
-        len += 1 + r->args.len;
+    vv = ngx_http_get_indexed_variable(r, mlcf->index);
+
+    if (vv == NULL || vv->not_found || vv->len == 0) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "the \"$memcached_key\" variable is not set");
+        return NGX_ERROR;
+    }
+
+    len = sizeof("get ") - 1 + vv->len + sizeof(" " CRLF) - 1;
+    if (vv->len) {
+        len += 1 + vv->len;
     }
 
     b = ngx_create_temp_buf(r->pool, len);
@@ -252,12 +268,7 @@ ngx_http_memcached_create_request(ngx_ht
 
     ctx->key.data = b->last;
 
-    b->last = ngx_copy(b->last, r->uri.data, r->uri.len);
-
-    if (r->args.len) {
-        *b->last++ = '?';
-        b->last = ngx_copy(b->last, r->args.data, r->args.len);
-    }
+    b->last = ngx_copy(b->last, vv->data, vv->len);
 
     ctx->key.len = b->last - ctx->key.data;
 
@@ -504,7 +515,7 @@ ngx_http_memcached_create_loc_conf(ngx_c
      *     conf->upstream.uri = { 0, NULL };
      *     conf->upstream.location = NULL;
      *
-     *     conf->peers = NULL;
+     *     conf->index = 0;
      */
 
     conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC;
@@ -604,6 +615,12 @@ ngx_http_memcached_pass(ngx_conf_t *cf, 
         clcf->auto_redirect = 1;
     }
 
+    lcf->index = ngx_http_get_variable_index(cf, &ngx_http_memcached_key);
+
+    if (lcf->index == NGX_ERROR) {
+        return NGX_CONF_ERROR;
+    }
+
     return NGX_CONF_OK;
 }
 
--- 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.5.8';
+our $VERSION = '0.5.9';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/modules/perl/nginx.xs
+++ b/src/http/modules/perl/nginx.xs
@@ -363,7 +363,7 @@ has_request_body(r, next)
 
     r->request_body_in_single_buf = 1;
     r->request_body_in_persistent_file = 1;
-    r->request_body_delete_incomplete_file = 1;
+    r->request_body_in_clean_file = 1;
 
     if (r->request_body_in_file_only) {
         r->request_body_file_log_level = 0;
--- a/src/http/modules/perl/ngx_http_perl_module.c
+++ b/src/http/modules/perl/ngx_http_perl_module.c
@@ -44,9 +44,8 @@ static ngx_int_t ngx_http_perl_ssi(ngx_h
 static void ngx_http_perl_sleep_handler(ngx_http_request_t *r);
 static char *ngx_http_perl_init_interpreter(ngx_conf_t *cf,
     ngx_http_perl_main_conf_t *pmcf);
-static PerlInterpreter *
-    ngx_http_perl_create_interpreter(ngx_http_perl_main_conf_t *pmcf,
-    ngx_log_t *log);
+static PerlInterpreter *ngx_http_perl_create_interpreter(ngx_conf_t *cf,
+    ngx_http_perl_main_conf_t *pmcf);
 static ngx_int_t ngx_http_perl_run_requires(pTHX_ ngx_array_t *requires,
     ngx_log_t *log);
 static ngx_int_t ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r,
@@ -475,7 +474,7 @@ ngx_http_perl_init_interpreter(ngx_conf_
 
     PERL_SYS_INIT(&ngx_argc, &ngx_argv);
 
-    pmcf->perl = ngx_http_perl_create_interpreter(pmcf, cf->log);
+    pmcf->perl = ngx_http_perl_create_interpreter(cf, pmcf);
 
     if (pmcf->perl == NULL) {
         PERL_SYS_TERM();
@@ -500,8 +499,8 @@ ngx_http_perl_init_interpreter(ngx_conf_
 
 
 static PerlInterpreter *
-ngx_http_perl_create_interpreter(ngx_http_perl_main_conf_t *pmcf,
-    ngx_log_t *log)
+ngx_http_perl_create_interpreter(ngx_conf_t *cf,
+    ngx_http_perl_main_conf_t *pmcf)
 {
     int                n;
     STRLEN             len;
@@ -509,11 +508,15 @@ ngx_http_perl_create_interpreter(ngx_htt
     char              *ver, *embedding[6];
     PerlInterpreter   *perl;
 
-    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "create perl interpreter");
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "create perl interpreter");
+
+    if (ngx_set_environment(cf->cycle, NULL) == NULL) {
+        return NULL;
+    }
 
     perl = perl_alloc();
     if (perl == NULL) {
-        ngx_log_error(NGX_LOG_ALERT, log, 0, "perl_alloc() failed");
+        ngx_log_error(NGX_LOG_ALERT, cf->log, 0, "perl_alloc() failed");
         return NULL;
     }
 
@@ -546,7 +549,7 @@ ngx_http_perl_create_interpreter(ngx_htt
     n = perl_parse(perl, ngx_http_perl_xs_init, n, embedding, NULL);
 
     if (n != 0) {
-        ngx_log_error(NGX_LOG_ALERT, log, 0, "perl_parse() failed: %d", n);
+        ngx_log_error(NGX_LOG_ALERT, cf->log, 0, "perl_parse() failed: %d", n);
         goto fail;
     }
 
@@ -554,13 +557,13 @@ ngx_http_perl_create_interpreter(ngx_htt
     ver = SvPV(sv, len);
 
     if (ngx_strcmp(ver, NGINX_VERSION) != 0) {
-        ngx_log_error(NGX_LOG_ALERT, log, 0,
+        ngx_log_error(NGX_LOG_ALERT, cf->log, 0,
                       "version " NGINX_VERSION " of nginx.pm is required, "
                       "but %s was found", ver);
         goto fail;
     }
 
-    if (ngx_http_perl_run_requires(aTHX_ &pmcf->requires, log) != NGX_OK) {
+    if (ngx_http_perl_run_requires(aTHX_ &pmcf->requires, cf->log) != NGX_OK) {
         goto fail;
     }
 
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -23,6 +23,11 @@ typedef struct {
 #define NGX_HTTP_LOCATION_REGEX           4
 
 
+#define NGX_HTTP_REQUEST_BODY_FILE_OFF    0
+#define NGX_HTTP_REQUEST_BODY_FILE_ON     1
+#define NGX_HTTP_REQUEST_BODY_FILE_CLEAN  2
+
+
 static ngx_int_t ngx_http_core_find_location(ngx_http_request_t *r,
     ngx_array_t *locations, size_t len);
 
@@ -74,6 +79,14 @@ static ngx_conf_deprecated_t  ngx_conf_d
 };
 
 
+static ngx_conf_enum_t  ngx_http_core_request_body_in_file[] = {
+    { ngx_string("off"), NGX_HTTP_REQUEST_BODY_FILE_OFF },
+    { ngx_string("on"), NGX_HTTP_REQUEST_BODY_FILE_ON },
+    { ngx_string("clean"), NGX_HTTP_REQUEST_BODY_FILE_CLEAN },
+    { ngx_null_string, 0 }
+};
+
+
 static ngx_command_t  ngx_http_core_commands[] = {
 
     { ngx_string("variables_hash_max_size"),
@@ -269,13 +282,14 @@ static ngx_command_t  ngx_http_core_comm
 
     { ngx_string("client_body_in_file_only"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
-      ngx_conf_set_flag_slot,
+      ngx_conf_set_enum_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
       offsetof(ngx_http_core_loc_conf_t, client_body_in_file_only),
-      NULL },
+      &ngx_http_core_request_body_in_file },
 
     { ngx_string("sendfile"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
+                        |NGX_CONF_TAKE1,
       ngx_conf_set_flag_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
       offsetof(ngx_http_core_loc_conf_t, sendfile),
@@ -876,6 +890,8 @@ ngx_http_update_location_config(ngx_http
     if (clcf->client_body_in_file_only) {
         r->request_body_in_file_only = 1;
         r->request_body_in_persistent_file = 1;
+        r->request_body_in_clean_file =
+            clcf->client_body_in_file_only == NGX_HTTP_REQUEST_BODY_FILE_CLEAN;
         r->request_body_file_log_level = NGX_LOG_NOTICE;
 
     } else {
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -409,7 +409,7 @@ struct ngx_http_request_s {
     unsigned                          request_body_in_single_buf:1;
     unsigned                          request_body_in_file_only:1;
     unsigned                          request_body_in_persistent_file:1;
-    unsigned                          request_body_delete_incomplete_file:1;
+    unsigned                          request_body_in_clean_file:1;
     unsigned                          request_body_file_group_access:1;
     unsigned                          request_body_file_log_level:3;
 
--- a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -14,7 +14,6 @@ static void ngx_http_read_client_request
 static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r);
 static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r,
     ngx_chain_t *body);
-static void ngx_http_finalize_request_body(ngx_http_request_t *r, ngx_int_t rc);
 static void ngx_http_read_discarded_body_handler(ngx_http_request_t *r);
 static ngx_int_t ngx_http_read_discarded_body(ngx_http_request_t *r);
 
@@ -72,6 +71,7 @@ ngx_http_read_client_request_body(ngx_ht
             tf->warn = "a client request body is buffered to a temporary file";
             tf->log_level = r->request_body_file_log_level;
             tf->persistent = r->request_body_in_persistent_file;
+            tf->clean = r->request_body_in_clean_file;
 
             if (r->request_body_file_group_access) {
                 tf->access = 0660;
@@ -80,7 +80,7 @@ ngx_http_read_client_request_body(ngx_ht
             rb->temp_file = tf;
 
             if (ngx_create_temp_file(&tf->file, tf->path, tf->pool,
-                                     tf->persistent, tf->access)
+                                     tf->persistent, tf->clean, tf->access)
                 != NGX_OK)
             {
                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
@@ -238,14 +238,14 @@ ngx_http_read_client_request_body_handle
 
     if (r->connection->read->timedout) {
         r->connection->timedout = 1;
-        ngx_http_finalize_request_body(r, NGX_HTTP_REQUEST_TIME_OUT);
+        ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT);
         return;
     }
 
     rc = ngx_http_do_read_client_request_body(r);
 
     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
-        ngx_http_finalize_request_body(r, rc);
+        ngx_http_finalize_request(r, rc);
     }
 }
 
@@ -400,6 +400,7 @@ ngx_http_write_request_body(ngx_http_req
         tf->warn = "a client request body is buffered to a temporary file";
         tf->log_level = r->request_body_file_log_level;
         tf->persistent = r->request_body_in_persistent_file;
+        tf->clean = r->request_body_in_clean_file;
 
         if (r->request_body_file_group_access) {
             tf->access = 0660;
@@ -422,26 +423,6 @@ ngx_http_write_request_body(ngx_http_req
 }
 
 
-static void
-ngx_http_finalize_request_body(ngx_http_request_t *r, ngx_int_t rc)
-{
-    if (r->request_body->temp_file
-        && r->request_body_in_persistent_file
-        && r->request_body_delete_incomplete_file)
-    {
-        if (ngx_delete_file(r->request_body->temp_file->file.name.data)
-            == NGX_FILE_ERROR)
-        {
-            ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
-                          ngx_delete_file_n " \"%s\" failed",
-                          r->request_body->temp_file->file.name.data);
-        }
-    }
-
-    ngx_http_finalize_request(r, rc);
-}
-
-
 ngx_int_t
 ngx_http_discard_body(ngx_http_request_t *r)
 {
--- a/src/os/unix/ngx_process_cycle.c
+++ b/src/os/unix/ngx_process_cycle.c
@@ -757,15 +757,20 @@ ngx_worker_process_cycle(ngx_cycle_t *cy
 static void
 ngx_worker_process_init(ngx_cycle_t *cycle, ngx_uint_t priority)
 {
-    sigset_t           set;
-    ngx_int_t          n;
-    ngx_uint_t         i;
-    struct rlimit      rlmt;
-    ngx_core_conf_t   *ccf;
-    ngx_listening_t   *ls;
+    sigset_t          set;
+    ngx_int_t         n;
+    ngx_uint_t        i;
+    struct rlimit     rlmt;
+    ngx_core_conf_t  *ccf;
+    ngx_listening_t  *ls;
 
     ngx_process = NGX_PROCESS_WORKER;
 
+    if (ngx_set_environment(cycle, NULL) == NULL) {
+        /* fatal */
+        exit(2);
+    }
+
     ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);
 
     if (geteuid() == 0) {