changeset 266:251bcd11a5b8 NGINX_0_5_3

nginx 0.5.3 *) Feature: the ngx_http_perl_module supports the $r->status, $r->log_error, and $r->sleep methods. *) Feature: the $r->variable method supports variables that do not exist in nginx configuration. *) Bugfix: the $r->has_request_body method did not work.
author Igor Sysoev <http://sysoev.ru>
date Wed, 13 Dec 2006 00:00:00 +0300
parents 3d4634b3b321
children fb0eff2f3efe
files CHANGES CHANGES.ru src/core/nginx.h src/core/ngx_inet.c src/core/ngx_inet.h src/http/modules/ngx_http_fastcgi_module.c src/http/modules/ngx_http_log_module.c src/http/modules/ngx_http_memcached_module.c src/http/modules/ngx_http_proxy_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/modules/perl/ngx_http_perl_module.h src/http/ngx_http_core_module.c src/http/ngx_http_upstream.c src/http/ngx_http_upstream.h src/http/ngx_http_upstream_round_robin.c src/imap/ngx_imap_auth_http_module.c src/imap/ngx_imap_core_module.c
diffstat 19 files changed, 399 insertions(+), 150 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,22 @@
 
+Changes with nginx 0.5.3                                         13 Dec 2006
+
+    *) Feature: the ngx_http_perl_module supports the $r->status, 
+       $r->log_error, and $r->sleep methods.
+
+    *) Feature: the $r->variable method supports variables that do not 
+       exist in nginx configuration.
+
+    *) Bugfix: the $r->has_request_body method did work.
+
+
+Changes with nginx 0.5.2                                         11 Dec 2006
+
+    *) Bugfix: if the "proxy_pass" directive used the name of the 
+       "upstream" block, then nginx tried to resolve the name; bug appeared 
+       in 0.5.1.
+
+
 Changes with nginx 0.5.1                                         11 Dec 2006
 
     *) Bugfix: the "post_action" directive might not run after a 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,22 @@
 
+Изменения в nginx 0.5.3                                           13.12.2006
+
+    *) Добавление: модуль ngx_http_perl_module поддерживает методы 
+       $r->status, $r->log_error и $r->sleep.
+
+    *) Добавление: метод $r->variable поддерживает переменные, неописанные 
+       в конфигурации nginx'а.
+
+    *) Исправление: метод $r->has_request_body не работал.
+
+
+Изменения в nginx 0.5.2                                           11.12.2006
+
+    *) Исправление: если в директивах proxy_pass использовалось имя, 
+       указанное в upstream, то nginx пытался найти IP-адрес этого имени; 
+       ошибка появилась в 0.5.1.
+
+
 Изменения в nginx 0.5.1                                           11.12.2006
 
     *) Исправление: директива post_action могла не работать после 
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VERSION      "0.5.2"
+#define NGINX_VERSION      "0.5.3"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_inet.c
+++ b/src/core/ngx_inet.c
@@ -221,8 +221,8 @@ ngx_ptocidr(ngx_str_t *text, void *cidr)
 ngx_int_t
 ngx_parse_url(ngx_conf_t *cf, ngx_url_t *u)
 {
-    u_char              *p, *host;
-    size_t               len;
+    u_char              *p, *host, *port_start;
+    size_t               len, port_len;
     ngx_int_t            port;
     ngx_uint_t           i;
     struct hostent      *h;
@@ -290,8 +290,7 @@ ngx_parse_url(ngx_conf_t *cf, ngx_url_t 
         u->host.len = len;
         u->host.data = p;
 
-        u->host_header.len = sizeof("localhost") - 1;
-        u->host_header.data = (u_char *) "localhost";
+        u->unix_socket = 1;
 
         return NGX_OK;
 
@@ -309,17 +308,18 @@ ngx_parse_url(ngx_conf_t *cf, ngx_url_t 
     }
 
     u->host.data = p;
-    u->host_header.len = len;
-    u->host_header.data = p;
+
+    port_start = NULL;
+    port_len = 0;
 
     for (i = 0; i < len; i++) {
 
         if (p[i] == ':') {
-            u->port.data = &p[i + 1];
+            port_start = &p[i + 1];
             u->host.len = i;
 
             if (!u->uri_part) {
-                u->port.len = len - (i + 1);
+                port_len = len - (i + 1);
                 break;
             }
         }
@@ -327,20 +327,19 @@ ngx_parse_url(ngx_conf_t *cf, ngx_url_t 
         if (p[i] == '/') {
             u->uri.len = len - i;
             u->uri.data = &p[i];
-            u->host_header.len = i;
 
             if (u->host.len == 0) {
                 u->host.len = i;
             }
 
-            if (u->port.data == NULL) {
+            if (port_start == NULL) {
                 u->no_port = 1;
                 goto no_port;
             }
 
-            u->port.len = &p[i] - u->port.data;
+            port_len = &p[i] - port_start;
 
-            if (u->port.len == 0) {
+            if (port_len == 0) {
                 u->err = "invalid port";
                 return NGX_ERROR;
             }
@@ -349,18 +348,18 @@ ngx_parse_url(ngx_conf_t *cf, ngx_url_t 
         }
     }
 
-    if (u->port.data) {
+    if (port_start) {
 
-        if (u->port.len == 0) {
-            u->port.len = &p[i] - u->port.data;
+        if (port_len == 0) {
+            port_len = &p[i] - port_start;
 
-            if (u->port.len == 0) {
+            if (port_len == 0) {
                 u->err = "invalid port";
                 return NGX_ERROR;
             }
         }
 
-        port = ngx_atoi(u->port.data, u->port.len);
+        port = ngx_atoi(port_start, port_len);
 
         if (port == NGX_ERROR || port < 1 || port > 65536) {
             u->err = "invalid port";
@@ -377,24 +376,22 @@ ngx_parse_url(ngx_conf_t *cf, ngx_url_t 
             goto no_port;
         }
 
-        u->port.len = len;
-        u->port.data = p;
         u->wildcard = 1;
     }
 
-    u->portn = (in_port_t) port;
+    u->port = (in_port_t) port;
 
 no_port:
 
     if (u->listen) {
 
-        if (u->portn == 0) {
-            if (u->default_portn == 0) {
+        if (u->port == 0) {
+            if (u->default_port == 0) {
                 u->err = "no port";
                 return NGX_ERROR;
             }
 
-            u->portn = u->default_portn;
+            u->port = u->default_port;
         }
 
         if (u->host.len == 1 && u->host.data[0] == '*') {
@@ -422,7 +419,7 @@ no_port:
                     return NGX_ERROR;
                 }
 
-                u->addr.in_addr = *(in_addr_t *)(h->h_addr_list[0]);
+                u->addr.in_addr = *(in_addr_t *) (h->h_addr_list[0]);
             }
 
         } else {
@@ -432,28 +429,6 @@ no_port:
         return NGX_OK;
     }
 
-    if (u->no_port) {
-
-        if (u->default_portn == 0 && !u->upstream) {
-            u->err = "no port";
-            return NGX_ERROR;
-        }
-
-        u->portn = u->default_portn;
-
-        u->port.data = ngx_palloc(cf->pool, sizeof("65536") - 1);
-        if (u->port.data == NULL) {
-            return NGX_ERROR;
-        }
-
-        u->port.len = ngx_sprintf(u->port.data, "%d", u->portn) - u->port.data;
-
-    } else if (u->portn == 0) {
-
-        u->err = "no port";
-        return NGX_ERROR;
-    }
-
     if (u->host.len == 0) {
         u->err = "no host";
         return NGX_ERROR;
@@ -463,6 +438,15 @@ no_port:
         return NGX_OK;
     }
 
+    if (u->no_port) {
+        u->port = u->default_port;
+    }
+
+    if (u->port == 0) {
+        u->err = "no port";
+        return NGX_ERROR;
+    }
+
     if (ngx_inet_resolve_host(cf, u) != NGX_OK) {
         return NGX_ERROR;
     }
@@ -474,7 +458,7 @@ no_port:
 ngx_int_t
 ngx_inet_resolve_host(ngx_conf_t *cf, ngx_url_t *u)
 {
-    u_char              *host;
+    u_char              *p, *host;
     size_t               len;
     in_addr_t            in_addr;
     ngx_uint_t           i;
@@ -524,7 +508,7 @@ ngx_inet_resolve_host(ngx_conf_t *cf, ng
             }
 
             sin->sin_family = AF_INET;
-            sin->sin_port = htons(u->portn);
+            sin->sin_port = htons(u->port);
             sin->sin_addr.s_addr = *(in_addr_t *) (h->h_addr_list[i]);
 
             u->addrs[i].sockaddr = (struct sockaddr *) sin;
@@ -532,17 +516,15 @@ ngx_inet_resolve_host(ngx_conf_t *cf, ng
 
             len = INET_ADDRSTRLEN - 1 + 1 + sizeof(":65536") - 1;
 
-            u->addrs[i].name.data = ngx_palloc(cf->pool, len);
-            if (u->addrs[i].name.data == NULL) {
+            p = ngx_palloc(cf->pool, len);
+            if (p == NULL) {
                 return NGX_ERROR;
             }
 
-            len = ngx_sock_ntop(AF_INET, (struct sockaddr *) sin,
-                                u->addrs[i].name.data, len);
+            len = ngx_sock_ntop(AF_INET, (struct sockaddr *) sin, p, len);
 
-            u->addrs[i].name.len = ngx_sprintf(&u->addrs[i].name.data[len],
-                                               ":%d", u->portn)
-                                      - u->addrs[i].name.data;
+            u->addrs[i].name.len = ngx_sprintf(&p[len], ":%d", u->port) - p;
+            u->addrs[i].name.data = p;
         }
 
     } else {
@@ -562,21 +544,19 @@ ngx_inet_resolve_host(ngx_conf_t *cf, ng
         u->naddrs = 1;
 
         sin->sin_family = AF_INET;
-        sin->sin_port = htons(u->portn);
+        sin->sin_port = htons(u->port);
         sin->sin_addr.s_addr = in_addr;
 
         u->addrs[0].sockaddr = (struct sockaddr *) sin;
         u->addrs[0].socklen = sizeof(struct sockaddr_in);
 
-        u->addrs[0].name.data = ngx_palloc(cf->pool,
-                                           u->host.len + sizeof(":65536") - 1);
-        if (u->addrs[0].name.data == NULL) {
+        p = ngx_palloc(cf->pool, u->host.len + sizeof(":65536") - 1);
+        if (p == NULL) {
             return NGX_ERROR;
         }
 
-        u->addrs[0].name.len = ngx_sprintf(u->addrs[0].name.data, "%V:%d",
-                                           &u->host, u->portn)
-                                  - u->addrs[0].name.data;
+        u->addrs[0].name.len = ngx_sprintf(p, "%V:%d", &u->host, u->port) - p;
+        u->addrs[0].name.data = p;
     }
 
     return NGX_OK;
--- a/src/core/ngx_inet.h
+++ b/src/core/ngx_inet.h
@@ -35,21 +35,19 @@ typedef struct {
 
     ngx_str_t         url;
     ngx_str_t         host;
-    ngx_str_t         host_header;
-    ngx_str_t         port;
     ngx_str_t         uri;
 
-    in_port_t         portn;
-    in_port_t         default_portn;
+    in_port_t         port;
+    in_port_t         default_port;
 
     unsigned          listen:1;
     unsigned          uri_part:1;
-    unsigned          upstream:1;
     unsigned          no_resolve:1;
     unsigned          one_addr:1;
 
     unsigned          wildcard:1;
     unsigned          no_port:1;
+    unsigned          unix_socket:1;
 
     ngx_url_addr_t    addr;
 
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -2010,7 +2010,6 @@ ngx_http_fastcgi_pass(ngx_conf_t *cf, ng
     ngx_memzero(&u, sizeof(ngx_url_t));
 
     u.url = value[1];
-    u.upstream = 1;
     u.no_resolve = 1;
 
     lcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
--- a/src/http/modules/ngx_http_log_module.c
+++ b/src/http/modules/ngx_http_log_module.c
@@ -546,6 +546,8 @@ ngx_http_log_merge_loc_conf(ngx_conf_t *
                 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;
 
--- a/src/http/modules/ngx_http_memcached_module.c
+++ b/src/http/modules/ngx_http_memcached_module.c
@@ -583,7 +583,6 @@ ngx_http_memcached_pass(ngx_conf_t *cf, 
     ngx_memzero(&u, sizeof(ngx_url_t));
 
     u.url = value[1];
-    u.upstream = 1;
     u.no_resolve = 1;
     /* u.uri_part = 1;  may be used as namespace */
 
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -51,7 +51,7 @@ typedef struct {
 
     ngx_str_t                      method;
     ngx_str_t                      host_header;
-    ngx_str_t                      port_text;
+    ngx_str_t                      port;
 
     ngx_flag_t                     redirect;
 } ngx_http_proxy_loc_conf_t;
@@ -1232,11 +1232,11 @@ ngx_http_proxy_port_variable(ngx_http_re
 
     plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
 
-    v->len = plcf->port_text.len;
+    v->len = plcf->port.len;
     v->valid = 1;
     v->no_cachable = 0;
     v->not_found = 0;
-    v->data = plcf->port_text.data;
+    v->data = plcf->port.data;
 
     return NGX_OK;
 }
@@ -1817,7 +1817,7 @@ peers:
         conf->upstream.upstream = prev->upstream.upstream;
 
         conf->host_header = prev->host_header;
-        conf->port_text = prev->port_text;
+        conf->port = prev->port;
         conf->upstream.schema = prev->upstream.schema;
     }
 
@@ -2093,6 +2093,7 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_
 {
     ngx_http_proxy_loc_conf_t *plcf = conf;
 
+    u_char                      *p;
     size_t                       add;
     u_short                      port;
     ngx_str_t                   *value, *url;
@@ -2158,18 +2159,49 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_
 
     u.url.len = url->len - add;
     u.url.data = url->data + add;
-    u.default_portn = port;
-    u.upstream = 1;
+    u.default_port = port;
+    u.uri_part = 1;
     u.no_resolve = 1;
-    u.uri_part = 1;
 
     plcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
     if (plcf->upstream.upstream == NULL) {
         return NGX_CONF_ERROR;
     }
 
-    plcf->host_header = u.host_header;
-    plcf->port_text = u.port;
+    if (!u.unix_socket) {
+        if (u.no_port || u.port == port) {
+            plcf->host_header = u.host;
+
+            if (port == 80) {
+                plcf->port.len = sizeof("80") - 1;
+                plcf->port.data = (u_char *) "80";
+            } else {
+                plcf->port.len = sizeof("443") - 1;
+                plcf->port.data = (u_char *) "443";
+            }
+
+        } else {
+            p = ngx_palloc(cf->pool, u.host.len + sizeof(":65536") - 1);
+            if (p == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            plcf->host_header.len = ngx_sprintf(p, "%V:%d", &u.host, u.port)
+                                        - p;
+            plcf->host_header.data = p;
+
+            plcf->port.len = plcf->host_header.len -  u.host.len - 1;
+            plcf->port.data = p + u.host.len + 1;
+        }
+
+
+    } else {
+        plcf->host_header.len = sizeof("localhost") - 1;
+        plcf->host_header.data = (u_char *) "localhost";
+        plcf->port.len = 0;
+        plcf->port.data = (u_char *) "";
+    }
+
     plcf->upstream.uri = u.uri;
 
     plcf->upstream.schema.len = add;
--- a/src/http/modules/perl/nginx.pm
+++ b/src/http/modules/perl/nginx.pm
@@ -11,26 +11,85 @@ our @ISA = qw(Exporter);
 our @EXPORT = qw(
     OK
     DECLINED
+
     HTTP_OK
+    HTTP_CREATED
+    HTTP_NO_CONTENT
+    HTTP_PARTIAL_CONTENT
+
+    HTTP_MOVED_PERMANENTLY
+    HTTP_MOVED_TEMPORARILY
     HTTP_REDIRECT
+    HTTP_NOT_MODIFIED
+
+    HTTP_BAD_REQUEST
+    HTTP_UNAUTHORIZED
+    HTTP_PAYMENT_REQUIRED
+    HTTP_FORBIDDEN
     HTTP_NOT_FOUND
+    HTTP_NOT_ALLOWED
+    HTTP_NOT_ACCEPTABLE
+    HTTP_REQUEST_TIME_OUT
+    HTTP_CONFLICT
+    HTTP_GONE
+    HTTP_LENGTH_REQUIRED
+    HTTP_REQUEST_ENTITY_TOO_LARGE
+    HTTP_REQUEST_URI_TOO_LARGE
+    HTTP_UNSUPPORTED_MEDIA_TYPE
+    HTTP_RANGE_NOT_SATISFIABLE
+
+    HTTP_INTERNAL_SERVER_ERROR
     HTTP_SERVER_ERROR
+    HTTP_NOT_IMPLEMENTED
+    HTTP_BAD_GATEWAY
+    HTTP_SERVICE_UNAVAILABLE
+    HTTP_GATEWAY_TIME_OUT
+    HTTP_INSUFFICIENT_STORAGE
 );
 
-our $VERSION = '0.5.2';
+our $VERSION = '0.5.3';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
 
 # Preloaded methods go here.
 
-use constant OK                   => 0;
-use constant DECLINED             => -5;
+use constant OK                             => 0;
+use constant DECLINED                       => -5;
+
+use constant HTTP_OK                        => 200;
+use constant HTTP_CREATED                   => 201;
+use constant HTTP_NO_CONTENT                => 204;
+use constant HTTP_PARTIAL_CONTENT           => 206;
+
+use constant HTTP_MOVED_PERMANENTLY         => 301;
+use constant HTTP_MOVED_TEMPORARILY         => 302;
+use constant HTTP_REDIRECT                  => 302;
+use constant HTTP_NOT_MODIFIED              => 304;
 
-use constant HTTP_OK              => 200;
-use constant HTTP_REDIRECT        => 302;
-use constant HTTP_NOT_FOUND       => 404;
-use constant HTTP_SERVER_ERROR    => 500;
+use constant HTTP_BAD_REQUEST               => 400;
+use constant HTTP_UNAUTHORIZED              => 401;
+use constant HTTP_PAYMENT_REQUIRED          => 402;
+use constant HTTP_FORBIDDEN                 => 403;
+use constant HTTP_NOT_FOUND                 => 404;
+use constant HTTP_NOT_ALLOWED               => 405;
+use constant HTTP_NOT_ACCEPTABLE            => 406;
+use constant HTTP_REQUEST_TIME_OUT          => 408;
+use constant HTTP_CONFLICT                  => 409;
+use constant HTTP_GONE                      => 410;
+use constant HTTP_LENGTH_REQUIRED           => 411;
+use constant HTTP_REQUEST_ENTITY_TOO_LARGE  => 413;
+use constant HTTP_REQUEST_URI_TOO_LARGE     => 414;
+use constant HTTP_UNSUPPORTED_MEDIA_TYPE    => 415;
+use constant HTTP_RANGE_NOT_SATISFIABLE     => 416;
+
+use constant HTTP_INTERNAL_SERVER_ERROR     => 500;
+use constant HTTP_SERVER_ERROR              => 500;
+use constant HTTP_NOT_IMPLEMENTED           => 501;
+use constant HTTP_BAD_GATEWAY               => 502;
+use constant HTTP_SERVICE_UNAVAILABLE       => 503;
+use constant HTTP_GATEWAY_TIME_OUT          => 504;
+use constant HTTP_INSUFFICIENT_STORAGE      => 507;
 
 
 1;
--- a/src/http/modules/perl/nginx.xs
+++ b/src/http/modules/perl/nginx.xs
@@ -94,6 +94,22 @@ MODULE = nginx    PACKAGE = nginx
 
 
 void
+status(r, code)
+    CODE:
+
+    ngx_http_request_t  *r;
+
+    ngx_http_perl_set_request(r);
+
+    r->headers_out.status = SvIV(ST(1));
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "perl status: %d", r->headers_out.status);
+
+    XSRETURN_UNDEF;
+
+
+void
 send_http_header(r, ...)
     CODE:
 
@@ -334,7 +350,6 @@ has_request_body(r, next)
 
     dXSTARG;
     ngx_http_request_t   *r;
-    SV                   *next;
     ngx_http_perl_ctx_t  *ctx;
 
     ngx_http_perl_set_request(r);
@@ -343,10 +358,8 @@ has_request_body(r, next)
         XSRETURN_UNDEF;
     }
 
-    next = ST(1);
-
     ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
-    ctx->next = next;
+    ctx->next = SvRV(ST(1));
 
     r->request_body_in_single_buf = 1;
     r->request_body_in_persistent_file = 1;
@@ -776,6 +789,8 @@ variable(r, name, value = NULL)
     STRLEN                      len;
     ngx_str_t                   var, val;
     ngx_uint_t                  i, hash;
+    ngx_http_perl_var_t        *v;
+    ngx_http_perl_ctx_t        *ctx;
     ngx_http_variable_value_t  *vv;
 
     ngx_http_perl_set_request(r);
@@ -817,13 +832,69 @@ variable(r, name, value = NULL)
     var.len = len;
     var.data = lowcase;
 
+    #if (NGX_LOG_DEBUG)
+
+    if (value) {
+        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "perl variable: \"%V\"=\"%V\"", &var, &val);
+    } else {
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "perl variable: \"%V\"", &var);
+    }
+
+    #endif
+
     vv = ngx_http_get_variable(r, &var, hash, 1);
     if (vv == NULL) {
         XSRETURN_UNDEF;
     }
 
     if (vv->not_found) {
-        if (value == NULL) {
+
+        ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
+
+        if (ctx->variables) {
+
+            v = ctx->variables->elts;
+            for (i = 0; i < ctx->variables->nelts; i++) {
+
+                if (hash != v[i].hash
+                    || len != v[i].name.len
+                    || ngx_strncmp(lowcase, v[i].name.data, len) != 0)
+                {
+                    continue;
+                }
+
+                if (value) {
+                    v[i].value = val;
+                    XSRETURN_UNDEF;
+                }
+
+                ngx_http_perl_set_targ(v[i].value.data, v[i].value.len, 0);
+
+                goto done;
+            }
+        }
+
+        if (value) {
+            if (ctx->variables == NULL) {
+                ctx->variables = ngx_array_create(r->pool, 1,
+                                                  sizeof(ngx_http_perl_var_t));
+                if (ctx->variables == NULL) {
+                    XSRETURN_UNDEF;
+                }
+            }
+
+            v = ngx_array_push(ctx->variables);
+            if (v == NULL) {
+                XSRETURN_UNDEF;
+            }
+
+            v->hash = hash;
+            v->name.len = len;
+            v->name.data = lowcase;
+            v->value = val;
+
             XSRETURN_UNDEF;
         }
 
@@ -845,4 +916,60 @@ variable(r, name, value = NULL)
 
     ngx_http_perl_set_targ(vv->data, vv->len, 0);
 
+    done:
+
     ST(0) = TARG;
+
+
+void
+sleep(r, sleep, next)
+    CODE:
+
+    dXSTARG;
+    ngx_http_request_t   *r;
+    ngx_http_perl_ctx_t  *ctx;
+
+    ngx_http_perl_set_request(r);
+
+    ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module);
+
+    ctx->sleep = SvIV(ST(1));
+    ctx->next = SvRV(ST(2));
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "perl sleep: %d", ctx->sleep);
+
+    XSRETURN_EMPTY;
+
+
+void
+log_error(r, err, msg)
+    CODE:
+
+    ngx_http_request_t  *r;
+    SV                  *err, *msg;
+    u_char              *p;
+    STRLEN               len;
+    ngx_err_t            e;
+
+    ngx_http_perl_set_request(r);
+
+    err = ST(1);
+
+    if (SvROK(err) && SvTYPE(SvRV(err)) == SVt_PV) {
+        err = SvRV(err);
+    }
+
+    e = SvIV(err);
+
+    msg = ST(2);
+
+    if (SvROK(msg) && SvTYPE(SvRV(msg)) == SVt_PV) {
+        msg = SvRV(msg);
+    }
+
+    p = (u_char *) SvPV(msg, len);
+
+    ngx_log_error(NGX_LOG_ERR, r->connection->log, e, "perl: %s", p);
+
+    XSRETURN_EMPTY;
--- a/src/http/modules/perl/ngx_http_perl_module.c
+++ b/src/http/modules/perl/ngx_http_perl_module.c
@@ -41,6 +41,7 @@ static ngx_int_t ngx_http_perl_ssi(ngx_h
     ngx_http_ssi_ctx_t *ssi_ctx, ngx_str_t **params);
 #endif
 
+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 *
@@ -62,7 +63,6 @@ static char *ngx_http_perl_require(ngx_c
     void *conf);
 static char *ngx_http_perl(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 static char *ngx_http_perl_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
-static void ngx_http_perl_cleanup_sv(void *data);
 
 #if (NGX_HAVE_PERL_MULTIPLICITY)
 static void ngx_http_perl_cleanup_perl(void *data);
@@ -246,6 +246,12 @@ ngx_http_perl_handle_request(ngx_http_re
     ctx->filename.data = NULL;
     ctx->redirect_uri.len = 0;
 
+    if (ctx->sleep) {
+        ngx_add_timer(r->connection->write, (ngx_msec_t) ctx->sleep);
+        r->write_event_handler = ngx_http_perl_sleep_handler;
+        ctx->sleep = 0;
+    }
+
     if (ctx->done || ctx->next) {
         return;
     }
@@ -264,6 +270,28 @@ ngx_http_perl_handle_request(ngx_http_re
 }
 
 
+static void
+ngx_http_perl_sleep_handler(ngx_http_request_t *r)
+{
+    ngx_event_t  *wev;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "perl sleep handler");
+
+    wev = r->connection->write;
+
+    if (wev->timedout) {
+        wev->timedout = 0;
+        ngx_http_perl_handle_request(r);
+        return;
+    }
+
+    if (ngx_handle_write_event(wev, 0) == NGX_ERROR) {
+        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+    }
+}
+
+
 static ngx_int_t
 ngx_http_perl_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
     uintptr_t data)
@@ -758,18 +786,6 @@ ngx_http_perl_cleanup_perl(void *data)
 #endif
 
 
-static void
-ngx_http_perl_cleanup_sv(void *data)
-{
-    ngx_http_perl_cleanup_t  *cln = data;
-
-    dTHXa(cln->perl);
-    PERL_SET_CONTEXT(cln->perl);
-
-    SvREFCNT_dec(cln->sv);
-}
-
-
 static ngx_int_t
 ngx_http_perl_preconfiguration(ngx_conf_t *cf)
 {
@@ -860,8 +876,6 @@ ngx_http_perl(ngx_conf_t *cf, ngx_comman
     ngx_http_perl_loc_conf_t *plcf = conf;
 
     ngx_str_t                  *value;
-    ngx_pool_cleanup_t         *cln;
-    ngx_http_perl_cleanup_t    *pcln;
     ngx_http_core_loc_conf_t   *clcf;
     ngx_http_perl_main_conf_t  *pmcf;
 
@@ -881,11 +895,6 @@ ngx_http_perl(ngx_conf_t *cf, ngx_comman
         }
     }
 
-    cln = ngx_pool_cleanup_add(cf->pool, sizeof(ngx_http_perl_cleanup_t));
-    if (cln == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
     plcf->handler = value[1];
 
     {
@@ -907,11 +916,6 @@ ngx_http_perl(ngx_conf_t *cf, ngx_comman
 
     }
 
-    cln->handler = ngx_http_perl_cleanup_sv;
-    pcln = cln->data;
-    pcln->sv = plcf->sub;
-    pcln->perl = pmcf->perl;
-
     clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
     clcf->handler = ngx_http_perl_handler;
 
@@ -924,9 +928,7 @@ ngx_http_perl_set(ngx_conf_t *cf, ngx_co
 {
     ngx_int_t                   index;
     ngx_str_t                  *value;
-    ngx_pool_cleanup_t         *cln;
     ngx_http_variable_t        *v;
-    ngx_http_perl_cleanup_t    *pcln;
     ngx_http_perl_variable_t   *pv;
     ngx_http_perl_main_conf_t  *pmcf;
 
@@ -964,11 +966,6 @@ ngx_http_perl_set(ngx_conf_t *cf, ngx_co
         }
     }
 
-    cln = ngx_pool_cleanup_add(cf->pool, sizeof(ngx_http_perl_cleanup_t));
-    if (cln == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
     pv->handler = value[2];
 
     {
@@ -990,11 +987,6 @@ ngx_http_perl_set(ngx_conf_t *cf, ngx_co
 
     }
 
-    cln->handler = ngx_http_perl_cleanup_sv;
-    pcln = cln->data;
-    pcln->sv = pv->sub;
-    pcln->perl = pmcf->perl;
-
     v->get_handler = ngx_http_perl_variable;
     v->data = (uintptr_t) pv;
 
--- a/src/http/modules/perl/ngx_http_perl_module.h
+++ b/src/http/modules/perl/ngx_http_perl_module.h
@@ -23,16 +23,27 @@ typedef struct {
     ngx_str_t                 filename;
     ngx_str_t                 redirect_uri;
     ngx_str_t                 redirect_args;
+
     SV                       *next;
+    int                       sleep;
 
     ngx_uint_t                done;   /* unsigned  done:1; */
 
+    ngx_array_t              *variables;  /* array of ngx_http_perl_var_t */
+
 #if (NGX_HTTP_SSI)
     ngx_http_ssi_ctx_t       *ssi;
 #endif
 } ngx_http_perl_ctx_t;
 
 
+typedef struct {
+    ngx_uint_t    hash;
+    ngx_str_t     name;
+    ngx_str_t     value;
+} ngx_http_perl_var_t;
+
+
 extern ngx_module_t  ngx_http_perl_module;
 
 
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -2390,7 +2390,7 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx
 
     u.url = value[1];
     u.listen = 1;
-    u.default_portn = 80;
+    u.default_port = 80;
 
     if (ngx_parse_url(cf, &u) != NGX_OK) {
         if (u.err) {
@@ -2411,7 +2411,7 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx
 
     ls->family = AF_INET;
     ls->addr = u.addr.in_addr;
-    ls->port = u.portn;
+    ls->port = u.port;
     ls->file_name = cf->conf_file->file.name;
     ls->line = cf->conf_file->line;
     ls->conf.backlog = -1;
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -2598,7 +2598,6 @@ ngx_http_upstream(ngx_conf_t *cf, ngx_co
 
     value = cf->args->elts;
     u.host = value[1];
-    u.upstream = 1;
     u.no_resolve = 1;
 
     uscf = ngx_http_upstream_add(cf, &u, NGX_HTTP_UPSTREAM_CREATE
@@ -2722,7 +2721,7 @@ ngx_http_upstream_server(ngx_conf_t *cf,
     ngx_memzero(&u, sizeof(ngx_url_t));
 
     u.url = value[1];
-    u.default_portn = 80;
+    u.default_port = 80;
 
     if (ngx_parse_url(cf, &u) != NGX_OK) {
         if (u.err) {
@@ -2843,8 +2842,8 @@ ngx_http_upstream_add(ngx_conf_t *cf, ng
     uscfp = umcf->upstreams.elts;
 
     for (i = 0; i < umcf->upstreams.nelts; i++) {
-        if ((uscfp[i]->port && uscfp[i]->port != u->portn)
-            || uscfp[i]->host.len != u->host.len
+
+        if (uscfp[i]->host.len != u->host.len
             || ngx_strncasecmp(uscfp[i]->host.data, u->host.data, u->host.len)
                != 0)
         {
@@ -2859,10 +2858,23 @@ ngx_http_upstream_add(ngx_conf_t *cf, ng
             return NULL;
         }
 
-        if (uscfp[i]->port == 0 && u->portn && !u->no_port) {
+        if ((uscfp[i]->flags & NGX_HTTP_UPSTREAM_CREATE) && u->port) {
             ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
-                               "upstream \"%V\" port %d is ignored",
-                               &u->host, u->portn);
+                               "upstream \"%V\" may not have port %d",
+                               &u->host, u->port);
+            return NULL;
+        }
+
+        if ((flags & NGX_HTTP_UPSTREAM_CREATE) && uscfp[i]->port) {
+            ngx_log_error(NGX_LOG_WARN, cf->log, 0,
+                          "upstream \"%V\" may not have port %d in %s:%ui",
+                          &u->host, uscfp[i]->port,
+                          uscfp[i]->file_name.data, uscfp[i]->line);
+            return NULL;
+        }
+
+        if (uscfp[i]->port != u->port) {
+            continue;
         }
 
         return uscfp[i];
@@ -2877,7 +2889,8 @@ ngx_http_upstream_add(ngx_conf_t *cf, ng
     uscf->host = u->host;
     uscf->file_name = cf->conf_file->file.name;
     uscf->line = cf->conf_file->line;
-    uscf->port = u->portn;
+    uscf->port = u->port;
+    uscf->default_port = u->default_port;
 
     if (u->naddrs == 1) {
         uscf->servers = ngx_array_create(cf->pool, 1,
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -94,6 +94,7 @@ struct ngx_http_upstream_srv_conf_s {
     ngx_str_t                       file_name;
     ngx_uint_t                      line;
     in_port_t                       port;
+    in_port_t                       default_port;
 };
 
 
--- a/src/http/ngx_http_upstream_round_robin.c
+++ b/src/http/ngx_http_upstream_round_robin.c
@@ -61,10 +61,17 @@ ngx_http_upstream_init_round_robin(ngx_c
 
     /* an upstream implicitly defined by proxy_pass, etc. */
 
+    if (us->port == 0 && us->default_port == 0) {
+        ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+                      "no port in upstream \"%V\" in %s:%ui",
+                      &us->host, us->file_name.data, us->line);
+        return NGX_ERROR;
+    }
+
     ngx_memzero(&u, sizeof(ngx_url_t));
 
     u.host = us->host;
-    u.portn = us->port;
+    u.port = (in_port_t) (us->port ? us->port : us->default_port);
 
     if (ngx_inet_resolve_host(cf, &u) != NGX_OK) {
         if (u.err) {
@@ -76,13 +83,6 @@ ngx_http_upstream_init_round_robin(ngx_c
         return NGX_ERROR;
     }
 
-    if (us->port == 0) {
-        ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
-                      "no port in upstream \"%V\" in %s:%ui",
-                      &us->host, us->file_name.data, us->line);
-        return NGX_ERROR;
-    }
-
     n = u.naddrs;
 
     peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t)
--- a/src/imap/ngx_imap_auth_http_module.c
+++ b/src/imap/ngx_imap_auth_http_module.c
@@ -1291,7 +1291,7 @@ ngx_imap_auth_http(ngx_conf_t *cf, ngx_c
     ngx_memzero(&u, sizeof(ngx_url_t));
 
     u.url = value[1];
-    u.default_portn = 80;
+    u.default_port = 80;
     u.uri_part = 1;
     u.one_addr = 1;
 
@@ -1304,7 +1304,7 @@ ngx_imap_auth_http(ngx_conf_t *cf, ngx_c
 
     ahcf->peer = u.addrs;
 
-    ahcf->host_header = u.host_header;
+    ahcf->host_header = u.host;
     ahcf->uri = u.uri;
 
     if (ahcf->uri.len == 0) {
--- a/src/imap/ngx_imap_core_module.c
+++ b/src/imap/ngx_imap_core_module.c
@@ -541,7 +541,7 @@ ngx_imap_core_listen(ngx_conf_t *cf, ngx
 
     for (i = 0; i < cmcf->listen.nelts; i++) {
 
-        if (imls[i].addr != u.addr.in_addr || imls[i].port != u.portn) {
+        if (imls[i].addr != u.addr.in_addr || imls[i].port != u.port) {
             continue;
         }
 
@@ -558,7 +558,7 @@ ngx_imap_core_listen(ngx_conf_t *cf, ngx
     ngx_memzero(imls, sizeof(ngx_imap_listen_t));
 
     imls->addr = u.addr.in_addr;
-    imls->port = u.portn;
+    imls->port = u.port;
     imls->family = AF_INET;
     imls->ctx = cf->ctx;