diff src/http/ngx_http_upstream.c @ 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 e6da4931e0e0
children ca5f86d94316
line wrap: on
line diff
--- 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)