changeset 200:d2ae1c9f1fd3 NGINX_0_3_47

nginx 0.3.47 *) Feature: the "upstream" directive. *) Change: now the "\" escape symbol in the "\"" and "\'" pairs in the SSI command is always removed.
author Igor Sysoev <http://sysoev.ru>
date Tue, 23 May 2006 00:00:00 +0400
parents 869664706c09
children 958c1992c173
files CHANGES CHANGES.ru src/core/nginx.h src/core/ngx_conf_file.h src/core/ngx_core.h src/core/ngx_cpuinfo.c src/core/ngx_inet.c src/core/ngx_inet.h src/core/ngx_parse.c src/event/ngx_event_connect.h src/http/modules/ngx_http_empty_gif_module.c src/http/modules/ngx_http_fastcgi_module.c src/http/modules/ngx_http_proxy_module.c src/http/modules/ngx_http_ssi_filter_module.c src/http/modules/perl/ngx_http_perl_module.c src/http/ngx_http_core_module.c src/http/ngx_http_request.c src/http/ngx_http_request.h src/http/ngx_http_upstream.c src/http/ngx_http_upstream.h
diffstat 20 files changed, 899 insertions(+), 257 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,12 @@
 
+Changes with nginx 0.3.47                                        23 May 2006
+
+    *) Feature: the "upstream" directive.
+
+    *) Change: now the "\" escape symbol in the "\"" and "\'" pairs in the 
+       SSI command is always removed.
+
+
 Changes with nginx 0.3.46                                        11 May 2006
 
     *) Feature: the "proxy_hide_header", "proxy_pass_header", 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,10 +1,18 @@
 
+Изменения в nginx 0.3.47                                          23.05.2006
+
+    *) Добавление: директива upstream.
+
+    *) Изменение: символ "\" в парах "\"" и "\'" в SSI командах теперь 
+       всегда убирается.
+
+
 Изменения в nginx 0.3.46                                          11.05.2006
 
     *) Добавление: директивы proxy_hide_header, proxy_pass_header, 
        fastcgi_hide_header и fastcgi_pass_header.
 
-    *) Изменение: директивы proxy_x_powered_by, fastcgi_x_powered_by и 
+    *) Изменение: директивы proxy_pass_x_powered_by, fastcgi_x_powered_by и 
        proxy_pass_server упразднены.
 
     *) Добавление: в режиме прокси поддерживается строка заголовка 
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VER          "nginx/0.3.46"
+#define NGINX_VER          "nginx/0.3.47"
 
 #define NGINX_VAR          "NGINX"
 #define NGX_OLDPID_EXT     ".oldbin"
--- a/src/core/ngx_conf_file.h
+++ b/src/core/ngx_conf_file.h
@@ -61,7 +61,7 @@
 
 
 #define NGX_CONF_OK          NULL
-#define NGX_CONF_ERROR       (char *) -1
+#define NGX_CONF_ERROR       (void *) -1
 
 #define NGX_CONF_BLOCK_START 1
 #define NGX_CONF_BLOCK_DONE  2
--- a/src/core/ngx_core.h
+++ b/src/core/ngx_core.h
@@ -63,6 +63,9 @@ typedef void (*ngx_connection_handler_pt
 #include <ngx_radix_tree.h>
 #include <ngx_times.h>
 #include <ngx_shmtx.h>
+#if (NGX_OPENSSL)
+#include <ngx_event_openssl.h>
+#endif
 #include <ngx_inet.h>
 #if (NGX_HAVE_UNIX_DOMAIN)
 #include <ngx_unix_domain.h>
@@ -71,9 +74,6 @@ typedef void (*ngx_connection_handler_pt
 #include <ngx_process_cycle.h>
 #include <ngx_conf_file.h>
 #include <ngx_os.h>
-#if (NGX_OPENSSL)
-#include <ngx_event_openssl.h>
-#endif
 #include <ngx_connection.h>
 
 
--- a/src/core/ngx_cpuinfo.c
+++ b/src/core/ngx_cpuinfo.c
@@ -31,16 +31,14 @@ ngx_cpuid(uint32_t i, uint32_t *buf)
     "    mov    %%ebx, %%esi;  "
 
     "    cpuid;                "
-    "    mov    %%eax, %0;     "
-    "    mov    %%ebx, %1;     "
-    "    mov    %%edx, %2;     "
-    "    mov    %%ecx, %3;     "
+    "    mov    %%eax, (%1);   "
+    "    mov    %%ebx, 4(%1);  "
+    "    mov    %%edx, 8(%1);  "
+    "    mov    %%ecx, 12(%1); "
 
     "    mov    %%esi, %%ebx;  "
 
-    : "=m" (buf[0]), "=m" (buf[1]), "=m" (buf[2]), "=m" (buf[3])
-    : "a" (i)
-    : "ecx", "edx", "esi" );
+    : : "a" (i), "D" (buf) : "ecx", "edx", "esi", "memory" );
 }
 
 
--- a/src/core/ngx_inet.c
+++ b/src/core/ngx_inet.c
@@ -220,6 +220,339 @@ 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;
+    size_t               len;
+    ngx_int_t            port;
+    ngx_uint_t           i;
+#if (NGX_HAVE_UNIX_DOMAIN)
+    struct sockaddr_un  *saun;
+#endif
+
+    len = u->url.len;
+    p = u->url.data;
+
+    if (ngx_strncasecmp(p, "unix:", 5) == 0) {
+
+#if (NGX_HAVE_UNIX_DOMAIN)
+
+        u->type = NGX_PARSE_URL_UNIX;
+
+        p += 5;
+        len -= 5;
+
+        if (u->uri_part) {
+            for (i = 0; i < len; i++) {
+
+                if (p[i] == ':') {
+                    len = i;
+
+                    u->uri.len -= len + 1;
+                    u->uri.data += len + 1;
+
+                    break;
+                }
+            }
+        }
+
+        if (len == 0) {
+            u->err = "no path in the unix domain socket";
+            return NGX_ERROR;
+        }
+
+        if (len + 1 > sizeof(saun->sun_path)) {
+            u->err = "too long path in the unix domain socket";
+            return NGX_ERROR;
+        }
+
+        u->peers = ngx_pcalloc(cf->pool, sizeof(ngx_peers_t));
+        if (u->peers == NULL) {
+            return NGX_ERROR;
+        }
+
+        saun = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_un));
+        if (saun == NULL) {
+            return NGX_ERROR;
+        }
+
+        u->peers->number = 1;
+
+        saun->sun_family = AF_UNIX;
+        (void) ngx_cpystrn((u_char *) saun->sun_path, p, len + 1);
+
+        u->peers->peer[0].sockaddr = (struct sockaddr *) saun;
+        u->peers->peer[0].socklen = sizeof(struct sockaddr_un);
+        u->peers->peer[0].name = u->url;
+        u->peers->peer[0].uri_separator = ":";
+
+        u->host_header.len = sizeof("localhost") - 1;
+        u->host_header.data = (u_char *) "localhost";
+
+        return NGX_OK;
+
+#else
+        u->err = "the unix domain sockets are not supported on this platform";
+
+        return NGX_ERROR;
+
+#endif
+    }
+
+    if ((p[0] == ':' || p[0] == '/') && !u->listen) {
+        u->err = "invalid host";
+        return NGX_ERROR;
+    }
+
+    u->type = NGX_PARSE_URL_INET;
+
+    u->host.data = p;
+    u->host_header.len = len;
+    u->host_header.data = p;
+
+    for (i = 0; i < len; i++) {
+
+        if (p[i] == ':') {
+            u->port.data = &p[i + 1];
+            u->host.len = i;
+
+            if (!u->uri_part) {
+                u->port.len = &p[len] - u->port.data;
+                break;
+            }
+        }
+
+        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) {
+                u->default_port = 1;
+                goto port;
+            }
+
+            u->port.len = &p[i] - u->port.data;
+
+            if (u->port.len == 0) {
+                u->err = "invalid port";
+                return NGX_ERROR;
+            }
+
+            break;
+        }
+    }
+
+    if (u->port.data) {
+
+        if (u->port.len == 0) {
+            u->port.len = &p[i] - u->port.data;
+
+            if (u->port.len == 0) {
+                u->err = "invalid port";
+                return NGX_ERROR;
+            }
+        }
+
+        port = ngx_atoi(u->port.data, u->port.len);
+
+        if (port == NGX_ERROR || port < 1 || port > 65536) {
+            u->err = "invalid port";
+            return NGX_ERROR;
+        }
+
+    } else {
+        port = ngx_atoi(p, len);
+
+        if (port == NGX_ERROR) {
+            u->default_port = 1;
+            u->host.len = len;
+
+            goto port;
+        }
+
+        u->port.len = len;
+        u->port.data = p;
+        u->wildcard = 1;
+    }
+
+    u->portn = (in_port_t) port;
+
+port:
+
+    if (u->listen) {
+        return NGX_OK;
+    }
+
+    if (u->default_port) {
+
+        if (u->upstream) {
+            return NGX_OK;
+        }
+
+        if (u->default_portn == 0) {
+            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) {
+        if (u->portn == u->default_portn) {
+            u->default_port = 1;
+        }
+
+    } else {
+        u->err = "no port";
+        return NGX_ERROR;
+    }
+
+    if (u->host.len == 0) {
+        u->err = "no host";
+        return NGX_ERROR;
+    }
+
+    u->peers = ngx_inet_resolve_peer(cf, &u->host, u->portn);
+
+    if (u->peers == NULL) {
+        return NGX_ERROR;
+    }
+
+    if (u->peers == NGX_CONF_ERROR) {
+        u->err = "host not found";
+        return NGX_ERROR;
+    }
+
+    return NGX_OK;
+}
+
+
+ngx_peers_t *
+ngx_inet_resolve_peer(ngx_conf_t *cf, ngx_str_t *name, in_port_t port)
+{
+    u_char              *host;
+    size_t               len;
+    in_addr_t            in_addr;
+    ngx_uint_t           i;
+    ngx_peers_t         *peers;
+    struct hostent      *h;
+    struct sockaddr_in  *sin;
+
+    host = ngx_palloc(cf->temp_pool, name->len + 1);
+    if (host == NULL) {
+        return NULL;
+    }
+
+    (void) ngx_cpystrn(host, name->data, name->len + 1);
+
+    /* AF_INET only */
+
+    in_addr = inet_addr((char *) host);
+
+    if (in_addr == INADDR_NONE) {
+        h = gethostbyname((char *) host);
+
+        if (h == NULL || h->h_addr_list[0] == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        for (i = 0; h->h_addr_list[i] != NULL; i++) { /* void */ }
+
+        /* MP: ngx_shared_palloc() */
+
+        peers = ngx_pcalloc(cf->pool,
+                            sizeof(ngx_peers_t) + sizeof(ngx_peer_t) * (i - 1));
+        if (peers == NULL) {
+            return NULL;
+        }
+
+        peers->number = i;
+        peers->weight = 1;
+
+        for (i = 0; h->h_addr_list[i] != NULL; i++) {
+
+            sin = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in));
+            if (sin == NULL) {
+                return NULL;
+            }
+
+            sin->sin_family = AF_INET;
+            sin->sin_port = htons(port);
+            sin->sin_addr.s_addr = *(in_addr_t *) (h->h_addr_list[i]);
+
+            peers->peer[i].sockaddr = (struct sockaddr *) sin;
+            peers->peer[i].socklen = sizeof(struct sockaddr_in);
+
+            len = INET_ADDRSTRLEN - 1 + 1 + sizeof(":65536") - 1;
+
+            peers->peer[i].name.data = ngx_palloc(cf->pool, len);
+            if (peers->peer[i].name.data == NULL) {
+                return NULL;
+            }
+
+            len = ngx_sock_ntop(AF_INET, (struct sockaddr *) sin,
+                                peers->peer[i].name.data, len);
+
+            peers->peer[i].name.len =
+                                    ngx_sprintf(&peers->peer[i].name.data[len],
+                                                ":%d", port)
+                                      - peers->peer[i].name.data;
+
+            peers->peer[i].uri_separator = "";
+        }
+
+    } else {
+
+        /* MP: ngx_shared_palloc() */
+
+        peers = ngx_pcalloc(cf->pool, sizeof(ngx_peers_t));
+        if (peers == NULL) {
+            return NULL;
+        }
+
+        sin = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in));
+        if (sin == NULL) {
+            return NULL;
+        }
+
+        peers->number = 1;
+
+        sin->sin_family = AF_INET;
+        sin->sin_port = htons(port);
+        sin->sin_addr.s_addr = in_addr;
+
+        peers->peer[0].sockaddr = (struct sockaddr *) sin;
+        peers->peer[0].socklen = sizeof(struct sockaddr_in);
+
+        peers->peer[0].name.data = ngx_palloc(cf->pool,
+                                              name->len + sizeof(":65536") - 1);
+        if (peers->peer[0].name.data == NULL) {
+            return NULL;
+        }
+
+        peers->peer[0].name.len = ngx_sprintf(peers->peer[0].name.data, "%V:%d",
+                                              name, port)
+                                  - peers->peer[0].name.data;
+
+        peers->peer[0].uri_separator = "";
+    }
+
+    return peers;
+}
+
+
 ngx_peers_t *
 ngx_inet_upstream_parse(ngx_conf_t *cf, ngx_inet_upstream_t *u)
 {
@@ -241,6 +574,7 @@ ngx_inet_upstream_parse(ngx_conf_t *cf, 
     }
 
     if (u->default_port) {
+
         if (u->default_port_value == 0) {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                "no port in upstream \"%V\"", &u->name);
@@ -277,7 +611,7 @@ ngx_inet_upstream_parse(ngx_conf_t *cf, 
 
     u->port = htons(u->port);
 
-    host = ngx_palloc(cf->pool, u->host.len + 1);
+    host = ngx_palloc(cf->temp_pool, u->host.len + 1);
     if (host == NULL) {
         return NULL;
     }
--- a/src/core/ngx_inet.h
+++ b/src/core/ngx_inet.h
@@ -12,6 +12,10 @@
 #include <ngx_core.h>
 
 
+#define NGX_PARSE_URL_INET   1
+#define NGX_PARSE_URL_UNIX   2
+
+
 typedef struct {
     in_addr_t  addr;
     in_addr_t  mask;
@@ -19,6 +23,66 @@ typedef struct {
 
 
 typedef struct {
+    struct sockaddr    *sockaddr;
+    socklen_t           socklen;
+
+    ngx_str_t           name;
+    char               *uri_separator;
+
+    ngx_uint_t          weight;
+
+    ngx_uint_t          fails;
+    time_t              accessed;
+
+    ngx_uint_t          max_fails;
+    time_t              fail_timeout;
+
+#if (NGX_SSL)
+    ngx_ssl_session_t  *ssl_session;
+#endif
+} ngx_peer_t;
+
+
+struct ngx_peers_s {
+    ngx_uint_t          current;
+    ngx_uint_t          weight;
+
+    ngx_uint_t          number;
+    ngx_uint_t          last_cached;
+
+ /* ngx_mutex_t        *mutex; */
+    ngx_connection_t  **cached;
+
+    ngx_peer_t          peer[1];
+};
+
+
+typedef struct {
+    ngx_int_t     type;
+
+    ngx_peers_t  *peers;
+
+    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;
+
+    unsigned      listen:1;
+    unsigned      uri_part:1;
+    unsigned      upstream:1;
+
+    unsigned      default_port:1;
+    unsigned      wildcard:1;
+
+    char         *err;
+} ngx_url_t;
+
+
+typedef struct {
     ngx_str_t     name;           /* "schema:host:port/uri" */
     ngx_str_t     url;            /* "host:port/uri" */
     ngx_str_t     host;
@@ -35,6 +99,7 @@ typedef struct {
 
     unsigned      uri_part:1;
     unsigned      port_only:1;
+    unsigned      virtual:1;
 } ngx_inet_upstream_t;
 
 
@@ -45,7 +110,10 @@ size_t ngx_inet_ntop(int family, void *a
 ngx_int_t ngx_ptocidr(ngx_str_t *text, void *cidr);
 
 ngx_peers_t *ngx_inet_upstream_parse(ngx_conf_t *cf, ngx_inet_upstream_t *u);
+ngx_peers_t *ngx_inet_resolve_peer(ngx_conf_t *cf, ngx_str_t *name,
+    in_port_t port);
 char *ngx_inet_parse_host_port(ngx_inet_upstream_t *u);
+ngx_int_t ngx_parse_url(ngx_conf_t *cf, ngx_url_t *u);
 
 
 #endif /* _NGX_INET_H_INCLUDED_ */
--- a/src/core/ngx_parse.c
+++ b/src/core/ngx_parse.c
@@ -50,10 +50,10 @@ ngx_parse_size(ngx_str_t *line)
 ngx_int_t
 ngx_parse_time(ngx_str_t *line, ngx_int_t sec)
 {
-    size_t      len;
-    u_char     *start, last;
-    ngx_int_t   value, total, scale;
-    ngx_uint_t  max, i;
+    size_t       len;
+    u_char      *start, last;
+    ngx_int_t    value, total, scale;
+    ngx_uint_t   max, i;
     enum {
         st_start = 0,
         st_year,
--- a/src/event/ngx_event_connect.h
+++ b/src/event/ngx_event_connect.h
@@ -14,41 +14,6 @@
 
 
 typedef struct {
-    struct sockaddr    *sockaddr;
-    socklen_t           socklen;
-
-    ngx_str_t           name;
-    char               *uri_separator;
-
-    ngx_uint_t          weight;
-
-    ngx_uint_t          fails;
-    time_t              accessed;
-
-    ngx_uint_t          max_fails;
-    time_t              fail_timeout;
-
-#if (NGX_SSL)
-    ngx_ssl_session_t  *ssl_session;
-#endif
-} ngx_peer_t;
-
-
-struct ngx_peers_s {
-    ngx_uint_t          current;
-    ngx_uint_t          weight;
-
-    ngx_uint_t          number;
-    ngx_uint_t          last_cached;
-
- /* ngx_mutex_t        *mutex; */
-    ngx_connection_t  **cached;
-
-    ngx_peer_t          peer[1];
-};
-
-
-typedef struct {
     ngx_peers_t        *peers;
     ngx_uint_t          cur_peer;
     ngx_uint_t          tries;
--- a/src/http/modules/ngx_http_empty_gif_module.c
+++ b/src/http/modules/ngx_http_empty_gif_module.c
@@ -135,7 +135,7 @@ ngx_http_empty_gif_handler(ngx_http_requ
         }
     }
 
-    b = ngx_create_temp_buf(r->pool, sizeof(ngx_empty_gif));
+    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
     if (b == NULL) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
@@ -145,6 +145,7 @@ ngx_http_empty_gif_handler(ngx_http_requ
 
     b->pos = ngx_empty_gif;
     b->last = ngx_empty_gif + sizeof(ngx_empty_gif);
+    b->memory = 1;
     b->last_buf = 1;
 
     r->headers_out.status = NGX_HTTP_OK;
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -11,16 +11,17 @@
 
 
 typedef struct {
-    ngx_http_upstream_conf_t   upstream;
-
-    ngx_peers_t               *peers;
-
-    ngx_str_t                  index;
-
-    ngx_array_t               *flushes;
-    ngx_array_t               *params_len;
-    ngx_array_t               *params;
-    ngx_array_t               *params_source;
+    ngx_http_upstream_conf_t       upstream;
+
+    ngx_http_upstream_srv_conf_t  *upstream_peers;
+    ngx_peers_t                   *peers0;
+
+    ngx_str_t                      index;
+
+    ngx_array_t                   *flushes;
+    ngx_array_t                   *params_len;
+    ngx_array_t                   *params;
+    ngx_array_t                   *params_source;
 } ngx_http_fastcgi_loc_conf_t;
 
 
@@ -39,14 +40,14 @@ typedef enum {
 
 
 typedef struct {
-    ngx_http_fastcgi_state_e   state;
-    u_char                    *pos;
-    u_char                    *last;
-    ngx_uint_t                 type;
-    size_t                     length;
-    size_t                     padding;
-
-    ngx_uint_t                 fastcgi_stdout;
+    ngx_http_fastcgi_state_e       state;
+    u_char                        *pos;
+    u_char                        *last;
+    ngx_uint_t                     type;
+    size_t                         length;
+    size_t                         padding;
+
+    ngx_uint_t                     fastcgi_stdout;
 } ngx_http_fastcgi_ctx_t;
 
 
@@ -391,8 +392,8 @@ ngx_http_fastcgi_handler(ngx_http_reques
 
     u->peer.log = r->connection->log;
     u->peer.log_error = NGX_ERROR_ERR;
-    u->peer.peers = flcf->peers;
-    u->peer.tries = flcf->peers->number;
+    u->peer.peers = flcf->upstream_peers->peers;
+    u->peer.tries = flcf->upstream_peers->peers->number;
 #if (NGX_THREADS)
     u->peer.lock = &r->connection->lock;
 #endif
@@ -1687,11 +1688,13 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
     ngx_conf_merge_sec_value(conf->upstream.fail_timeout,
                               prev->upstream.fail_timeout, 10);
 
-    if (conf->peers && conf->peers->number > 1) {
-        for (i = 0; i < conf->peers->number; i++) {
-            conf->peers->peer[i].weight = 1;
-            conf->peers->peer[i].max_fails = conf->upstream.max_fails;
-            conf->peers->peer[i].fail_timeout = conf->upstream.fail_timeout;
+    if (conf->upstream_peers && !conf->upstream_peers->balanced) {
+        for (i = 0; i < conf->upstream_peers->peers->number; i++) {
+            conf->upstream_peers->peers->peer[i].weight = 1;
+            conf->upstream_peers->peers->peer[i].max_fails =
+                                                   conf->upstream.max_fails;
+            conf->upstream_peers->peers->peer[i].fail_timeout =
+                                                   conf->upstream.fail_timeout;
         }
     }
 
@@ -1813,8 +1816,8 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
 
 peers:
 
-    if (conf->peers == NULL) {
-        conf->peers = prev->peers;
+    if (conf->upstream_peers == NULL) {
+        conf->upstream_peers = prev->upstream_peers;
         conf->upstream.schema = prev->upstream.schema;
     }
 
@@ -1989,12 +1992,9 @@ ngx_http_fastcgi_pass(ngx_conf_t *cf, ng
 {
     ngx_http_fastcgi_loc_conf_t *lcf = conf;
 
+    ngx_url_t                    u;
     ngx_str_t                   *value;
-    ngx_inet_upstream_t          inet_upstream;
     ngx_http_core_loc_conf_t    *clcf;
-#if (NGX_HAVE_UNIX_DOMAIN)
-    ngx_unix_domain_upstream_t   unix_upstream;
-#endif
 
     if (lcf->upstream.schema.len) {
         return "is duplicate";
@@ -2002,40 +2002,14 @@ ngx_http_fastcgi_pass(ngx_conf_t *cf, ng
 
     value = cf->args->elts;
 
-    if (ngx_strncasecmp(value[1].data, "unix:", 5) == 0) {
-
-#if (NGX_HAVE_UNIX_DOMAIN)
-
-        ngx_memzero(&unix_upstream, sizeof(ngx_unix_domain_upstream_t));
-
-        unix_upstream.name = value[1];
-        unix_upstream.url = value[1];
-
-        lcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream);
-        if (lcf->peers == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        lcf->peers->peer[0].uri_separator = "";
-
-#else
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "the unix domain sockets are not supported "
-                           "on this platform");
+    ngx_memzero(&u, sizeof(ngx_url_t));
+
+    u.url = value[1];
+    u.upstream = 1;
+
+    lcf->upstream_peers = ngx_http_upstream_add(cf, &u);
+    if (lcf->upstream_peers == NULL) {
         return NGX_CONF_ERROR;
-
-#endif
-
-    } else {
-        ngx_memzero(&inet_upstream, sizeof(ngx_inet_upstream_t));
-
-        inet_upstream.name = value[1];
-        inet_upstream.url = value[1];
-
-        lcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream);
-        if (lcf->peers == NULL) {
-            return NGX_CONF_ERROR;
-        }
     }
 
     lcf->upstream.schema.len = sizeof("fastcgi://") - 1;
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -16,56 +16,56 @@ typedef ngx_int_t (*ngx_http_proxy_redir
     ngx_table_elt_t *h, size_t prefix, ngx_http_proxy_redirect_t *pr);
 
 struct ngx_http_proxy_redirect_s {
-    ngx_http_proxy_redirect_pt   handler;
-    ngx_str_t                    redirect;
+    ngx_http_proxy_redirect_pt     handler;
+    ngx_str_t                      redirect;
 
     union {
-        ngx_str_t                text;
+        ngx_str_t                  text;
 
         struct {
-            void                *lengths;
-            void                *values;
+            void                  *lengths;
+            void                  *values;
         } vars;
 
-        void                    *regex;
+        void                      *regex;
     } replacement;
 };
 
 
 typedef struct {
-    ngx_http_upstream_conf_t     upstream;
-
-    ngx_peers_t                 *peers;
-
-    ngx_array_t                 *flushes;
-    ngx_array_t                 *body_set_len;
-    ngx_array_t                 *body_set;
-    ngx_array_t                 *headers_set_len;
-    ngx_array_t                 *headers_set;
-    ngx_hash_t                   headers_set_hash;
-
-    ngx_array_t                 *headers_source;
-    ngx_array_t                 *headers_names;
-
-    ngx_array_t                 *redirects;
-
-    ngx_str_t                    body_source;
-
-    ngx_str_t                    method;
-    ngx_str_t                    host_header;
-    ngx_str_t                    port_text;
-
-    ngx_flag_t                   redirect;
+    ngx_http_upstream_conf_t       upstream;
+
+    ngx_http_upstream_srv_conf_t  *upstream_peers;
+
+    ngx_array_t                   *flushes;
+    ngx_array_t                   *body_set_len;
+    ngx_array_t                   *body_set;
+    ngx_array_t                   *headers_set_len;
+    ngx_array_t                   *headers_set;
+    ngx_hash_t                     headers_set_hash;
+
+    ngx_array_t                   *headers_source;
+    ngx_array_t                   *headers_names;
+
+    ngx_array_t                   *redirects;
+
+    ngx_str_t                      body_source;
+
+    ngx_str_t                      method;
+    ngx_str_t                      host_header;
+    ngx_str_t                      port_text;
+
+    ngx_flag_t                     redirect;
 } ngx_http_proxy_loc_conf_t;
 
 
 typedef struct {
-    ngx_uint_t                   status;
-    ngx_uint_t                   status_count;
-    u_char                      *status_start;
-    u_char                      *status_end;
-
-    size_t                       internal_body_length;
+    ngx_uint_t                     status;
+    ngx_uint_t                     status_count;
+    u_char                        *status_start;
+    u_char                        *status_end;
+
+    size_t                         internal_body_length;
 } ngx_http_proxy_ctx_t;
 
 
@@ -407,8 +407,8 @@ ngx_http_proxy_handler(ngx_http_request_
 
     u->peer.log = r->connection->log;
     u->peer.log_error = NGX_ERROR_ERR;
-    u->peer.peers = plcf->peers;
-    u->peer.tries = plcf->peers->number;
+    u->peer.peers = plcf->upstream_peers->peers;
+    u->peer.tries = plcf->upstream_peers->peers->number;
 #if (NGX_THREADS)
     u->peer.lock = &r->connection->lock;
 #endif
@@ -1640,11 +1640,13 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
     ngx_conf_merge_sec_value(conf->upstream.fail_timeout,
                               prev->upstream.fail_timeout, 10);
 
-    if (conf->peers && conf->peers->number > 1) {
-        for (i = 0; i < conf->peers->number; i++) {
-            conf->peers->peer[i].weight = 1;
-            conf->peers->peer[i].max_fails = conf->upstream.max_fails;
-            conf->peers->peer[i].fail_timeout = conf->upstream.fail_timeout;
+    if (conf->upstream_peers && !conf->upstream_peers->balanced) {
+        for (i = 0; i < conf->upstream_peers->peers->number; i++) {
+            conf->upstream_peers->peers->peer[i].weight = 1;
+            conf->upstream_peers->peers->peer[i].max_fails =
+                                                   conf->upstream.max_fails;
+            conf->upstream_peers->peers->peer[i].fail_timeout =
+                                                   conf->upstream.fail_timeout;
         }
     }
 
@@ -1797,8 +1799,8 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
 
 peers:
 
-    if (conf->peers == NULL) {
-        conf->peers = prev->peers;
+    if (conf->upstream_peers == NULL) {
+        conf->upstream_peers = prev->upstream_peers;
 
         conf->host_header = prev->host_header;
         conf->port_text = prev->port_text;
@@ -2106,14 +2108,11 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_
     size_t                       add;
     u_short                      port;
     ngx_str_t                   *value, *url;
-    ngx_inet_upstream_t          inet_upstream;
+    ngx_url_t                    u;
     ngx_http_core_loc_conf_t    *clcf;
 #if (NGX_HTTP_SSL)
     ngx_pool_cleanup_t          *cln;
 #endif
-#if (NGX_HAVE_UNIX_DOMAIN)
-    ngx_unix_domain_upstream_t   unix_upstream;
-#endif
 
     if (plcf->upstream.schema.len) {
         return "is duplicate";
@@ -2167,53 +2166,23 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_
         return NGX_CONF_ERROR;
     }
 
-    if (ngx_strncasecmp(url->data + add, "unix:", 5) == 0) {
-
-#if (NGX_HAVE_UNIX_DOMAIN)
-
-        ngx_memzero(&unix_upstream, sizeof(ngx_unix_domain_upstream_t));
-
-        unix_upstream.name = *url;
-        unix_upstream.url.len = url->len - add;
-        unix_upstream.url.data = url->data + add;
-        unix_upstream.uri_part = 1;
-
-        plcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream);
-        if (plcf->peers == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        plcf->host_header.len = sizeof("localhost") - 1;
-        plcf->host_header.data = (u_char *) "localhost";
-        plcf->upstream.uri = unix_upstream.uri;
-
-#else
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "the unix domain sockets are not supported "
-                           "on this platform");
+    ngx_memzero(&u, sizeof(ngx_url_t));
+
+    u.url.len = url->len - add;
+    u.url.data = url->data + add;
+    u.default_portn = port;
+    u.uri_part = 1;
+    u.upstream = 1;
+
+    plcf->upstream_peers = ngx_http_upstream_add(cf, &u);
+    if (plcf->upstream_peers == NULL) {
         return NGX_CONF_ERROR;
-
-#endif
-
-    } else {
-        ngx_memzero(&inet_upstream, sizeof(ngx_inet_upstream_t));
-
-        inet_upstream.name = *url;
-        inet_upstream.url.len = url->len - add;
-        inet_upstream.url.data = url->data + add;
-        inet_upstream.default_port_value = port;
-        inet_upstream.uri_part = 1;
-
-        plcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream);
-        if (plcf->peers == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        plcf->host_header = inet_upstream.host_header;
-        plcf->port_text = inet_upstream.port_text;
-        plcf->upstream.uri = inet_upstream.uri;
     }
 
+    plcf->host_header = u.host_header;
+    plcf->port_text = u.port;
+    plcf->upstream.uri = u.uri;
+
     plcf->upstream.schema.len = add;
     plcf->upstream.schema.data = url->data;
 
--- a/src/http/modules/ngx_http_ssi_filter_module.c
+++ b/src/http/modules/ngx_http_ssi_filter_module.c
@@ -1224,38 +1224,14 @@ ngx_http_ssi_parse(ngx_http_request_t *r
         case ssi_quoted_symbol_state:
             state = ctx->saved_state;
 
-            if (ch == '\\') {
-                break;
-            }
-
-            if (ch == '"' && state == ssi_double_quoted_value_state) {
-                ctx->param->value.data[ctx->param->value.len - 1] = ch;
-                break;
-            }
-
-            if (ch == '\'' && state == ssi_quoted_value_state) {
-                ctx->param->value.data[ctx->param->value.len - 1] = ch;
-                break;
-            }
-
-            if (ctx->param->value.len == ctx->value_len) {
-                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                              "too long \"%V%c...\" value of \"%V\" "
-                              "parameter in \"%V\" SSI command",
-                              &ctx->param->value, ch, &ctx->param->key,
-                              &ctx->command);
-                state = ssi_error_state;
-                break;
-            }
-
             ctx->param->value.data[ctx->param->value.len++] = ch;
 
             break;
 
         case ssi_postparam_state:
 
-            if (ctx->param->value.len < ctx->value_len / 2) {
-                value = ngx_palloc(r->pool, ctx->param->value.len);
+            if (ctx->param->value.len + 1 < ctx->value_len / 2) {
+                value = ngx_palloc(r->pool, ctx->param->value.len + 1);
                 if (value == NULL) {
                     return NGX_ERROR;
                 }
@@ -1433,7 +1409,7 @@ ngx_http_ssi_evaluate_string(ngx_http_re
     size_t                     *size, len, prefix, part_len;
     ngx_str_t                   var, *val;
     ngx_int_t                   key;
-    ngx_uint_t                  i, j, n, bracket;
+    ngx_uint_t                  i, j, n, bracket, quoted;
     ngx_array_t                 lengths, values;
     ngx_http_variable_value_t  *vv;
 
@@ -1567,18 +1543,28 @@ ngx_http_ssi_evaluate_string(ngx_http_re
 
         } else {
             part_data = &text->data[i];
+            quoted = 0;
 
             for (p = part_data; i < text->len; i++) {
                 ch = text->data[i];
 
-                if (ch == '$') {
-                    if (text->data[i - 1] != '\\') {
+                if (!quoted) {
+
+                    if (ch == '\\') {
+                        quoted = 1;
+                        continue;
+                    }
+
+                    if (ch == '$') {
                         break;
                     }
 
-                    *(p - 1) = ch;
-
-                    continue;
+                } else {
+                    quoted = 0;
+
+                    if (ch != '\\' && ch != '\'' && ch != '"' && ch != '$') {
+                        *p++ = '\\';
+                    }
                 }
 
                 *p++ = ch;
@@ -2016,7 +2002,7 @@ ngx_http_ssi_if(ngx_http_request_t *r, n
         flags = 0;
 
         if (p < last - 1 && p[0] == '\\' && p[1] == '/') {
-	    p++;
+            p++;
         }
     }
 
--- a/src/http/modules/perl/ngx_http_perl_module.c
+++ b/src/http/modules/perl/ngx_http_perl_module.c
@@ -399,6 +399,24 @@ ngx_http_perl_ssi(ngx_http_request_t *r,
 
     dTHXa(ctx->perl);
 
+#if 0
+
+    /* the code is disabled to force the precompiled perl code using only */
+
+    ngx_http_perl_eval_anon_sub(aTHX_ handler, &sv);
+
+    if (sv == &PL_sv_undef) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                      "eval_pv(\"%V\") failed", handler);
+        return NGX_ERROR;
+    }
+
+    if (sv == NULL) {
+        sv = newSVpvn((char *) handler->data, handler->len);
+    }
+
+#endif
+
     sv = newSVpvn((char *) handler->data, handler->len);
 
     rc = ngx_http_perl_call_handler(aTHX_ r, sv, &params[NGX_HTTP_PERL_SSI_ARG],
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -106,7 +106,7 @@ static ngx_command_t  ngx_http_core_comm
       NULL },
 
     { ngx_string("server"),
-      NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
+      NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_MULTI|NGX_CONF_NOARGS,
       ngx_http_core_server,
       0,
       0,
@@ -506,7 +506,6 @@ ngx_http_handler(ngx_http_request_t *r)
     r->valid_unparsed_uri = 1;
     r->valid_location = 1;
     r->uri_changed = 1;
-    r->uri_changes = NGX_HTTP_MAX_REWRITE_CYCLES + 1;
 
     r->phase = (r == r->main) ? NGX_HTTP_POST_READ_PHASE:
                                 NGX_HTTP_SERVER_REWRITE_PHASE;
@@ -547,7 +546,7 @@ ngx_http_core_run_phases(ngx_http_reques
 
             if (r->uri_changes == 0) {
                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                              "rewrite cycle");
+                              "rewrite or internal redirection cycle");
                 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
                 return;
             }
@@ -1263,6 +1262,8 @@ ngx_http_subrequest(ngx_http_request_t *
     sr->discard_body = r->discard_body;
     sr->main_filter_need_in_memory = r->main_filter_need_in_memory;
 
+    sr->uri_changes = NGX_HTTP_MAX_URI_CHANGES + 1;
+
     ngx_http_handler(sr);
 
     if (!c->destroyed) {
@@ -1331,6 +1332,8 @@ ngx_http_internal_redirect(ngx_http_requ
     r->internal = 1;
     r->method = NGX_HTTP_GET;
 
+    r->uri_changes--;
+
     ngx_http_handler(r);
 
     return NGX_DONE;
@@ -1794,7 +1797,7 @@ ngx_http_core_create_main_conf(ngx_conf_
 
     if (ngx_array_init(&cmcf->servers, cf->pool, 4,
                        sizeof(ngx_http_core_srv_conf_t *))
-        == NGX_ERROR)
+        != NGX_OK)
     {
         return NGX_CONF_ERROR;
     }
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -666,6 +666,8 @@ ngx_http_process_request_line(ngx_event_
                 c->write->handler = ngx_http_request_handler;
                 r->read_event_handler = ngx_http_block_read;
 
+                r->uri_changes = NGX_HTTP_MAX_URI_CHANGES + 1;
+
                 ngx_http_handler(r);
 
                 return;
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -8,7 +8,7 @@
 #define _NGX_HTTP_REQUEST_H_INCLUDED_
 
 
-#define NGX_HTTP_MAX_REWRITE_CYCLES        10
+#define NGX_HTTP_MAX_URI_CHANGES           10
 
 /* must be 2^n */
 #define NGX_HTTP_LC_HEADER_LEN             32
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -85,8 +85,12 @@ static ngx_int_t ngx_http_upstream_statu
 static ngx_int_t ngx_http_upstream_response_time_variable(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
 
+static char *ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy);
+static char *ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd,
+    void *conf);
+
 static void *ngx_http_upstream_create_main_conf(ngx_conf_t *cf);
-static char *ngx_http_core_init_main_conf(ngx_conf_t *cf, void *conf);
+static char *ngx_http_upstream_init_main_conf(ngx_conf_t *cf, void *conf);
 
 #if (NGX_HTTP_SSL)
 static void ngx_http_upstream_ssl_init_connection(ngx_http_request_t *,
@@ -206,12 +210,32 @@ ngx_http_upstream_header_t  ngx_http_ups
 };
 
 
-ngx_http_module_t  ngx_http_upstream_module_ctx = {
+static ngx_command_t  ngx_http_upstream_commands[] = {
+
+    { ngx_string("upstream"),
+      NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE1,
+      ngx_http_upstream,
+      0,
+      0,
+      NULL },
+
+    { ngx_string("server"),
+      NGX_HTTP_UPS_CONF|NGX_CONF_TAKE1,
+      ngx_http_upstream_server,
+      NGX_HTTP_SRV_CONF_OFFSET,
+      0,
+      NULL },
+
+      ngx_null_command
+};
+
+
+static ngx_http_module_t  ngx_http_upstream_module_ctx = {
     ngx_http_upstream_add_variables,       /* preconfiguration */
     NULL,                                  /* postconfiguration */
 
     ngx_http_upstream_create_main_conf,    /* create main configuration */
-    ngx_http_core_init_main_conf,          /* init main configuration */
+    ngx_http_upstream_init_main_conf,      /* init main configuration */
 
     NULL,                                  /* create server configuration */
     NULL,                                  /* merge server configuration */
@@ -224,7 +248,7 @@ ngx_http_module_t  ngx_http_upstream_mod
 ngx_module_t  ngx_http_upstream_module = {
     NGX_MODULE_V1,
     &ngx_http_upstream_module_ctx,         /* module context */
-    NULL,                                  /* module directives */
+    ngx_http_upstream_commands,            /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
     NULL,                                  /* init master */
     NULL,                                  /* init module */
@@ -868,6 +892,14 @@ ngx_http_upstream_send_request_handler(n
 
 #endif
 
+    if (u->header_sent) {
+        wev->handler = ngx_http_upstream_dummy_handler;
+
+        (void) ngx_handle_write_event(wev, 0);
+
+        return;
+    }
+
     ngx_http_upstream_send_request(r, u);
 }
 
@@ -2547,6 +2579,232 @@ ngx_http_upstream_response_time_variable
 }
 
 
+static char *
+ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
+{
+    char                           *rv;
+    void                           *mconf;
+    ngx_str_t                      *value;
+    ngx_url_t                       u;
+    ngx_uint_t                      i, j, m, n;
+    ngx_conf_t                      pcf;
+    ngx_peers_t                   **peers;
+    ngx_http_module_t              *module;
+    ngx_http_conf_ctx_t            *ctx;
+    ngx_http_upstream_srv_conf_t   *uscf;
+
+    ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
+    if (ctx == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    ngx_memzero(&u, sizeof(ngx_url_t));
+
+    value = cf->args->elts;
+    u.host = value[1];
+
+    uscf = ngx_http_upstream_add(cf, &u);
+    if (uscf == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    /* the upstream{}'s srv_conf */
+
+    ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
+    if (ctx->srv_conf == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    ctx->srv_conf[ngx_http_upstream_module.ctx_index] = uscf;
+
+
+    /* the upstream{}'s loc_conf */
+
+    ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
+    if (ctx->loc_conf == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    for (m = 0; ngx_modules[m]; m++) {
+        if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
+            continue;
+        }
+
+        module = ngx_modules[m]->ctx;
+
+        if (module->create_loc_conf) {
+            mconf = module->create_loc_conf(cf);
+            if (mconf == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            ctx->loc_conf[ngx_modules[m]->ctx_index] = mconf;
+        }
+    }
+
+
+    /* parse inside upstream{} */
+
+    pcf = *cf;
+    cf->ctx = ctx;
+    cf->cmd_type = NGX_HTTP_UPS_CONF;
+
+    rv = ngx_conf_parse(cf, NULL);
+
+    *cf = pcf;
+
+    if (rv != NGX_CONF_OK) {
+        return rv;
+    }
+
+    if (uscf->servers == NULL) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "no servers are inside upstream");
+        return NGX_CONF_ERROR;
+    }
+
+    peers = uscf->servers->elts;
+
+    if (uscf->servers->nelts == 1) {
+        uscf->peers = peers[0];
+    }
+
+    n = 0;
+
+    for (i = 0; i < uscf->servers->nelts; i++) {
+        n += peers[i]->number;
+    }
+
+    uscf->peers = ngx_pcalloc(cf->pool,
+                           sizeof(ngx_peers_t) + sizeof(ngx_peer_t) * (n - 1));
+    if (uscf->peers == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    uscf->peers->number = n;
+    uscf->peers->weight = 1;
+
+    n = 0;
+
+    for (i = 0; i < uscf->servers->nelts; i++) {
+        for (j = 0; j < peers[i]->number; j++) {
+            uscf->peers->peer[n++] = peers[i]->peer[j];
+        }
+    }
+
+    return rv;
+}
+
+
+static char *
+ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_upstream_srv_conf_t  *uscf = conf;
+
+    ngx_str_t                    *value;
+    ngx_url_t                     u;
+    ngx_peers_t                 **peers;
+
+    if (uscf->servers == NULL) {
+        uscf->servers = ngx_array_create(cf->pool, 4, sizeof(ngx_peers_t *));
+        if (uscf->servers == NULL) {
+            return NGX_CONF_ERROR;
+        }
+    }
+
+    peers = ngx_array_push(uscf->servers);
+    if (peers == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    value = cf->args->elts;
+
+    ngx_memzero(&u, sizeof(ngx_url_t));
+
+    u.url = value[1];
+    u.default_portn = 80;
+
+    if (ngx_parse_url(cf, &u) != NGX_OK) {
+        if (u.err) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "%s in upstream \"%V\"", u.err, &u.url);
+        }
+
+        return NGX_CONF_ERROR;
+    }
+
+    *peers = u.peers;
+
+    return NGX_CONF_OK;
+}
+
+
+ngx_http_upstream_srv_conf_t *
+ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u)
+{
+    ngx_uint_t                      i;
+    ngx_http_upstream_srv_conf_t   *uscf, **uscfp;
+    ngx_http_upstream_main_conf_t  *umcf;
+
+    if (u->upstream) {
+        if (ngx_parse_url(cf, u) != NGX_OK) {
+            if (u->err) {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                   "%s in upstream \"%V\"", u->err, &u->url);
+            }
+
+            return NULL;
+        }
+
+        if (u->peers) {
+            uscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_srv_conf_t));
+            if (uscf == NULL) {
+                return NULL;
+            }
+
+            uscf->peers = u->peers;
+
+            return uscf;
+        }
+    }
+
+    umcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_upstream_module);
+
+    uscfp = umcf->upstreams.elts;
+
+    for (i = 0; i < umcf->upstreams.nelts; i++) {
+        if (uscfp[i]->host.len != u->host.len) {
+            continue;
+        }
+
+        if (ngx_strncasecmp(uscfp[i]->host.data, u->host.data, u->host.len)
+            == 0)
+        {
+            return uscfp[i];
+        }
+    }
+
+    uscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_srv_conf_t));
+    if (uscf == NULL) {
+        return NULL;
+    }
+
+    uscf->host = u->host;
+    uscf->file_name = cf->conf_file->file.name;
+    uscf->line = cf->conf_file->line;
+    uscf->port = u->default_portn;
+
+    uscfp = ngx_array_push(&umcf->upstreams);
+    if (uscfp == NULL) {
+        return NULL;
+    }
+
+    *uscfp = uscf;
+
+    return uscf;
+}
+
+
 static void *
 ngx_http_upstream_create_main_conf(ngx_conf_t *cf)
 {
@@ -2557,19 +2815,51 @@ ngx_http_upstream_create_main_conf(ngx_c
         return NULL;
     }
 
+    if (ngx_array_init(&umcf->upstreams, cf->pool, 4,
+                       sizeof(ngx_http_upstream_srv_conf_t *))
+        != NGX_OK)
+    {
+        return NGX_CONF_ERROR;
+    }
+
     return umcf;
 }
 
 
 static char *
-ngx_http_core_init_main_conf(ngx_conf_t *cf, void *conf)
+ngx_http_upstream_init_main_conf(ngx_conf_t *cf, void *conf)
 {
     ngx_http_upstream_main_conf_t  *umcf = conf;
 
-    ngx_array_t                  headers_in;
-    ngx_hash_key_t              *hk;
-    ngx_hash_init_t              hash;
-    ngx_http_upstream_header_t  *header;
+    ngx_uint_t                      i;
+    ngx_array_t                     headers_in;
+    ngx_hash_key_t                 *hk;
+    ngx_hash_init_t                 hash;
+    ngx_http_upstream_header_t     *header;
+    ngx_http_upstream_srv_conf_t  **uscfp;
+
+    uscfp = umcf->upstreams.elts;
+
+    for (i = 0; i < umcf->upstreams.nelts; i++) {
+        if (uscfp[i]->peers) {
+            continue;
+        }
+
+        uscfp[i]->peers = ngx_inet_resolve_peer(cf, &uscfp[i]->host,
+                          uscfp[i]->port);
+
+        if (uscfp[i]->peers == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        if (uscfp[i]->peers == NGX_CONF_ERROR) {
+            ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+                          "upstream host \"%V\" is not found in %s:%ui",
+                          &uscfp[i]->host, uscfp[i]->file_name.data,
+                          uscfp[i]->line);
+            return NGX_CONF_ERROR;
+        }
+    }
 
     if (ngx_array_init(&headers_in, cf->temp_pool, 32, sizeof(ngx_hash_key_t))
         != NGX_OK)
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -42,10 +42,26 @@ typedef struct {
 
 typedef struct {
     ngx_hash_t                      headers_in_hash;
+    ngx_array_t                     upstreams;
+                                           /* ngx_http_upstream_srv_conf_t */
 } ngx_http_upstream_main_conf_t;
 
 
 typedef struct {
+    ngx_peers_t                    *peers;
+
+    ngx_array_t                    *servers;
+
+    ngx_str_t                       host;
+    ngx_str_t                       file_name;
+    ngx_uint_t                      line;
+    in_port_t                       port;
+
+    ngx_uint_t                      balanced;    /* unsigned  balanced:1; */
+} ngx_http_upstream_srv_conf_t;
+
+
+typedef struct {
     ngx_msec_t                      connect_timeout;
     ngx_msec_t                      send_timeout;
     ngx_msec_t                      read_timeout;
@@ -199,6 +215,8 @@ struct ngx_http_upstream_s {
 
 
 void ngx_http_upstream_init(ngx_http_request_t *r);
+ngx_http_upstream_srv_conf_t *ngx_http_upstream_add(ngx_conf_t *cf,
+    ngx_url_t *u);
 
 
 extern ngx_module_t  ngx_http_upstream_module;