changeset 186:54aabf2b0bc6 NGINX_0_3_40

nginx 0.3.40 *) Feature: the ngx_http_dav_module supports the MKCOL method. *) Feature: the "create_full_put_path" directive. *) Feature: the "$limit_rate" variable.
author Igor Sysoev <http://sysoev.ru>
date Wed, 19 Apr 2006 00:00:00 +0400
parents a9c5dc369ffe
children c0ed72c62dfa
files CHANGES CHANGES.ru auto/modules src/core/nginx.h src/core/ngx_file.c src/core/ngx_file.h src/http/modules/ngx_http_autoindex_module.c src/http/modules/ngx_http_dav_module.c src/http/modules/ngx_http_fastcgi_module.c src/http/modules/ngx_http_geo_module.c src/http/modules/ngx_http_gzip_filter_module.c src/http/modules/ngx_http_index_module.c src/http/modules/ngx_http_map_module.c src/http/modules/ngx_http_proxy_module.c src/http/modules/ngx_http_referer_module.c src/http/modules/ngx_http_rewrite_module.c src/http/modules/ngx_http_ssi_filter_module.c src/http/modules/ngx_http_ssl_module.c src/http/modules/ngx_http_userid_filter_module.c src/http/modules/perl/ngx_http_perl_module.c src/http/ngx_http.c src/http/ngx_http_core_module.c src/http/ngx_http_header_filter_module.c src/http/ngx_http_parse.c src/http/ngx_http_request.c src/http/ngx_http_request.h src/http/ngx_http_request_body.c src/http/ngx_http_script.c src/http/ngx_http_script.h src/http/ngx_http_special_response.c src/http/ngx_http_upstream.c src/http/ngx_http_variables.c src/http/ngx_http_variables.h src/os/unix/ngx_errno.h
diffstat 34 files changed, 523 insertions(+), 152 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,13 @@
 
+Changes with nginx 0.3.40                                        19 Apr 2006
+
+    *) Feature: the ngx_http_dav_module supports the MKCOL method.
+
+    *) Feature: the "create_full_put_path" directive.
+
+    *) Feature: the "$limit_rate" variable.
+
+
 Changes with nginx 0.3.39                                        17 Apr 2006
 
     *) Feature: the "uninitialized_variable_warn" directive; the logging 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,13 @@
 
+Изменения в nginx 0.3.40                                          19.04.2006
+
+    *) Добавление: модуль ngx_http_dav_module поддерживает метод MKCOL.
+
+    *) Добавление: директива create_full_put_path.
+
+    *) Добавление: переменная $limit_rate.
+
+
 Изменения в nginx 0.3.39                                          17.04.2006
 
     *) Добавление: директива uninitialized_variable_warn; уровень 
--- a/auto/modules
+++ b/auto/modules
@@ -128,6 +128,7 @@ fi
 HTTP_MODULES="$HTTP_MODULES $HTTP_STATIC_MODULE"
 
 if [ $HTTP_DAV = YES ]; then
+    have=NGX_HTTP_DAV . auto/have
     HTTP_MODULES="$HTTP_MODULES $HTTP_DAV_MODULE"
     HTTP_SRCS="$HTTP_SRCS $HTTP_DAV_SRCS"
 fi
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VER          "nginx/0.3.39"
+#define NGINX_VER          "nginx/0.3.40"
 
 #define NGINX_VAR          "NGINX"
 #define NGX_OLDPID_EXT     ".oldbin"
--- a/src/core/ngx_file.c
+++ b/src/core/ngx_file.c
@@ -25,8 +25,12 @@ ngx_write_chain_to_temp_file(ngx_temp_fi
             return rc;
         }
 
-        if (!tf->persistent && tf->warn) {
-            ngx_log_error(NGX_LOG_WARN, tf->file.log, 0, tf->warn);
+        if (tf->log_level == NGX_LOG_NOTICE) {
+            ngx_log_error(NGX_LOG_NOTICE, tf->file.log, 0, tf->warn);
+
+        } else if (tf->log_level == NGX_LOG_WARN) {
+            ngx_log_error(NGX_LOG_WARN, tf->file.log, 0, "%s %V",
+                          tf->warn, &tf->file.name);
         }
     }
 
@@ -182,6 +186,35 @@ ngx_create_path(ngx_file_t *file, ngx_pa
 }
 
 
+ngx_err_t
+ngx_create_full_path(u_char *dir)
+{
+    u_char     *p, ch;
+    ngx_err_t   err;
+
+    for (p = dir + 1; *p; p++) {
+        ch = *p;
+
+        if (ch != '/') {
+            continue;
+        }
+
+        *p = '\0';
+
+        if (ngx_create_dir(dir) == NGX_FILE_ERROR) {
+            err = ngx_errno;
+            if (err != NGX_EEXIST) {
+                return err;
+            }
+        }
+
+        *p = '/';
+    }
+
+    return 0;
+}
+
+
 void
 ngx_init_temp_number(void)
 {
--- a/src/core/ngx_file.h
+++ b/src/core/ngx_file.h
@@ -51,6 +51,7 @@ typedef struct {
 
     ngx_uint_t          mode;
 
+    unsigned            log_level:8;
     unsigned            persistent:1;
 } ngx_temp_file_t;
 
@@ -60,6 +61,7 @@ ngx_int_t ngx_create_temp_file(ngx_file_
     ngx_pool_t *pool, ngx_uint_t persistent,ngx_uint_t mode);
 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_int_t ngx_add_path(ngx_conf_t *cf, ngx_path_t **slot);
 ngx_int_t ngx_create_pathes(ngx_cycle_t *cycle, ngx_uid_t user);
 
--- a/src/http/modules/ngx_http_autoindex_module.c
+++ b/src/http/modules/ngx_http_autoindex_module.c
@@ -162,6 +162,10 @@ ngx_http_autoindex_handler(ngx_http_requ
         return NGX_DECLINED;
     }
 
+    if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) {
+        return NGX_DECLINED;
+    }
+
     alcf = ngx_http_get_module_loc_conf(r, ngx_http_autoindex_module);
 
     if (!alcf->enable) {
--- a/src/http/modules/ngx_http_dav_module.c
+++ b/src/http/modules/ngx_http_dav_module.c
@@ -13,11 +13,15 @@
 
 typedef struct {
     ngx_uint_t  methods;
+    ngx_flag_t  create_full_put_path;
 } ngx_http_dav_loc_conf_t;
 
 
 static ngx_int_t ngx_http_dav_handler(ngx_http_request_t *r);
 static void ngx_http_dav_put_handler(ngx_http_request_t *r);
+static ngx_int_t ngx_http_dav_error(ngx_http_request_t *, ngx_err_t err,
+    ngx_int_t not_found, char *failed, u_char *path);
+static ngx_int_t ngx_http_dav_location(ngx_http_request_t *r, u_char *path);
 static void *ngx_http_dav_create_loc_conf(ngx_conf_t *cf);
 static char *ngx_http_dav_merge_loc_conf(ngx_conf_t *cf,
     void *parent, void *child);
@@ -28,6 +32,7 @@ static ngx_conf_bitmask_t  ngx_http_dav_
     { ngx_string("off"), NGX_HTTP_DAV_OFF },
     { ngx_string("put"), NGX_HTTP_PUT },
     { ngx_string("delete"), NGX_HTTP_DELETE },
+    { ngx_string("mkcol"), NGX_HTTP_MKCOL },
     { ngx_null_string, 0 }
 };
 
@@ -41,6 +46,13 @@ static ngx_command_t  ngx_http_dav_comma
       offsetof(ngx_http_dav_loc_conf_t, methods),
       &ngx_http_dav_methods_mask },
 
+    { ngx_string("create_full_put_path"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_dav_loc_conf_t, create_full_put_path),
+      NULL },
+
       ngx_null_command
 };
 
@@ -79,8 +91,10 @@ ngx_module_t  ngx_http_dav_module = {
 static ngx_int_t
 ngx_http_dav_handler(ngx_http_request_t *r)
 {
+    char                     *failed;
     ngx_int_t                 rc;
     ngx_str_t                 path;
+    ngx_file_info_t           fi;
     ngx_http_dav_loc_conf_t  *dlcf;
 
     /* TODO: Win32 */
@@ -102,10 +116,15 @@ ngx_http_dav_handler(ngx_http_request_t 
             return NGX_DECLINED;
         }
 
+        if (r->headers_in.content_length_n < 0) {
+            return NGX_HTTP_BAD_REQUEST;
+        }
+
         r->request_body_in_file_only = 1;
         r->request_body_in_persistent_file = 1;
         r->request_body_delete_incomplete_file = 1;
         r->request_body_file_group_access = 1;
+        r->request_body_file_log_level = 0;
 
         rc = ngx_http_read_client_request_body(r, ngx_http_dav_put_handler);
 
@@ -117,8 +136,14 @@ ngx_http_dav_handler(ngx_http_request_t 
 
     case NGX_HTTP_DELETE:
 
-        if (r->uri.data[r->uri.len - 1] == '/') {
-            return NGX_DECLINED;
+        if (r->headers_in.content_length_n > 0) {
+            return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE;
+        }
+
+        rc = ngx_http_discard_body(r);
+
+        if (rc != NGX_OK && rc != NGX_AGAIN) {
+            return rc;
         }
 
         ngx_http_map_uri_to_path(r, &path, 0);
@@ -126,14 +151,83 @@ ngx_http_dav_handler(ngx_http_request_t 
         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                        "http delete filename: \"%s\"", path.data);
 
-        if (ngx_delete_file(path.data) == NGX_FILE_ERROR) {
-            ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
-                          ngx_delete_file_n " \"%s\" failed", path.data);
+        if (ngx_file_info(path.data, &fi) != -1) {
+
+            if (ngx_is_dir(&fi)) {
+
+                if (r->uri.data[r->uri.len - 1] != '/'
+                    || r->headers_in.depth == NULL
+                    || r->headers_in.depth->value.len != sizeof("infinity") - 1
+                    || ngx_strcmp(r->headers_in.depth->value.data, "infinity")
+                       != 0)
+                {
+                    return NGX_HTTP_BAD_REQUEST;
+                }
+
+                if (ngx_delete_dir(path.data) != NGX_FILE_ERROR) {
+                    return NGX_HTTP_NO_CONTENT;
+                }
+
+                failed = ngx_delete_dir_n;
+
+            } else {
 
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+                if (r->uri.data[r->uri.len - 1] == '/') {
+                    return NGX_HTTP_BAD_REQUEST;
+                }
+
+                if (r->headers_in.depth
+                    && r->headers_in.depth->value.len == 1
+                    && r->headers_in.depth->value.data[0] == '1')
+                {
+                    return NGX_HTTP_BAD_REQUEST;
+                }
+
+                if (ngx_delete_file(path.data) != NGX_FILE_ERROR) {
+                    return NGX_HTTP_NO_CONTENT;
+                }
+
+                failed = ngx_delete_file_n;
+            }
+
+        } else {
+            failed = ngx_file_info_n;
         }
 
-        return NGX_HTTP_NO_CONTENT;
+        return ngx_http_dav_error(r, ngx_errno, NGX_HTTP_NOT_FOUND, failed,
+                                  path.data);
+
+    case NGX_HTTP_MKCOL:
+
+        if (r->uri.data[r->uri.len - 1] != '/') {
+            return NGX_DECLINED;
+        }
+
+        if (r->headers_in.content_length_n > 0) {
+            return NGX_HTTP_UNSUPPORTED_MEDIA_TYPE;
+        }
+
+        rc = ngx_http_discard_body(r);
+
+        if (rc != NGX_OK && rc != NGX_AGAIN) {
+            return rc;
+        }
+
+        ngx_http_map_uri_to_path(r, &path, 0);
+
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "http mkcol path: \"%s\"", path.data);
+
+        if (ngx_create_dir(path.data) != NGX_FILE_ERROR) {
+            if (ngx_http_dav_location(r, path.data) != NGX_OK) {
+                return NGX_HTTP_INTERNAL_SERVER_ERROR;
+            }
+
+            return NGX_HTTP_CREATED;
+        }
+
+        return ngx_http_dav_error(r, ngx_errno, NGX_HTTP_CONFLICT,
+                                  ngx_create_dir_n, path.data);
     }
 
     return NGX_DECLINED;
@@ -143,12 +237,11 @@ ngx_http_dav_handler(ngx_http_request_t 
 static void
 ngx_http_dav_put_handler(ngx_http_request_t *r)
 {
-    u_char                    *location;
-    ngx_err_t                  err;
-    ngx_str_t                 *temp, path;
-    ngx_uint_t                 status;
-    ngx_file_info_t            fi;
-    ngx_http_core_loc_conf_t  *clcf;
+    ngx_err_t                 err;
+    ngx_str_t                *temp, path;
+    ngx_uint_t                status;
+    ngx_file_info_t           fi;
+    ngx_http_dav_loc_conf_t  *dlcf;
 
     ngx_http_map_uri_to_path(r, &path, 0);
 
@@ -164,12 +257,34 @@ ngx_http_dav_put_handler(ngx_http_reques
         status = NGX_HTTP_NO_CONTENT;
     }
 
+    if (ngx_is_dir(&fi)) {
+        ngx_http_finalize_request(r, NGX_HTTP_CONFLICT);
+        return;
+    }
+
     if (ngx_rename_file(temp->data, path.data) != NGX_FILE_ERROR) {
         goto ok;
     }
 
     err = ngx_errno;
 
+    if (err == NGX_ENOENT) {
+
+        dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_module);
+
+        if (dlcf->create_full_put_path) {
+            err = ngx_create_full_path(path.data);
+
+            if (err == 0) {
+                if (ngx_rename_file(temp->data, path.data) != NGX_FILE_ERROR) {
+                    goto ok;
+                }
+
+                err = ngx_errno;
+            }
+        }
+    }
+
 #if (NGX_WIN32)
 
     if (err == NGX_EEXIST) {
@@ -185,45 +300,18 @@ ngx_http_dav_put_handler(ngx_http_reques
 
 #endif
 
-    ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
-                  ngx_rename_file_n " \"%s\" failed", path.data);
-
-    ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+    ngx_http_finalize_request(r, ngx_http_dav_error(r, err, NGX_HTTP_CONFLICT,
+                                                    ngx_rename_file_n,
+                                                    path.data));
     return;
 
 ok:
 
     if (status == NGX_HTTP_CREATED) {
-
-        r->headers_out.location = ngx_palloc(r->pool, sizeof(ngx_table_elt_t));
-        if (r->headers_out.location == NULL) {
+        if (ngx_http_dav_location(r, path.data) != NGX_OK) {
             ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
             return;
         }
-
-        clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
-        if (!clcf->alias && clcf->root_lengths == NULL) {
-            location = path.data + clcf->root.len;
-
-        } else {
-            location = ngx_palloc(r->pool, r->uri.len);
-            if (location == NULL) {
-                ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
-                return;
-            }
-
-            ngx_memcpy(location, r->uri.data, r->uri.len);
-        }
-
-        /*
-         * we do not need to set the r->headers_out.location->hash and
-         * r->headers_out.location->key fields
-         */
-
-        r->headers_out.location->value.len = r->uri.len;
-        r->headers_out.location->value.data = location;
-
     }
 
     r->headers_out.status = status;
@@ -234,6 +322,78 @@ ok:
 }
 
 
+static ngx_int_t
+ngx_http_dav_error(ngx_http_request_t *r, ngx_err_t err, ngx_int_t not_found,
+    char *failed, u_char *path)
+{
+    ngx_int_t   rc;
+    ngx_uint_t  level;
+
+    if (err == NGX_ENOENT || err == NGX_ENOTDIR || err == NGX_ENAMETOOLONG) {
+        level = NGX_LOG_ERR;
+        rc = not_found;
+
+    } else if (err == NGX_EACCES || err == NGX_EPERM) {
+        level = NGX_LOG_ERR;
+        rc = NGX_HTTP_FORBIDDEN;
+
+    } else if (err == NGX_EEXIST) {
+        level = NGX_LOG_ERR;
+        rc = NGX_HTTP_NOT_ALLOWED;
+
+    } else if (err == NGX_ENOSPC) {
+        level = NGX_LOG_CRIT;
+        rc = NGX_HTTP_INSUFFICIENT_STORAGE;
+
+    } else {
+        level = NGX_LOG_CRIT;
+        rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    ngx_log_error(level, r->connection->log, err,
+                  "%s \"%s\" failed", failed, path);
+
+    return rc;
+}
+
+
+static ngx_int_t
+ngx_http_dav_location(ngx_http_request_t *r, u_char *path)
+{
+    u_char                    *location;
+    ngx_http_core_loc_conf_t  *clcf;
+
+    r->headers_out.location = ngx_palloc(r->pool, sizeof(ngx_table_elt_t));
+    if (r->headers_out.location == NULL) {
+        return NGX_ERROR;
+    }
+
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+    if (!clcf->alias && clcf->root_lengths == NULL) {
+        location = path + clcf->root.len;
+
+    } else {
+        location = ngx_palloc(r->pool, r->uri.len);
+        if (location == NULL) {
+            return NGX_ERROR;
+        }
+
+        ngx_memcpy(location, r->uri.data, r->uri.len);
+    }
+
+    /*
+     * we do not need to set the r->headers_out.location->hash and
+     * r->headers_out.location->key fields
+     */
+
+    r->headers_out.location->value.len = r->uri.len;
+    r->headers_out.location->value.data = location;
+
+    return NGX_OK;
+}
+
+
 static void *
 ngx_http_dav_create_loc_conf(ngx_conf_t *cf)
 {
@@ -250,6 +410,8 @@ ngx_http_dav_create_loc_conf(ngx_conf_t 
      *     conf->methods = 0;
      */
 
+    conf->create_full_put_path = NGX_CONF_UNSET;
+
     return conf;
 }
 
@@ -261,7 +423,10 @@ ngx_http_dav_merge_loc_conf(ngx_conf_t *
     ngx_http_dav_loc_conf_t  *conf = child;
 
     ngx_conf_merge_bitmask_value(conf->methods, prev->methods,
-                              (NGX_CONF_BITMASK_SET|NGX_HTTP_DAV_OFF));
+                         (NGX_CONF_BITMASK_SET|NGX_HTTP_DAV_OFF));
+
+    ngx_conf_merge_value(conf->create_full_put_path, prev->create_full_put_path,
+                         0);
 
     return NGX_CONF_OK;
 }
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -1445,7 +1445,7 @@ ngx_http_fastcgi_add_variables(ngx_conf_
         return NGX_ERROR;
     }
 
-    var->handler = ngx_http_fastcgi_script_name_variable;
+    var->get_handler = ngx_http_fastcgi_script_name_variable;
 
     return NGX_OK;
 }
--- a/src/http/modules/ngx_http_geo_module.c
+++ b/src/http/modules/ngx_http_geo_module.c
@@ -127,7 +127,7 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_c
         return NGX_CONF_ERROR;
     }
 
-    var->handler = ngx_http_geo_variable;
+    var->get_handler = ngx_http_geo_variable;
     var->data = (uintptr_t) tree;
 
     pool = ngx_create_pool(16384, cf->log);
--- a/src/http/modules/ngx_http_gzip_filter_module.c
+++ b/src/http/modules/ngx_http_gzip_filter_module.c
@@ -969,7 +969,7 @@ ngx_http_gzip_add_variables(ngx_conf_t *
         return NGX_ERROR;
     }
 
-    var->handler = ngx_http_gzip_ratio_variable;
+    var->get_handler = ngx_http_gzip_ratio_variable;
 
     for (op = ngx_http_gzip_log_fmt_ops; op->name.len; op++) { /* void */ }
     op->run = NULL;
--- a/src/http/modules/ngx_http_index_module.c
+++ b/src/http/modules/ngx_http_index_module.c
@@ -143,6 +143,10 @@ ngx_http_index_handler(ngx_http_request_
         return NGX_DECLINED;
     }
 
+    if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) {
+        return NGX_DECLINED;
+    }
+
     log = r->connection->log;
 
     /*
--- a/src/http/modules/ngx_http_map_module.c
+++ b/src/http/modules/ngx_http_map_module.c
@@ -237,7 +237,7 @@ ngx_http_map_block(ngx_conf_t *cf, ngx_c
         return NGX_CONF_ERROR;
     }
 
-    var->handler = ngx_http_map_variable;
+    var->get_handler = ngx_http_map_variable;
     var->data = (uintptr_t) map;
 
     pool = ngx_create_pool(16384, cf->log);
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -366,23 +366,23 @@ static ngx_table_elt_t  ngx_http_proxy_h
 
 static ngx_http_variable_t  ngx_http_proxy_vars[] = {
 
-    { ngx_string("proxy_host"), ngx_http_proxy_host_variable, 0,
+    { ngx_string("proxy_host"), NULL, ngx_http_proxy_host_variable, 0,
       NGX_HTTP_VAR_CHANGABLE|NGX_HTTP_VAR_NOHASH, 0 },
 
-    { ngx_string("proxy_port"), ngx_http_proxy_port_variable, 0,
+    { ngx_string("proxy_port"), NULL, ngx_http_proxy_port_variable, 0,
       NGX_HTTP_VAR_CHANGABLE|NGX_HTTP_VAR_NOHASH, 0 },
 
-    { ngx_string("proxy_add_x_forwarded_for"),
+    { ngx_string("proxy_add_x_forwarded_for"), NULL,
       ngx_http_proxy_add_x_forwarded_for_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },
 
 #if 0
-    { ngx_string("proxy_add_via"), NULL, 0, NGX_HTTP_VAR_NOHASH, 0 },
+    { ngx_string("proxy_add_via"), NULL, NULL, 0, NGX_HTTP_VAR_NOHASH, 0 },
 #endif
 
-    { ngx_string("proxy_internal_body_length"),
+    { ngx_string("proxy_internal_body_length"), NULL,
       ngx_http_proxy_internal_body_length_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },
 
-    { ngx_null_string, NULL, 0, 0, 0 }
+    { ngx_null_string, NULL, NULL, 0, 0, 0 }
 };
 
 
@@ -1382,7 +1382,7 @@ ngx_http_proxy_add_variables(ngx_conf_t 
             return NGX_ERROR;
         }
 
-        var->handler = v->handler;
+        var->get_handler = v->get_handler;
         var->data = v->data;
     }
 
--- a/src/http/modules/ngx_http_referer_module.c
+++ b/src/http/modules/ngx_http_referer_module.c
@@ -298,7 +298,7 @@ ngx_http_valid_referers(ngx_conf_t *cf, 
         return NGX_CONF_ERROR;
     }
 
-    var->handler = ngx_http_referer_variable;
+    var->get_handler = ngx_http_referer_variable;
 
     if (rlcf->keys == NULL) {
         rlcf->keys = ngx_pcalloc(cf->temp_pool, sizeof(ngx_hash_keys_arrays_t));
--- a/src/http/modules/ngx_http_rewrite_module.c
+++ b/src/http/modules/ngx_http_rewrite_module.c
@@ -74,15 +74,6 @@ static ngx_command_t  ngx_http_rewrite_c
       0,
       NULL },
 
-#if 0
-    { ngx_string("valid_referers"),
-      NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
-      ngx_http_rewrite_valid_referers,
-      NGX_HTTP_LOC_CONF_OFFSET,
-      0,
-      NULL },
-#endif
-
     { ngx_string("set"),
       NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
                        |NGX_CONF_TAKE2,
@@ -879,10 +870,11 @@ ngx_http_rewrite_set(ngx_conf_t *cf, ngx
 {
     ngx_http_rewrite_loc_conf_t  *lcf = conf;
 
-    ngx_int_t                     index;
-    ngx_str_t                    *value;
-    ngx_http_variable_t          *v;
-    ngx_http_script_var_code_t   *var;
+    ngx_int_t                            index;
+    ngx_str_t                           *value;
+    ngx_http_variable_t                 *v;
+    ngx_http_script_var_code_t          *vcode;
+    ngx_http_script_var_handler_code_t  *vhcode;
 
     value = cf->args->elts;
 
@@ -905,8 +897,8 @@ ngx_http_rewrite_set(ngx_conf_t *cf, ngx
         return NGX_CONF_ERROR;
     }
 
-    if (v->handler == NULL) {
-        v->handler = ngx_http_rewrite_var;
+    if (v->get_handler == NULL) {
+        v->get_handler = ngx_http_rewrite_var;
         v->data = index;
     }
 
@@ -914,14 +906,28 @@ ngx_http_rewrite_set(ngx_conf_t *cf, ngx
         return NGX_CONF_ERROR;
     }
 
-    var = ngx_http_script_start_code(cf->pool, &lcf->codes,
-                                     sizeof(ngx_http_script_var_code_t));
-    if (var == NULL) {
+    if (v->set_handler) {
+        vhcode = ngx_http_script_start_code(cf->pool, &lcf->codes,
+                                   sizeof(ngx_http_script_var_handler_code_t));
+        if (vhcode == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        vhcode->code = ngx_http_script_var_set_handler_code;
+        vhcode->handler = v->set_handler;
+        vhcode->data = v->data;
+
+        return NGX_CONF_OK;
+    }
+
+    vcode = ngx_http_script_start_code(cf->pool, &lcf->codes,
+                                       sizeof(ngx_http_script_var_code_t));
+    if (vcode == NULL) {
         return NGX_CONF_ERROR;
     }
 
-    var->code = ngx_http_script_set_var_code;
-    var->index = (uintptr_t) index;
+    vcode->code = ngx_http_script_set_var_code;
+    vcode->index = (uintptr_t) index;
 
     return NGX_CONF_OK;
 }
--- a/src/http/modules/ngx_http_ssi_filter_module.c
+++ b/src/http/modules/ngx_http_ssi_filter_module.c
@@ -262,13 +262,13 @@ static ngx_http_ssi_command_t  ngx_http_
 
 static ngx_http_variable_t  ngx_http_ssi_vars[] = {
 
-    { ngx_string("date_local"), ngx_http_ssi_date_gmt_local_variable, 0,
+    { ngx_string("date_local"), NULL, ngx_http_ssi_date_gmt_local_variable, 0,
       NGX_HTTP_VAR_NOCACHABLE, 0 },
 
-    { ngx_string("date_gmt"), ngx_http_ssi_date_gmt_local_variable, 1,
+    { ngx_string("date_gmt"), NULL, ngx_http_ssi_date_gmt_local_variable, 1,
       NGX_HTTP_VAR_NOCACHABLE, 0 },
 
-    { ngx_null_string, NULL, 0, 0, 0 }
+    { ngx_null_string, NULL, NULL, 0, 0, 0 }
 };
 
 
@@ -2153,7 +2153,7 @@ ngx_http_ssi_preconfiguration(ngx_conf_t
             return NGX_ERROR;
         }
 
-        var->handler = v->handler;
+        var->get_handler = v->get_handler;
         var->data = v->data;
     }
 
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -136,13 +136,13 @@ ngx_module_t  ngx_http_ssl_module = {
 
 static ngx_http_variable_t  ngx_http_ssl_vars[] = {
 
-    { ngx_string("ssl_protocol"), ngx_http_ssl_variable,
+    { ngx_string("ssl_protocol"), NULL, ngx_http_ssl_variable,
       (uintptr_t) ngx_ssl_get_protocol, NGX_HTTP_VAR_CHANGABLE, 0 },
 
-    { ngx_string("ssl_cipher"), ngx_http_ssl_variable,
+    { ngx_string("ssl_cipher"), NULL, ngx_http_ssl_variable,
       (uintptr_t) ngx_ssl_get_cipher_name, NGX_HTTP_VAR_CHANGABLE, 0 },
 
-    { ngx_null_string, NULL, 0, 0, 0 }
+    { ngx_null_string, NULL, NULL, 0, 0, 0 }
 };
 
 
@@ -190,7 +190,7 @@ ngx_http_ssl_add_variables(ngx_conf_t *c
             return NGX_ERROR;
         }
 
-        var->handler = v->handler;
+        var->get_handler = v->get_handler;
         var->data = v->data;
     }
 
--- a/src/http/modules/ngx_http_userid_filter_module.c
+++ b/src/http/modules/ngx_http_userid_filter_module.c
@@ -559,7 +559,7 @@ ngx_http_userid_add_variables(ngx_conf_t
         return NGX_ERROR;
     }
 
-    var->handler = ngx_http_userid_variable;
+    var->get_handler = ngx_http_userid_variable;
     var->data = offsetof(ngx_http_userid_ctx_t, uid_got);
 
     var = ngx_http_add_variable(cf, &ngx_http_userid_set, NGX_HTTP_VAR_NOHASH);
@@ -567,7 +567,7 @@ ngx_http_userid_add_variables(ngx_conf_t
         return NGX_ERROR;
     }
 
-    var->handler = ngx_http_userid_variable;
+    var->get_handler = ngx_http_userid_variable;
     var->data = offsetof(ngx_http_userid_ctx_t, uid_set);
 
 
--- a/src/http/modules/perl/ngx_http_perl_module.c
+++ b/src/http/modules/perl/ngx_http_perl_module.c
@@ -190,6 +190,10 @@ ngx_http_perl_handler(ngx_http_request_t
     r->request_body_in_persistent_file = 1;
     r->request_body_delete_incomplete_file = 1;
 
+    if (r->request_body_in_file_only) {
+        r->request_body_file_log_level = 0;
+    }
+
     rc = ngx_http_read_client_request_body(r, ngx_http_perl_handle_request);
 
     if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
@@ -1011,7 +1015,7 @@ ngx_http_perl_set(ngx_conf_t *cf, ngx_co
 
     }
 
-    v->handler = ngx_http_perl_variable;
+    v->get_handler = ngx_http_perl_variable;
     v->data = (uintptr_t) pv;
 
     return NGX_CONF_OK;
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -373,7 +373,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
     cmcf->phases[NGX_HTTP_LOG_PHASE].type = NGX_OK;
 
 
-    cmcf->headers_in_hash.max_size = 100;
+    cmcf->headers_in_hash.max_size = 200;
     cmcf->headers_in_hash.bucket_limit = 1;
     cmcf->headers_in_hash.bucket_size = sizeof(ngx_http_header_t);
     cmcf->headers_in_hash.name = "http headers_in";
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -753,6 +753,10 @@ 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_file_log_level = NGX_LOG_NOTICE;
+
+    } else {
+        r->request_body_file_log_level = NGX_LOG_WARN;
     }
 
     if (r->keepalive && clcf->keepalive_timeout == 0) {
@@ -1692,9 +1696,18 @@ ngx_http_core_cmp_locations(const void *
 static char *
 ngx_http_core_types(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
+    ngx_http_core_loc_conf_t *lcf = conf;
+
     char        *rv;
     ngx_conf_t   save;
 
+    if (lcf->types == NULL) {
+        lcf->types = ngx_array_create(cf->pool, 64, sizeof(ngx_hash_key_t));
+        if (lcf->types == NULL) {
+            return NGX_CONF_ERROR;
+        }
+    }
+
     save = *cf;
     cf->handler = ngx_http_core_type;
     cf->handler_conf = conf;
@@ -1716,13 +1729,6 @@ ngx_http_core_type(ngx_conf_t *cf, ngx_c
     ngx_uint_t       i, n;
     ngx_hash_key_t  *type;
 
-    if (lcf->types == NULL) {
-        lcf->types = ngx_array_create(cf->pool, 64, sizeof(ngx_hash_key_t));
-        if (lcf->types == NULL) {
-            return NGX_CONF_ERROR;
-        }
-    }
-
     content_type = ngx_palloc(cf->pool, sizeof(ngx_str_t));
     if (content_type == NULL) {
         return NGX_CONF_ERROR;
--- a/src/http/ngx_http_header_filter_module.c
+++ b/src/http/ngx_http_header_filter_module.c
@@ -93,7 +93,7 @@ static ngx_str_t ngx_http_status_lines[]
                        * because we treat such requests as the HTTP/0.9
                        * requests and send only a body without a header
                        */
-    ngx_null_string,  /* "415 Unsupported Media Type" */
+    ngx_string("415 Unsupported Media Type"),
     ngx_string("416 Requested Range Not Satisfiable"),
 
     /* ngx_null_string, */  /* "417 Expectation Failed" */
@@ -111,11 +111,11 @@ static ngx_str_t ngx_http_status_lines[]
     ngx_string("501 Method Not Implemented"),
     ngx_string("502 Bad Gateway"),
     ngx_string("503 Service Temporarily Unavailable"),
-    ngx_string("504 Gateway Time-out")
+    ngx_string("504 Gateway Time-out"),
 
-    /* ngx_null_string, */  /* "505 HTTP Version Not Supported" */
-    /* ngx_null_string, */  /* "506 Variant Also Negotiates" */
-    /* ngx_null_string, */  /* "507 Insufficient Storage" */
+    ngx_null_string,        /* "505 HTTP Version Not Supported" */
+    ngx_null_string,        /* "506 Variant Also Negotiates" */
+    ngx_string("507 Insufficient Storage"),
     /* ngx_null_string, */  /* "508 unused" */
     /* ngx_null_string, */  /* "509 unused" */
     /* ngx_null_string, */  /* "510 Not Extended" */
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -89,6 +89,14 @@ ngx_http_parse_request_line(ngx_http_req
                         r->method = NGX_HTTP_HEAD;
                     }
 
+                } else if (p - m == 5) {
+
+                    if (m[0] == 'M' && m[1] == 'K'
+                        && m[2] == 'C' && m[3] == 'O' && m[4] == 'L')
+                    {
+                        r->method = NGX_HTTP_MKCOL;
+                    }
+
                 } else if (p - m == 6) {
 
                     if (m[0] == 'D' && m[1] == 'E' && m[2] == 'L'
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -133,6 +133,14 @@ ngx_http_header_t  ngx_http_headers_in[]
                  ngx_http_process_header_line },
 #endif
 
+#if (NGX_HTTP_DAV)
+    { ngx_string("Depth"), offsetof(ngx_http_headers_in_t, depth),
+                 ngx_http_process_header_line },
+
+    { ngx_string("Destination"), offsetof(ngx_http_headers_in_t, destination),
+                 ngx_http_process_header_line },
+#endif
+
     { ngx_string("Cookie"), 0, ngx_http_process_cookie },
 
     { ngx_null_string, 0, NULL }
@@ -1403,7 +1411,10 @@ ngx_http_finalize_request(ngx_http_reque
         return;
     }
 
-    if (rc >= NGX_HTTP_SPECIAL_RESPONSE || rc == NGX_HTTP_NO_CONTENT) {
+    if (rc >= NGX_HTTP_SPECIAL_RESPONSE
+        || rc == NGX_HTTP_CREATED
+        || rc == NGX_HTTP_NO_CONTENT)
+    {
 
         if (rc == NGX_HTTP_CLOSE) {
             ngx_http_close_request(r, rc);
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -25,6 +25,7 @@
 #define NGX_HTTP_POST                      0x0008
 #define NGX_HTTP_PUT                       0x0010
 #define NGX_HTTP_DELETE                    0x0020
+#define NGX_HTTP_MKCOL                     0x0040
 
 #define NGX_HTTP_CONNECTION_CLOSE          1
 #define NGX_HTTP_CONNECTION_KEEP_ALIVE     2
@@ -61,9 +62,11 @@
 #define NGX_HTTP_NOT_FOUND                 404
 #define NGX_HTTP_NOT_ALLOWED               405
 #define NGX_HTTP_REQUEST_TIME_OUT          408
+#define NGX_HTTP_CONFLICT                  409
 #define NGX_HTTP_LENGTH_REQUIRED           411
 #define NGX_HTTP_REQUEST_ENTITY_TOO_LARGE  413
 #define NGX_HTTP_REQUEST_URI_TOO_LARGE     414
+#define NGX_HTTP_UNSUPPORTED_MEDIA_TYPE    415
 #define NGX_HTTP_RANGE_NOT_SATISFIABLE     416
 
 
@@ -96,6 +99,7 @@
 #define NGX_HTTP_BAD_GATEWAY               502
 #define NGX_HTTP_SERVICE_UNAVAILABLE       503
 #define NGX_HTTP_GATEWAY_TIME_OUT          504
+#define NGX_HTTP_INSUFFICIENT_STORAGE      507
 
 
 #define NGX_HTTP_LOWLEVEL_BUFFERED         0x000000f0
@@ -170,6 +174,11 @@ typedef struct {
     ngx_table_elt_t                  *accept_language;
 #endif
 
+#if (NGX_HTTP_DAV)
+    ngx_table_elt_t                  *depth;
+    ngx_table_elt_t                  *destination;
+#endif
+
     ngx_str_t                         user;
     ngx_str_t                         passwd;
 
@@ -384,6 +393,7 @@ struct ngx_http_request_s {
     unsigned                          request_body_in_persistent_file:1;
     unsigned                          request_body_delete_incomplete_file:1;
     unsigned                          request_body_file_group_access:1;
+    unsigned                          request_body_file_log_level:3;
 
     unsigned                          fast_subrequest:1;
 
--- a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -354,6 +354,7 @@ ngx_http_write_request_body(ngx_http_req
         tf->path = clcf->client_body_temp_path;
         tf->pool = r->pool;
         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;
 
         if (r->request_body_file_group_access) {
--- a/src/http/ngx_http_script.c
+++ b/src/http/ngx_http_script.c
@@ -1074,6 +1074,24 @@ ngx_http_script_set_var_code(ngx_http_sc
 
 
 void
+ngx_http_script_var_set_handler_code(ngx_http_script_engine_t *e)
+{
+    ngx_http_script_var_handler_code_t  *code;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
+                   "http script set var handler");
+
+    code = (ngx_http_script_var_handler_code_t *) e->ip;
+
+    e->ip += sizeof(ngx_http_script_var_handler_code_t);
+
+    e->sp--;
+
+    code->handler(e->request, e->sp, code->data);
+}
+
+
+void
 ngx_http_script_var_code(ngx_http_script_engine_t *e)
 {
     ngx_http_variable_value_t   *value;
--- a/src/http/ngx_http_script.h
+++ b/src/http/ngx_http_script.h
@@ -76,6 +76,13 @@ typedef struct {
 
 
 typedef struct {
+    ngx_http_script_code_pt         code;
+    ngx_http_set_variable_pt        handler;
+    uintptr_t                       data;
+} ngx_http_script_var_handler_code_t;
+
+
+typedef struct {
     ngx_http_script_code_pt          code;
     uintptr_t                        n;
 } ngx_http_script_copy_capture_code_t;
@@ -193,6 +200,7 @@ void ngx_http_script_file_code(ngx_http_
 void ngx_http_script_complex_value_code(ngx_http_script_engine_t *e);
 void ngx_http_script_value_code(ngx_http_script_engine_t *e);
 void ngx_http_script_set_var_code(ngx_http_script_engine_t *e);
+void ngx_http_script_var_set_handler_code(ngx_http_script_engine_t *e);
 void ngx_http_script_var_code(ngx_http_script_engine_t *e);
 void ngx_http_script_nop_code(ngx_http_script_engine_t *e);
 
--- a/src/http/ngx_http_special_response.c
+++ b/src/http/ngx_http_special_response.c
@@ -107,6 +107,14 @@ static char error_408_page[] =
 ;
 
 
+static char error_409_page[] =
+"<html>" CRLF
+"<head><title>409 Conflict</title></head>" CRLF
+"<body bgcolor=\"white\">" CRLF
+"<center><h1>409 Conflict</h1></center>" CRLF
+;
+
+
 static char error_410_page[] =
 "<html>" CRLF
 "<head><title>410 Gone</title></head>" CRLF
@@ -139,6 +147,14 @@ static char error_414_page[] =
 ;
 
 
+static char error_415_page[] =
+"<html>" CRLF
+"<head><title>415 Unsupported Media Type</title></head>" CRLF
+"<body bgcolor=\"white\">" CRLF
+"<center><h1>415 Unsupported Media Type</h1></center>" CRLF
+;
+
+
 static char error_416_page[] =
 "<html>" CRLF
 "<head><title>416 Requested Range Not Satisfiable</title></head>" CRLF
@@ -197,6 +213,14 @@ static char error_504_page[] =
 ;
 
 
+static char error_507_page[] =
+"<html>" CRLF
+"<head><title>507 Insufficient Storage</title></head>" CRLF
+"<body bgcolor=\"white\">" CRLF
+"<center><h1>507 Insufficient Storage</h1></center>" CRLF
+;
+
+
 static ngx_str_t error_pages[] = {
 
     ngx_null_string,             /* 201, 204 */
@@ -219,13 +243,13 @@ static ngx_str_t error_pages[] = {
     ngx_string(error_406_page),
     ngx_null_string,             /* 407 */
     ngx_string(error_408_page),
-    ngx_null_string,             /* 409 */
+    ngx_string(error_409_page),
     ngx_string(error_410_page),
     ngx_string(error_411_page),
     ngx_null_string,             /* 412 */
     ngx_string(error_413_page),
     ngx_string(error_414_page),
-    ngx_null_string,             /* 415 */
+    ngx_string(error_415_page),
     ngx_string(error_416_page),
 
 #define NGX_HTTP_LEVEL_400  17
@@ -238,7 +262,10 @@ static ngx_str_t error_pages[] = {
     ngx_string(error_501_page),
     ngx_string(error_502_page),
     ngx_string(error_503_page),
-    ngx_string(error_504_page)
+    ngx_string(error_504_page),
+    ngx_null_string,             /* 505 */
+    ngx_null_string,             /* 506 */
+    ngx_string(error_507_page)
 };
 
 
@@ -323,6 +350,7 @@ ngx_http_special_response_handler(ngx_ht
     if (error == NGX_HTTP_CREATED) {
         /* 201 */
         err = 0;
+        r->header_only = 1;
 
     } else if (error == NGX_HTTP_NO_CONTENT) {
         /* 204 */
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -249,13 +249,13 @@ static ngx_http_log_op_name_t  ngx_http_
 
 static ngx_http_variable_t  ngx_http_upstream_vars[] = {
 
-    { ngx_string("upstream_status"),
+    { ngx_string("upstream_status"), NULL,
       ngx_http_upstream_status_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },
 
-    { ngx_string("upstream_response_time"),
+    { ngx_string("upstream_response_time"), NULL,
       ngx_http_upstream_response_time_variable, 0, NGX_HTTP_VAR_NOHASH, 0 },
 
-    { ngx_null_string, NULL, 0, 0, 0 }
+    { ngx_null_string, NULL, NULL, 0, 0, 0 }
 };
 
 
@@ -2399,7 +2399,7 @@ ngx_http_upstream_add_variables(ngx_conf
             return NGX_ERROR;
         }
 
-        var->handler = v->handler;
+        var->get_handler = v->get_handler;
         var->data = v->data;
     }
 
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -12,6 +12,8 @@
 
 static ngx_int_t ngx_http_variable_request(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
+static void ngx_http_variable_request_set_size(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data);
 static ngx_int_t ngx_http_variable_header(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
 static ngx_int_t ngx_http_variable_headers(ngx_http_request_t *r,
@@ -59,88 +61,97 @@ static ngx_int_t ngx_http_variable_reque
 
 static ngx_http_variable_t  ngx_http_core_variables[] = {
 
-    { ngx_string("http_host"), ngx_http_variable_header,
+    { ngx_string("http_host"), NULL, ngx_http_variable_header,
       offsetof(ngx_http_request_t, headers_in.host), 0, 0 },
 
-    { ngx_string("http_user_agent"), ngx_http_variable_header,
+    { ngx_string("http_user_agent"), NULL, ngx_http_variable_header,
       offsetof(ngx_http_request_t, headers_in.user_agent), 0, 0 },
 
-    { ngx_string("http_referer"), ngx_http_variable_header,
+    { ngx_string("http_referer"), NULL, ngx_http_variable_header,
       offsetof(ngx_http_request_t, headers_in.referer), 0, 0 },
 
 #if (NGX_HTTP_GZIP)
-    { ngx_string("http_via"), ngx_http_variable_header,
+    { ngx_string("http_via"), NULL, ngx_http_variable_header,
       offsetof(ngx_http_request_t, headers_in.via), 0, 0 },
 #endif
 
 #if (NGX_HTTP_PROXY)
-    { ngx_string("http_x_forwarded_for"), ngx_http_variable_header,
+    { ngx_string("http_x_forwarded_for"), NULL, ngx_http_variable_header,
       offsetof(ngx_http_request_t, headers_in.x_forwarded_for), 0, 0 },
 #endif
 
-    { ngx_string("http_cookie"), ngx_http_variable_headers,
+    { ngx_string("http_cookie"), NULL, ngx_http_variable_headers,
       offsetof(ngx_http_request_t, headers_in.cookies), 0, 0 },
 
-    { ngx_string("content_length"), ngx_http_variable_header,
+    { ngx_string("content_length"), NULL, ngx_http_variable_header,
       offsetof(ngx_http_request_t, headers_in.content_length), 0, 0 },
 
-    { ngx_string("content_type"), ngx_http_variable_header,
+    { ngx_string("content_type"), NULL, ngx_http_variable_header,
       offsetof(ngx_http_request_t, headers_in.content_type), 0, 0 },
 
-    { ngx_string("host"), ngx_http_variable_host, 0, 0, 0 },
+    { ngx_string("host"), NULL, ngx_http_variable_host, 0, 0, 0 },
 
-    { ngx_string("remote_addr"), ngx_http_variable_remote_addr, 0, 0, 0 },
+    { ngx_string("remote_addr"), NULL, ngx_http_variable_remote_addr, 0, 0, 0 },
 
-    { ngx_string("remote_port"), ngx_http_variable_remote_port, 0, 0, 0 },
+    { ngx_string("remote_port"), NULL, ngx_http_variable_remote_port, 0, 0, 0 },
 
-    { ngx_string("server_addr"), ngx_http_variable_server_addr, 0, 0, 0 },
+    { ngx_string("server_addr"), NULL, ngx_http_variable_server_addr, 0, 0, 0 },
 
-    { ngx_string("server_port"), ngx_http_variable_server_port, 0, 0, 0 },
+    { ngx_string("server_port"), NULL, ngx_http_variable_server_port, 0, 0, 0 },
 
-    { ngx_string("server_protocol"), ngx_http_variable_request,
+    { ngx_string("server_protocol"), NULL, ngx_http_variable_request,
       offsetof(ngx_http_request_t, http_protocol), 0, 0 },
 
-    { ngx_string("request_uri"), ngx_http_variable_request,
+    { ngx_string("request_uri"), NULL, ngx_http_variable_request,
       offsetof(ngx_http_request_t, unparsed_uri), 0, 0 },
 
-    { ngx_string("uri"), ngx_http_variable_request,
+    { ngx_string("uri"), NULL, ngx_http_variable_request,
+      offsetof(ngx_http_request_t, uri),
+      NGX_HTTP_VAR_NOCACHABLE, 0 },
+
+    { ngx_string("document_uri"), NULL, ngx_http_variable_request,
       offsetof(ngx_http_request_t, uri),
       NGX_HTTP_VAR_NOCACHABLE, 0 },
 
-    { ngx_string("document_uri"), ngx_http_variable_request,
-      offsetof(ngx_http_request_t, uri),
-      NGX_HTTP_VAR_NOCACHABLE, 0 },
-
-    { ngx_string("request"), ngx_http_variable_request,
+    { ngx_string("request"), NULL, ngx_http_variable_request,
       offsetof(ngx_http_request_t, request_line), 0, 0 },
 
-    { ngx_string("document_root"), ngx_http_variable_document_root, 0, 0, 0 },
+    { ngx_string("document_root"), NULL,
+      ngx_http_variable_document_root, 0, 0, 0 },
 
-    { ngx_string("query_string"), ngx_http_variable_request,
+    { ngx_string("query_string"), NULL, ngx_http_variable_request,
       offsetof(ngx_http_request_t, args),
       NGX_HTTP_VAR_NOCACHABLE, 0 },
 
-    { ngx_string("args"), ngx_http_variable_request,
+    { ngx_string("args"), NULL, ngx_http_variable_request,
       offsetof(ngx_http_request_t, args),
       NGX_HTTP_VAR_NOCACHABLE, 0 },
 
-    { ngx_string("request_filename"), ngx_http_variable_request_filename, 0,
+    { ngx_string("request_filename"), NULL,
+      ngx_http_variable_request_filename, 0,
       NGX_HTTP_VAR_NOCACHABLE, 0 },
 
-    { ngx_string("server_name"), ngx_http_variable_request,
+    { ngx_string("server_name"), NULL, ngx_http_variable_request,
       offsetof(ngx_http_request_t, server_name), 0, 0 },
 
-    { ngx_string("request_method"), ngx_http_variable_request_method, 0, 0, 0 },
+    { ngx_string("request_method"), NULL,
+      ngx_http_variable_request_method, 0, 0, 0 },
 
-    { ngx_string("remote_user"), ngx_http_variable_remote_user, 0, 0, 0 },
+    { ngx_string("remote_user"), NULL, ngx_http_variable_remote_user, 0, 0, 0 },
 
-    { ngx_string("body_bytes_sent"), ngx_http_variable_body_bytes_sent,
+    { ngx_string("body_bytes_sent"), NULL, ngx_http_variable_body_bytes_sent,
       0, 0, 0 },
 
-    { ngx_string("request_completion"), ngx_http_variable_request_completion,
+    { ngx_string("request_completion"), NULL,
+      ngx_http_variable_request_completion,
       0, 0, 0 },
 
-    { ngx_null_string, NULL, 0, 0, 0 }
+    { ngx_string("limit_rate"), ngx_http_variable_request_set_size,
+      ngx_http_variable_request,
+      offsetof(ngx_http_request_t, limit_rate),
+      NGX_HTTP_VAR_CHANGABLE|NGX_HTTP_VAR_NOCACHABLE, 0 },
+
+    { ngx_null_string, NULL, NULL, 0, 0, 0 }
 };
 
 
@@ -195,7 +206,8 @@ ngx_http_add_variable(ngx_conf_t *cf, ng
         v->name.data[i] = ngx_tolower(name->data[i]);
     }
 
-    v->handler = NULL;
+    v->set_handler = NULL;
+    v->get_handler = NULL;
     v->data = 0;
     v->flags = flags;
     v->index = 0;
@@ -261,7 +273,8 @@ ngx_http_get_variable_index(ngx_conf_t *
         v->name.data[i] = ngx_tolower(name->data[i]);
     }
 
-    v->handler = NULL;
+    v->set_handler = NULL;
+    v->get_handler = NULL;
     v->data = 0;
     v->flags = 0;
     v->index = cmcf->variables.nelts - 1;
@@ -290,8 +303,9 @@ ngx_http_get_indexed_variable(ngx_http_r
 
     v = cmcf->variables.elts;
 
-    if (v[index].handler(r, &r->variables[index], v[index].data) == NGX_OK) {
-
+    if (v[index].get_handler(r, &r->variables[index], v[index].data)
+        == NGX_OK)
+    {
         if (v[index].flags & NGX_HTTP_VAR_NOCACHABLE) {
             r->variables[index].no_cachable = 1;
         }
@@ -343,7 +357,7 @@ ngx_http_get_variable(ngx_http_request_t
 
             vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
 
-            if (vv && v->handler(r, vv, v->data) == NGX_OK) {
+            if (vv && v->get_handler(r, vv, v->data) == NGX_OK) {
                 return vv;
             }
 
@@ -412,6 +426,32 @@ ngx_http_variable_request(ngx_http_reque
 }
 
 
+static void
+ngx_http_variable_request_set_size(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data)
+{
+    ssize_t    s, *sp;
+    ngx_str_t  val;
+
+    val.len = v->len & 0xffff;
+    val.data = v->data;
+
+    s = ngx_parse_size(&val);
+
+    if (s == NGX_ERROR) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "invalid size \"%V\"", &val);
+        return;
+    }
+
+    sp = (ssize_t *) ((char *) r + data);
+
+    *sp = s;
+
+    return;
+}
+
+
 static ngx_int_t
 ngx_http_variable_header(ngx_http_request_t *r, ngx_http_variable_value_t *v,
     uintptr_t data)
@@ -900,7 +940,7 @@ ngx_http_variables_init_vars(ngx_conf_t 
             {
                 av = key[n].value;
 
-                v[i].handler = av->handler;
+                v[i].get_handler = av->get_handler;
                 v[i].data = av->data;
 
                 av->flags |= NGX_HTTP_VAR_INDEXED;
@@ -913,14 +953,14 @@ ngx_http_variables_init_vars(ngx_conf_t 
         }
 
         if (ngx_strncmp(v[i].name.data, "http_", 5) == 0) {
-            v[i].handler = ngx_http_variable_unknown_header_in;
+            v[i].get_handler = ngx_http_variable_unknown_header_in;
             v[i].data = (uintptr_t) &v[i].name;
 
             continue;
         }
 
         if (ngx_strncmp(v[i].name.data, "sent_http_", 10) == 0) {
-            v[i].handler = ngx_http_variable_unknown_header_out;
+            v[i].get_handler = ngx_http_variable_unknown_header_out;
             v[i].data = (uintptr_t) &v[i].name;
 
             continue;
--- a/src/http/ngx_http_variables.h
+++ b/src/http/ngx_http_variables.h
@@ -28,6 +28,8 @@ typedef struct {
 
 typedef struct ngx_http_variable_s  ngx_http_variable_t;
 
+typedef void (*ngx_http_set_variable_pt) (ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data);
 typedef ngx_int_t (*ngx_http_get_variable_pt) (ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
 
@@ -40,7 +42,8 @@ typedef ngx_int_t (*ngx_http_get_variabl
 
 struct ngx_http_variable_s {
     ngx_str_t                     name;   /* must be first to build the hash */
-    ngx_http_get_variable_pt      handler;
+    ngx_http_set_variable_pt      set_handler;
+    ngx_http_get_variable_pt      get_handler;
     uintptr_t                     data;
     ngx_uint_t                    flags;
     ngx_uint_t                    index;
--- a/src/os/unix/ngx_errno.h
+++ b/src/os/unix/ngx_errno.h
@@ -14,6 +14,7 @@
 
 typedef int               ngx_err_t;
 
+#define NGX_EPERM         EPERM
 #define NGX_ENOENT        ENOENT
 #define NGX_ESRCH         ESRCH
 #define NGX_EINTR         EINTR