diff src/http/ngx_http_upstream.c @ 260:0effe91f6083 NGINX_0_5_0

nginx 0.5.0 *) Change: the parameters in the "%name" form in the "log_format" directive are not supported anymore. *) Change: the "proxy_upstream_max_fails", "proxy_upstream_fail_timeout", "fastcgi_upstream_max_fails", "fastcgi_upstream_fail_timeout", "memcached_upstream_max_fails", and "memcached_upstream_fail_timeout" directives are not supported anymore. *) Feature: the "server" directive in the "upstream" context supports the "max_fails", "fail_timeout", and "down" parameters. *) Feature: the "ip_hash" directive inside the "upstream" block. *) Feature: the WAIT status in the "Auth-Status" header line of the IMAP/POP3 proxy authentication server response. *) Bugfix: nginx could not be built on 64-bit platforms; bug appeared in 0.4.14.
author Igor Sysoev <http://sysoev.ru>
date Mon, 04 Dec 2006 00:00:00 +0300
parents 6ae1357b7b7c
children e0b1d0a6c629
line wrap: on
line diff
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -70,15 +70,6 @@ static ngx_int_t ngx_http_upstream_copy_
     ngx_table_elt_t *h, ngx_uint_t offset);
 #endif
 
-static size_t ngx_http_upstream_log_status_getlen(ngx_http_request_t *r,
-    uintptr_t data);
-static u_char *ngx_http_upstream_log_status(ngx_http_request_t *r,
-    u_char *buf, ngx_http_log_op_t *op);
-static size_t ngx_http_upstream_log_response_time_getlen(ngx_http_request_t *r,
-    uintptr_t data);
-static u_char *ngx_http_upstream_log_response_time(ngx_http_request_t *r,
-    u_char *buf, ngx_http_log_op_t *op);
-
 static ngx_int_t ngx_http_upstream_add_variables(ngx_conf_t *cf);
 static ngx_int_t ngx_http_upstream_status_variable(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
@@ -96,8 +87,6 @@ static char *ngx_http_upstream_init_main
 static void ngx_http_upstream_ssl_init_connection(ngx_http_request_t *,
     ngx_http_upstream_t *u, ngx_connection_t *c);
 static void ngx_http_upstream_ssl_handshake(ngx_connection_t *c);
-static void ngx_http_upstream_ssl_shutdown(ngx_connection_t *c,
-    ngx_peer_t *peer);
 #endif
 
 
@@ -224,7 +213,7 @@ static ngx_command_t  ngx_http_upstream_
       NULL },
 
     { ngx_string("server"),
-      NGX_HTTP_UPS_CONF|NGX_CONF_TAKE12,
+      NGX_HTTP_UPS_CONF|NGX_CONF_1MORE,
       ngx_http_upstream_server,
       NGX_HTTP_SRV_CONF_OFFSET,
       0,
@@ -265,17 +254,6 @@ ngx_module_t  ngx_http_upstream_module =
 };
 
 
-static ngx_http_log_op_name_t  ngx_http_upstream_log_fmt_ops[] = {
-    { ngx_string("upstream_status"), 0, NULL,
-                                    ngx_http_upstream_log_status_getlen,
-                                    ngx_http_upstream_log_status },
-    { ngx_string("upstream_response_time"), 0, NULL,
-                                    ngx_http_upstream_log_response_time_getlen,
-                                    ngx_http_upstream_log_response_time },
-    { ngx_null_string, 0, NULL, NULL, NULL }
-};
-
-
 static ngx_http_variable_t  ngx_http_upstream_vars[] = {
 
     { ngx_string("upstream_status"), NULL,
@@ -328,13 +306,16 @@ ngx_http_upstream_init(ngx_http_request_
         u->request_bufs = r->request_body->bufs;
     }
 
+    if (u->conf->upstream->peer.init(r, u->conf->upstream) != NGX_OK) {
+        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+        return;
+    }
+
     if (u->create_request(r) != NGX_OK) {
         ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
         return;
     }
 
-    u->peer.log = r->connection->log;
-
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
     u->output.sendfile = r->connection->sendfile;
@@ -346,7 +327,7 @@ ngx_http_upstream_init(ngx_http_request_
 
     u->writer.pool = r->pool;
 
-    if (ngx_array_init(&u->states, r->pool, u->peer.peers->number,
+    if (ngx_array_init(&u->states, r->pool, 1,
                        sizeof(ngx_http_upstream_state_t))
         != NGX_OK)
     {
@@ -548,7 +529,7 @@ ngx_http_upstream_connect(ngx_http_reque
         return;
     }
 
-    u->state->peer = &u->peer.peers->peer[u->peer.cur_peer].name;
+    u->state->peer = u->peer.name;
 
     if (rc == NGX_BUSY) {
         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no live upstreams");
@@ -637,8 +618,7 @@ static void
 ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r,
     ngx_http_upstream_t *u, ngx_connection_t *c)
 {
-    ngx_int_t    rc;
-    ngx_peer_t  *peer;
+    ngx_int_t   rc;
 
     if (ngx_ssl_create_connection(u->conf->ssl, c,
                                   NGX_SSL_BUFFER|NGX_SSL_CLIENT)
@@ -652,9 +632,7 @@ ngx_http_upstream_ssl_init_connection(ng
     c->sendfile = 0;
     u->output.sendfile = 0;
 
-    peer = &u->peer.peers->peer[u->peer.cur_peer];
-
-    if (ngx_ssl_set_session(c, peer->ssl_session) != NGX_OK) {
+    if (ngx_ssl_set_session(c, u->peer.ssl_session) != NGX_OK) {
         ngx_http_upstream_finalize_request(r, u,
                                            NGX_HTTP_INTERNAL_SERVER_ERROR);
         return;
@@ -684,6 +662,8 @@ ngx_http_upstream_ssl_handshake(ngx_conn
 
     if (c->ssl->handshaked) {
 
+        u->peer.save_session(&u->peer, u->peer.data);
+
         c->write->handler = ngx_http_upstream_send_request_handler;
         c->read->handler = ngx_http_upstream_process_header;
 
@@ -992,7 +972,7 @@ ngx_http_upstream_process_header(ngx_eve
     }
 
     n = u->peer.connection->recv(u->peer.connection, u->buffer.last,
-                                 u->buffer.end - u->buffer.last);
+                                      u->buffer.end - u->buffer.last);
 
     if (n == NGX_AGAIN) {
 #if 0
@@ -1605,7 +1585,7 @@ ngx_http_upstream_process_non_buffered_b
     ngx_buf_t                 *b;
     ngx_int_t                  rc;
     ngx_uint_t                 do_write;
-    ngx_connection_t          *c, *client;
+    ngx_connection_t          *c, *downstream, *upstream;
     ngx_http_request_t        *r;
     ngx_http_upstream_t       *u;
     ngx_http_core_loc_conf_t  *clcf;
@@ -1638,7 +1618,8 @@ ngx_http_upstream_process_non_buffered_b
         return;
     }
 
-    client = r->connection;
+    downstream = r->connection;
+    upstream = u->peer.connection;
 
     b = &u->buffer;
 
@@ -1653,7 +1634,7 @@ ngx_http_upstream_process_non_buffered_b
             if (u->out_bufs || u->busy_bufs) {
                 rc = ngx_http_output_filter(r, u->out_bufs);
 
-                if (client->destroyed) {
+                if (downstream->destroyed) {
                     return;
                 }
 
@@ -1669,8 +1650,8 @@ ngx_http_upstream_process_non_buffered_b
             if (u->busy_bufs == NULL) {
 
                 if (u->length == 0
-                    || u->peer.connection->read->eof
-                    || u->peer.connection->read->error)
+                    || upstream->read->eof
+                    || upstream->read->error)
                 {
                     ngx_http_upstream_finalize_request(r, u, 0);
                     return;
@@ -1687,9 +1668,9 @@ ngx_http_upstream_process_non_buffered_b
             size = u->length;
         }
 
-        if (size && u->peer.connection->read->ready) {
-
-            n = u->peer.connection->recv(u->peer.connection, b->last, size);
+        if (size && upstream->read->ready) {
+
+            n = upstream->recv(upstream, b->last, size);
 
             if (n == NGX_AGAIN) {
                 break;
@@ -1710,8 +1691,8 @@ ngx_http_upstream_process_non_buffered_b
         break;
     }
 
-    if (client->data == r) {
-        if (ngx_handle_write_event(client->write, clcf->send_lowat)
+    if (downstream->data == r) {
+        if (ngx_handle_write_event(downstream->write, clcf->send_lowat)
             == NGX_ERROR)
         {
             ngx_http_upstream_finalize_request(r, u, 0);
@@ -1719,23 +1700,23 @@ ngx_http_upstream_process_non_buffered_b
         }
     }
 
-    if (client->write->active) {
-        ngx_add_timer(client->write, clcf->send_timeout);
-
-    } else if (client->write->timer_set) {
-        ngx_del_timer(client->write);
+    if (downstream->write->active) {
+        ngx_add_timer(downstream->write, clcf->send_timeout);
+
+    } else if (downstream->write->timer_set) {
+        ngx_del_timer(downstream->write);
     }
 
-    if (ngx_handle_read_event(u->peer.connection->read, 0) == NGX_ERROR) {
+    if (ngx_handle_read_event(upstream->read, 0) == NGX_ERROR) {
         ngx_http_upstream_finalize_request(r, u, 0);
         return;
     }
 
-    if (u->peer.connection->read->active) {
-        ngx_add_timer(u->peer.connection->read, u->conf->read_timeout);
-
-    } else if (u->peer.connection->read->timer_set) {
-        ngx_del_timer(u->peer.connection->read);
+    if (upstream->read->active) {
+        ngx_add_timer(upstream->read, u->conf->read_timeout);
+
+    } else if (upstream->read->timer_set) {
+        ngx_del_timer(upstream->read);
     }
 }
 
@@ -1942,22 +1923,22 @@ static void
 ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u,
     ngx_uint_t ft_type)
 {
-    ngx_uint_t  status, down;
+    ngx_uint_t  status, state;
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "http next upstream, %xD", ft_type);
+                   "http next upstream, %xi", ft_type);
 
 #if 0
     ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock);
 #endif
 
     if (ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_404) {
-        down = 0;
+        state = NGX_PEER_NEXT;
     } else {
-        down = 1;
+        state = NGX_PEER_FAILED;
     }
 
-    ngx_event_connect_peer_failed(&u->peer, down);
+    u->peer.free(&u->peer, u->peer.data, state);
 
     if (ft_type == NGX_HTTP_UPSTREAM_FT_TIMEOUT) {
         ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ETIMEDOUT,
@@ -2023,11 +2004,15 @@ ngx_http_upstream_next(ngx_http_request_
                        "close http upstream connection: %d",
                        u->peer.connection->fd);
 #if (NGX_HTTP_SSL)
+
         if (u->peer.connection->ssl) {
-            ngx_http_upstream_ssl_shutdown(u->peer.connection,
-                                       &u->peer.peers->peer[u->peer.cur_peer]);
+            u->peer.connection->ssl->no_wait_shutdown = 1;
+            u->peer.connection->ssl->no_send_shutdown = 1;
+
+            (void) ngx_ssl_shutdown(u->peer.connection);
         }
 #endif
+
         ngx_close_connection(u->peer.connection);
     }
 
@@ -2074,19 +2059,32 @@ ngx_http_upstream_finalize_request(ngx_h
 
     u->finalize_request(r, rc);
 
+    u->peer.free(&u->peer, u->peer.data, 0);
+
     if (u->peer.connection) {
-        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "close http upstream connection: %d",
-                       u->peer.connection->fd);
+
 #if (NGX_HTTP_SSL)
 
         /* TODO: do not shutdown persistent connection */
 
         if (u->peer.connection->ssl) {
-            ngx_http_upstream_ssl_shutdown(u->peer.connection,
-                                       &u->peer.peers->peer[u->peer.cur_peer]);
+
+            /*
+             * We send the "close notify" shutdown alert to the upstream only
+             * and do not wait its "close notify" shutdown alert.
+             * It is acceptable according to the TLS standard.
+             */
+
+            u->peer.connection->ssl->no_wait_shutdown = 1;
+
+            (void) ngx_ssl_shutdown(u->peer.connection);
         }
 #endif
+
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "close http upstream connection: %d",
+                       u->peer.connection->fd);
+
         ngx_close_connection(u->peer.connection);
     }
 
@@ -2125,35 +2123,6 @@ ngx_http_upstream_finalize_request(ngx_h
 }
 
 
-#if (NGX_HTTP_SSL)
-
-static void
-ngx_http_upstream_ssl_shutdown(ngx_connection_t *c, ngx_peer_t *peer)
-{
-    /* lock peer mutex */
-
-    if (peer->ssl_session) {
-        ngx_ssl_free_session(peer->ssl_session);
-    }
-
-    peer->ssl_session = ngx_ssl_get_session(c);
-
-    /* unlock peer mutex */
-
-    /*
-     * We send the "close notify" shutdown alert to the upstream only
-     * and do not wait its "close notify" shutdown alert.
-     * It is acceptable according to the TLS standard.
-     */
-
-    c->ssl->no_wait_shutdown = 1;
-
-    (void) ngx_ssl_shutdown(c);
-}
-
-#endif
-
-
 static ngx_int_t
 ngx_http_upstream_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h,
     ngx_uint_t offset)
@@ -2481,108 +2450,10 @@ ngx_http_upstream_copy_content_encoding(
 #endif
 
 
-static size_t
-ngx_http_upstream_log_status_getlen(ngx_http_request_t *r, uintptr_t data)
-{
-    if (r->upstream) {
-        return r->upstream->states.nelts * (3 + 2);
-    }
-
-    return 1;
-}
-
-
-static u_char *
-ngx_http_upstream_log_status(ngx_http_request_t *r, u_char *buf,
-    ngx_http_log_op_t *op)
-{
-    ngx_uint_t                  i;
-    ngx_http_upstream_t        *u;
-    ngx_http_upstream_state_t  *state;
-
-    u = r->upstream;
-
-    if (u == NULL || u->states.nelts == 0) {
-        *buf = '-';
-        return buf + 1;
-    }
-
-    i = 0;
-    state = u->states.elts;
-
-    for ( ;; ) {
-        if (state[i].status == 0) {
-            *buf++ = '-';
-
-        } else {
-            buf = ngx_sprintf(buf, "%ui", state[i].status);
-        }
-
-        if (++i == u->states.nelts) {
-            return buf;
-        }
-
-        *buf++ = ',';
-        *buf++ = ' ';
-    }
-}
-
-
-static size_t
-ngx_http_upstream_log_response_time_getlen(ngx_http_request_t *r,
-    uintptr_t data)
-{
-    if (r->upstream) {
-        return r->upstream->states.nelts * (NGX_TIME_T_LEN + 4 + 2);
-    }
-
-    return 1;
-}
-
-
-static u_char *
-ngx_http_upstream_log_response_time(ngx_http_request_t *r, u_char *buf,
-    ngx_http_log_op_t *op)
-{
-    ngx_uint_t                  i;
-    ngx_http_upstream_t        *u;
-    ngx_http_upstream_state_t  *state;
-
-    u = r->upstream;
-
-    if (u == NULL || u->states.nelts == 0) {
-        *buf = '-';
-        return buf + 1;
-    }
-
-    i = 0;
-    state = u->states.elts;
-
-    for ( ;; ) {
-        if (state[i].status == 0) {
-            *buf++ = '-';
-
-        } else {
-            buf = ngx_sprintf(buf, "%d.%03d",
-                               state[i].response_time / 1000,
-                               state[i].response_time % 1000);
-        }
-
-        if (++i == u->states.nelts) {
-            return buf;
-        }
-
-        *buf++ = ',';
-        *buf++ = ' ';
-    }
-}
-
-
 static ngx_int_t
 ngx_http_upstream_add_variables(ngx_conf_t *cf)
 {
-    ngx_http_variable_t     *var, *v;
-    ngx_http_log_op_name_t  *op;
+    ngx_http_variable_t  *var, *v;
 
     for (v = ngx_http_upstream_vars; v->name.len; v++) {
         var = ngx_http_add_variable(cf, &v->name, v->flags);
@@ -2594,17 +2465,6 @@ ngx_http_upstream_add_variables(ngx_conf
         var->data = v->data;
     }
 
-    for (op = ngx_http_upstream_log_fmt_ops; op->name.len; op++) { /* void */ }
-    op->run = NULL;
-
-    for (op = ngx_http_log_fmt_ops; op->run; op++) {
-        if (op->name.len == 0) {
-            op = (ngx_http_log_op_name_t *) op->run;
-        }
-    }
-
-    op->run = (ngx_http_log_op_run_pt) ngx_http_upstream_log_fmt_ops;
-
     return NGX_OK;
 }
 
@@ -2724,31 +2584,41 @@ 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;
+    char                          *rv;
+    void                          *mconf;
+    ngx_str_t                     *value;
+    ngx_url_t                      u;
+    ngx_uint_t                     m;
+    ngx_conf_t                     pcf;
+    ngx_http_module_t             *module;
+    ngx_http_conf_ctx_t           *ctx, *http_ctx;
+    ngx_http_upstream_srv_conf_t  *uscf;
+
+    ngx_memzero(&u, sizeof(ngx_url_t));
+
+    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
+                                         |NGX_HTTP_UPSTREAM_WEIGHT
+                                         |NGX_HTTP_UPSTREAM_MAX_FAILS
+                                         |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT
+                                         |NGX_HTTP_UPSTREAM_DOWN
+                                         |NGX_HTTP_UPSTREAM_BACKUP);
+    if (uscf == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
 
     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;
-    }
+    http_ctx = cf->ctx;
+    ctx->main_conf = http_ctx->main_conf;
 
     /* the upstream{}'s srv_conf */
 
@@ -2759,6 +2629,8 @@ ngx_http_upstream(ngx_conf_t *cf, ngx_co
 
     ctx->srv_conf[ngx_http_upstream_module.ctx_index] = uscf;
 
+    uscf->srv_conf = ctx->srv_conf;
+
 
     /* the upstream{}'s loc_conf */
 
@@ -2774,6 +2646,15 @@ ngx_http_upstream(ngx_conf_t *cf, ngx_co
 
         module = ngx_modules[m]->ctx;
 
+        if (module->create_srv_conf) {
+            mconf = module->create_srv_conf(cf);
+            if (mconf == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            ctx->srv_conf[ngx_modules[m]->ctx_index] = mconf;
+        }
+
         if (module->create_loc_conf) {
             mconf = module->create_loc_conf(cf);
             if (mconf == NULL) {
@@ -2805,34 +2686,6 @@ ngx_http_upstream(ngx_conf_t *cf, ngx_co
         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;
-
-    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;
 }
 
@@ -2842,24 +2695,28 @@ ngx_http_upstream_server(ngx_conf_t *cf,
 {
     ngx_http_upstream_srv_conf_t  *uscf = conf;
 
-    ngx_str_t                    *value;
-    ngx_url_t                     u;
-    ngx_int_t                     weight;
-    ngx_uint_t                    i;
-    ngx_peers_t                 **peers;
+    time_t                       fail_timeout;
+    ngx_str_t                   *value, s;
+    ngx_url_t                    u;
+    ngx_int_t                    weight, max_fails;
+    ngx_uint_t                   i;
+    ngx_http_upstream_server_t  *us;
 
     if (uscf->servers == NULL) {
-        uscf->servers = ngx_array_create(cf->pool, 4, sizeof(ngx_peers_t *));
+        uscf->servers = ngx_array_create(cf->pool, 4,
+                                         sizeof(ngx_http_upstream_server_t));
         if (uscf->servers == NULL) {
             return NGX_CONF_ERROR;
         }
     }
 
-    peers = ngx_array_push(uscf->servers);
-    if (peers == NULL) {
+    us = ngx_array_push(uscf->servers);
+    if (us == NULL) {
         return NGX_CONF_ERROR;
     }
 
+    ngx_memzero(us, sizeof(ngx_http_upstream_server_t));
+
     value = cf->args->elts;
 
     ngx_memzero(&u, sizeof(ngx_url_t));
@@ -2877,51 +2734,100 @@ ngx_http_upstream_server(ngx_conf_t *cf,
     }
 
     weight = 1;
-
-    if (cf->args->nelts == 3) {
-
-        value = &value[2];
-
-        if (ngx_strncmp(value->data, "weight=", 7) == 0) {
-
-            weight = ngx_atoi(&value->data[7], value->len - 7);
+    max_fails = 1;
+    fail_timeout = 10;
+
+    for (i = 2; i < cf->args->nelts; i++) {
+
+        if (ngx_strncmp(value[i].data, "weight=", 7) == 0) {
+
+            if (!(uscf->flags & NGX_HTTP_UPSTREAM_WEIGHT)) {
+                goto invalid;
+            }
+
+            weight = ngx_atoi(&value[i].data[7], value[i].len - 7);
 
             if (weight == NGX_ERROR || weight == 0) {
                 goto invalid;
             }
 
-        } else {
-            goto invalid;
+            continue;
+        }
+
+        if (ngx_strncmp(value[i].data, "max_fails=", 10) == 0) {
+
+            if (!(uscf->flags & NGX_HTTP_UPSTREAM_MAX_FAILS)) {
+                goto invalid;
+            }
+
+            max_fails = ngx_atoi(&value[i].data[10], value[i].len - 10);
+
+            if (max_fails == NGX_ERROR) {
+                goto invalid;
+            }
+
+            continue;
         }
+
+        if (ngx_strncmp(value[i].data, "fail_timeout=", 13) == 0) {
+
+            if (!(uscf->flags & NGX_HTTP_UPSTREAM_FAIL_TIMEOUT)) {
+                goto invalid;
+            }
+
+            s.len = value[i].len - 13;
+            s.data = &value[i].data[13];
+
+            fail_timeout = ngx_parse_time(&s, 1);
+
+            if (fail_timeout < 0) {
+                goto invalid;
+            }
+
+            continue;
+        }
+
+        if (ngx_strncmp(value[i].data, "down", 4) == 0) {
+
+            if (!(uscf->flags & NGX_HTTP_UPSTREAM_DOWN)) {
+                goto invalid;
+            }
+
+            us->down = 1;
+
+            continue;
+        }
+
+        goto invalid;
     }
 
-    for (i = 0; i < u.peers->number; i++) {
-        u.peers->peer[i].weight = weight;
-        u.peers->peer[i].current_weight = weight;
-        u.peers->peer[i].max_fails = NGX_CONF_UNSET_UINT;
-        u.peers->peer[i].fail_timeout = NGX_CONF_UNSET;
-    }
-
-    *peers = u.peers;
+    us->addrs = u.addrs;
+    us->naddrs = u.naddrs;
+    us->weight = weight;
+    us->max_fails = max_fails;
+    us->fail_timeout = fail_timeout;
 
     return NGX_CONF_OK;
 
 invalid:
 
-    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", value);
+    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                       "invalid parameter \"%V\"", &value[i]);
 
     return NGX_CONF_ERROR;
 }
 
 
 ngx_http_upstream_srv_conf_t *
-ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u)
+ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags)
 {
     ngx_uint_t                      i;
+    ngx_http_upstream_server_t     *us;
     ngx_http_upstream_srv_conf_t   *uscf, **uscfp;
     ngx_http_upstream_main_conf_t  *umcf;
 
-    if (u->upstream) {
+    if (!(flags & NGX_HTTP_UPSTREAM_CREATE)) {
+
         if (ngx_parse_url(cf, u) != NGX_OK) {
             if (u->err) {
                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@@ -2930,17 +2836,6 @@ ngx_http_upstream_add(ngx_conf_t *cf, ng
 
             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);
@@ -2948,15 +2843,28 @@ ngx_http_upstream_add(ngx_conf_t *cf, ng
     uscfp = umcf->upstreams.elts;
 
     for (i = 0; i < umcf->upstreams.nelts; i++) {
-        if (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)
+        {
             continue;
         }
 
-        if (ngx_strncasecmp(uscfp[i]->host.data, u->host.data, u->host.len)
-            == 0)
+        if ((flags & NGX_HTTP_UPSTREAM_CREATE)
+             && (uscfp[i]->flags & NGX_HTTP_UPSTREAM_CREATE))
         {
-            return uscfp[i];
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "duplicate upstream \"%V\"", &u->host);
+            return NULL;
         }
+
+        if (uscfp[i]->port == 0 && u->portn && !u->no_port) {
+            ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+                               "upstream \"%V\" port %d is ignored",
+                               &u->host, u->portn);
+        }
+
+        return uscfp[i];
     }
 
     uscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_srv_conf_t));
@@ -2964,10 +2872,29 @@ ngx_http_upstream_add(ngx_conf_t *cf, ng
         return NULL;
     }
 
+    uscf->flags = flags;
     uscf->host = u->host;
     uscf->file_name = cf->conf_file->file.name;
     uscf->line = cf->conf_file->line;
-    uscf->port = u->default_portn;
+    uscf->port = u->portn;
+
+    if (u->naddrs == 1) {
+        uscf->servers = ngx_array_create(cf->pool, 1,
+                                         sizeof(ngx_http_upstream_server_t));
+        if (uscf->servers == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        us = ngx_array_push(uscf->servers);
+        if (us == NULL) {
+            return NGX_CONF_ERROR;
+        }
+
+        ngx_memzero(us, sizeof(ngx_http_upstream_server_t));
+
+        us->addrs = u->addrs;
+        us->naddrs = u->naddrs;
+    }
 
     uscfp = ngx_array_push(&umcf->upstreams);
     if (uscfp == NULL) {
@@ -3010,32 +2937,25 @@ ngx_http_upstream_init_main_conf(ngx_con
     ngx_array_t                     headers_in;
     ngx_hash_key_t                 *hk;
     ngx_hash_init_t                 hash;
+    ngx_http_upstream_init_pt       init;
     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);
+
+        init = uscfp[i]->peer.init_upstream ? uscfp[i]->peer.init_upstream:
+                                            ngx_http_upstream_init_round_robin;
+
+        if (init(cf, uscfp[i]) != NGX_OK) {
             return NGX_CONF_ERROR;
         }
     }
 
 
+    /* upstream_headers_in_hash */
+
     if (ngx_array_init(&headers_in, cf->temp_pool, 32, sizeof(ngx_hash_key_t))
         != NGX_OK)
     {