view src/http/ngx_http.c @ 158:2d15b82126ed NGINX_0_3_26

nginx 0.3.26 *) Change: the "optimize_host_names" directive was renamed to the "optimize_server_names". *) Bugfix: if in the "proxy_pass" directive was no the URI part, then the main request URI was transferred to a backend while proxying the SSI subrequest.
author Igor Sysoev <http://sysoev.ru>
date Fri, 03 Feb 2006 00:00:00 +0300
parents 396dbbc06dd7
children 6be073125f2e
line wrap: on
line source


/*
 * Copyright (C) Igor Sysoev
 */


#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_event.h>
#include <ngx_http.h>


static char *ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static ngx_int_t ngx_http_add_address(ngx_conf_t *cf,
    ngx_http_conf_in_port_t *in_port, ngx_http_listen_t *lscf,
    ngx_http_core_srv_conf_t *cscf);
static ngx_int_t ngx_http_add_names(ngx_conf_t *cf,
    ngx_http_conf_in_addr_t *in_addr, ngx_http_core_srv_conf_t *cscf);
static char *ngx_http_merge_locations(ngx_conf_t *cf,
    ngx_array_t *locations, void **loc_conf, ngx_http_module_t *module,
    ngx_uint_t ctx_index);
static int ngx_libc_cdecl ngx_http_cmp_conf_in_addrs(const void *one,
    const void *two);
static int ngx_libc_cdecl ngx_http_cmp_dns_wildcards(const void *one,
    const void *two);

ngx_uint_t   ngx_http_max_module;

ngx_uint_t   ngx_http_total_requests;
uint64_t     ngx_http_total_sent;


ngx_int_t  (*ngx_http_top_header_filter) (ngx_http_request_t *r);
ngx_int_t  (*ngx_http_top_body_filter) (ngx_http_request_t *r, ngx_chain_t *ch);


static ngx_command_t  ngx_http_commands[] = {

    { ngx_string("http"),
      NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
      ngx_http_block,
      0,
      0,
      NULL },

      ngx_null_command
};


static ngx_core_module_t  ngx_http_module_ctx = {
    ngx_string("http"),
    NULL,
    NULL
};


ngx_module_t  ngx_http_module = {
    NGX_MODULE_V1,
    &ngx_http_module_ctx,                  /* module context */
    ngx_http_commands,                     /* module directives */
    NGX_CORE_MODULE,                       /* module type */
    NULL,                                  /* init master */
    NULL,                                  /* init module */
    NULL,                                  /* init process */
    NULL,                                  /* init thread */
    NULL,                                  /* exit thread */
    NULL,                                  /* exit process */
    NULL,                                  /* exit master */
    NGX_MODULE_V1_PADDING
};


static char *
ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
    char                        *rv;
    u_char                       ch;
    ngx_int_t                    rc;
    ngx_uint_t                   mi, m, s, l, p, a, i;
    ngx_uint_t                   last, bind_all, done;
    ngx_conf_t                   pcf;
    ngx_array_t                  in_ports;
    ngx_hash_init_t              hash;
    ngx_listening_t             *ls;
    ngx_http_listen_t           *lscf;
    ngx_http_module_t           *module;
    ngx_http_in_port_t          *hip;
    ngx_http_handler_pt         *h;
    ngx_http_conf_ctx_t         *ctx;
    ngx_http_conf_in_port_t     *in_port;
    ngx_http_conf_in_addr_t     *in_addr;
    ngx_hash_keys_arrays_t       ha;
    ngx_http_server_name_t      *name;
    ngx_http_virtual_names_t    *vn;
    ngx_http_core_srv_conf_t   **cscfp, *cscf;
    ngx_http_core_loc_conf_t    *clcf;
    ngx_http_core_main_conf_t   *cmcf;
#if (NGX_WIN32)
    ngx_iocp_conf_t             *iocpcf;
#endif

    /* the main http context */

    ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
    if (ctx == NULL) {
        return NGX_CONF_ERROR;
    }

    *(ngx_http_conf_ctx_t **) conf = ctx;


    /* count the number of the http modules and set up their indices */

    ngx_http_max_module = 0;
    for (m = 0; ngx_modules[m]; m++) {
        if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
            continue;
        }

        ngx_modules[m]->ctx_index = ngx_http_max_module++;
    }


    /* the http main_conf context, it is the same in the all http contexts */

    ctx->main_conf = ngx_pcalloc(cf->pool,
                                 sizeof(void *) * ngx_http_max_module);
    if (ctx->main_conf == NULL) {
        return NGX_CONF_ERROR;
    }


    /*
     * the http null srv_conf context, it is used to merge
     * the server{}s' srv_conf's
     */

    ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
    if (ctx->srv_conf == NULL) {
        return NGX_CONF_ERROR;
    }


    /*
     * the http null loc_conf context, it is used to merge
     * the server{}s' loc_conf's
     */

    ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
    if (ctx->loc_conf == NULL) {
        return NGX_CONF_ERROR;
    }


    /*
     * create the main_conf's, the null srv_conf's, and the null loc_conf's
     * of the all http modules
     */

    for (m = 0; ngx_modules[m]; m++) {
        if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
            continue;
        }

        module = ngx_modules[m]->ctx;
        mi = ngx_modules[m]->ctx_index;

        if (module->create_main_conf) {
            ctx->main_conf[mi] = module->create_main_conf(cf);
            if (ctx->main_conf[mi] == NULL) {
                return NGX_CONF_ERROR;
            }
        }

        if (module->create_srv_conf) {
            ctx->srv_conf[mi] = module->create_srv_conf(cf);
            if (ctx->srv_conf[mi] == NULL) {
                return NGX_CONF_ERROR;
            }
        }

        if (module->create_loc_conf) {
            ctx->loc_conf[mi] = module->create_loc_conf(cf);
            if (ctx->loc_conf[mi] == NULL) {
                return NGX_CONF_ERROR;
            }
        }
    }

    pcf = *cf;
    cf->ctx = ctx;

    for (m = 0; ngx_modules[m]; m++) {
        if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
            continue;
        }

        module = ngx_modules[m]->ctx;
        mi = ngx_modules[m]->ctx_index;

        if (module->preconfiguration) {
            if (module->preconfiguration(cf) != NGX_OK) {
                return NGX_CONF_ERROR;
            }
        }
    }

    /* parse inside the http{} block */

    cf->module_type = NGX_HTTP_MODULE;
    cf->cmd_type = NGX_HTTP_MAIN_CONF;
    rv = ngx_conf_parse(cf, NULL);

    if (rv != NGX_CONF_OK) {
        *cf = pcf;
        return rv;
    }

    /*
     * init http{} main_conf's, merge the server{}s' srv_conf's
     * and its location{}s' loc_conf's
     */

    cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
    cscfp = cmcf->servers.elts;

    for (m = 0; ngx_modules[m]; m++) {
        if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
            continue;
        }

        module = ngx_modules[m]->ctx;
        mi = ngx_modules[m]->ctx_index;

        /* init http{} main_conf's */

        if (module->init_main_conf) {
            rv = module->init_main_conf(cf, ctx->main_conf[mi]);
            if (rv != NGX_CONF_OK) {
                *cf = pcf;
                return rv;
            }
        }

        for (s = 0; s < cmcf->servers.nelts; s++) {

            /* merge the server{}s' srv_conf's */

            if (module->merge_srv_conf) {
                rv = module->merge_srv_conf(cf,
                                            ctx->srv_conf[mi],
                                            cscfp[s]->ctx->srv_conf[mi]);
                if (rv != NGX_CONF_OK) {
                    *cf = pcf;
                    return rv;
                }
            }

            if (module->merge_loc_conf) {

                /* merge the server{}'s loc_conf */

                rv = module->merge_loc_conf(cf,
                                            ctx->loc_conf[mi],
                                            cscfp[s]->ctx->loc_conf[mi]);
                if (rv != NGX_CONF_OK) {
                    *cf = pcf;
                    return rv;
                }

                /* merge the locations{}' loc_conf's */

                rv = ngx_http_merge_locations(cf, &cscfp[s]->locations,
                                              cscfp[s]->ctx->loc_conf,
                                              module, mi);
                if (rv != NGX_CONF_OK) {
                    *cf = pcf;
                    return rv;
                }
            }
        }
    }


    /* init lists of the handlers */

    if (ngx_array_init(&cmcf->phases[NGX_HTTP_POST_READ_PHASE].handlers,
                       cf->pool, 1, sizeof(ngx_http_handler_pt))
        != NGX_OK)
    {
        return NGX_CONF_ERROR;
    }

    cmcf->phases[NGX_HTTP_POST_READ_PHASE].type = NGX_OK;


    if (ngx_array_init(&cmcf->phases[NGX_HTTP_SERVER_REWRITE_PHASE].handlers,
                       cf->pool, 1, sizeof(ngx_http_handler_pt))
        != NGX_OK)
    {
        return NGX_CONF_ERROR;
    }

    cmcf->phases[NGX_HTTP_SERVER_REWRITE_PHASE].type = NGX_OK;


    /* the special find config phase for a single handler */

    if (ngx_array_init(&cmcf->phases[NGX_HTTP_FIND_CONFIG_PHASE].handlers,
                       cf->pool, 1, sizeof(ngx_http_handler_pt))
        != NGX_OK)
    {
        return NGX_CONF_ERROR;
    }

    cmcf->phases[NGX_HTTP_FIND_CONFIG_PHASE].type = NGX_OK;

    h = ngx_array_push(&cmcf->phases[NGX_HTTP_FIND_CONFIG_PHASE].handlers);
    if (h == NULL) {
        return NGX_CONF_ERROR;
    }

    *h = ngx_http_find_location_config;


    if (ngx_array_init(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers,
                       cf->pool, 1, sizeof(ngx_http_handler_pt))
        != NGX_OK)
    {
        return NGX_CONF_ERROR;
    }

    cmcf->phases[NGX_HTTP_REWRITE_PHASE].type = NGX_OK;


    if (ngx_array_init(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers,
                       cf->pool, 1, sizeof(ngx_http_handler_pt))
        != NGX_OK)
    {
        return NGX_CONF_ERROR;
    }

    cmcf->phases[NGX_HTTP_PREACCESS_PHASE].type = NGX_OK;


    if (ngx_array_init(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers,
                       cf->pool, 2, sizeof(ngx_http_handler_pt))
        != NGX_OK)
    {
        return NGX_CONF_ERROR;
    }

    cmcf->phases[NGX_HTTP_ACCESS_PHASE].type = NGX_DECLINED;


    if (ngx_array_init(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers,
                       cf->pool, 4, sizeof(ngx_http_handler_pt))
        != NGX_OK)
    {
        return NGX_CONF_ERROR;
    }

    cmcf->phases[NGX_HTTP_CONTENT_PHASE].type = NGX_OK;


    if (ngx_array_init(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers,
                       cf->pool, 1, sizeof(ngx_http_handler_pt))
        != NGX_OK)
    {
        return NGX_CONF_ERROR;
    }

    cmcf->phases[NGX_HTTP_LOG_PHASE].type = NGX_OK;


    cmcf->headers_in_hash.max_size = 100;
    cmcf->headers_in_hash.bucket_limit = 1;
    cmcf->headers_in_hash.bucket_size = sizeof(ngx_http_header_t);
    cmcf->headers_in_hash.name = "http headers_in";

    if (ngx_hash0_init(&cmcf->headers_in_hash, cf->pool, ngx_http_headers_in, 0)
        != NGX_OK)
    {
        return NGX_CONF_ERROR;
    }

    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0,
                   "http headers_in hash size: %ui, max buckets per entry: %ui",
                   cmcf->headers_in_hash.hash_size,
                   cmcf->headers_in_hash.min_buckets);

    for (m = 0; ngx_modules[m]; m++) {
        if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
            continue;
        }

        module = ngx_modules[m]->ctx;
        mi = ngx_modules[m]->ctx_index;

        if (module->postconfiguration) {
            if (module->postconfiguration(cf) != NGX_OK) {
                return NGX_CONF_ERROR;
            }
        }
    }

    if (ngx_http_variables_init_vars(cf) != NGX_OK) {
        return NGX_CONF_ERROR;
    }

    /*
     * http{}'s cf->ctx was needed while the configuration merging
     * and in postconfiguration process
     */

    *cf = pcf;


    /*
     * create the lists of ports, addresses and server names
     * to quickly find the server core module configuration at run-time
     */

    if (ngx_array_init(&in_ports, cf->temp_pool, 2,
                       sizeof(ngx_http_conf_in_port_t))
        != NGX_OK)
    {
        return NGX_CONF_ERROR;
    }

    /* "server" directives */

    cscfp = cmcf->servers.elts;
    for (s = 0; s < cmcf->servers.nelts; s++) {

        /* "listen" directives */

        lscf = cscfp[s]->listen.elts;
        for (l = 0; l < cscfp[s]->listen.nelts; l++) {

            /* AF_INET only */

            in_port = in_ports.elts;
            for (p = 0; p < in_ports.nelts; p++) {

                if (lscf[l].port != in_port[p].port) {
                    continue;
                }

                /* the port is already in the port list */

                in_addr = in_port[p].addrs.elts;
                for (a = 0; a < in_port[p].addrs.nelts; a++) {

                    if (lscf[l].addr != in_addr[a].addr) {
                        continue;
                    }

                    /* the address is already in the address list */

                    if (ngx_http_add_names(cf, &in_addr[a], cscfp[s]) != NGX_OK)
                    {
                        return NGX_CONF_ERROR;
                    }

                    /*
                     * check the duplicate "default" server
                     * for this address:port
                     */

                    if (lscf[l].conf.default_server) {

                        if (in_addr[a].default_server) {
                            ngx_log_error(NGX_LOG_ERR, cf->log, 0,
                                        "the duplicate default server in %V:%d",
                                        &lscf[l].file_name, lscf[l].line);

                            return NGX_CONF_ERROR;
                        }

                        in_addr[a].core_srv_conf = cscfp[s];
                        in_addr[a].default_server = 1;
                    }

                    goto found;
                }

                /*
                 * add the address to the addresses list that
                 * bound to this port
                 */

                if (ngx_http_add_address(cf, &in_port[p], &lscf[l], cscfp[s])
                    != NGX_OK)
                {
                    return NGX_CONF_ERROR;
                }

                goto found;
            }

            /* add the port to the in_port list */

            in_port = ngx_array_push(&in_ports);
            if (in_port == NULL) {
                return NGX_CONF_ERROR;
            }

            in_port->port = lscf[l].port;
            in_port->addrs.elts = NULL;

            if (ngx_http_add_address(cf, in_port, &lscf[l], cscfp[s]) != NGX_OK)
            {
                return NGX_CONF_ERROR;
            }

        found:

            continue;
        }
    }


    /* optimize the lists of ports, addresses and server names */

    /* AF_INET only */

    in_port = in_ports.elts;
    for (p = 0; p < in_ports.nelts; p++) {

        ngx_qsort(in_port[p].addrs.elts, (size_t) in_port[p].addrs.nelts,
                  sizeof(ngx_http_conf_in_addr_t), ngx_http_cmp_conf_in_addrs);

        /*
         * check whether all name-based servers have the same configuraiton
         *     as the default server,
         * or some servers restrict the host names,
         * or some servers disable optimizing the server names
         */

        in_addr = in_port[p].addrs.elts;
        for (a = 0; a < in_port[p].addrs.nelts; a++) {

            name = in_addr[a].names.elts;
            for (s = 0; s < in_addr[a].names.nelts; s++) {

                if (in_addr[a].core_srv_conf != name[s].core_srv_conf
                    || name[s].core_srv_conf->optimize_server_names == 0
                    || name[s].core_srv_conf->restrict_host_names
                       != NGX_HTTP_RESTRICT_HOST_OFF)
                {
                    goto virtual_names;
                }
            }

            /*
             * if all name-based servers have the same configuration
             *         as the default server,
             *     and no servers restrict the host names,
             *     and no servers disable optimizing the server names
             * then we do not need to check them at run-time at all
             */

            in_addr[a].names.nelts = 0;

            continue;

        virtual_names:

            ha.temp_pool = ngx_create_pool(16384, cf->log);
            if (ha.temp_pool == NULL) {
                return NGX_CONF_ERROR;
            }

            ha.pool = cf->pool;

            if (ngx_hash_keys_array_init(&ha, NGX_HASH_LARGE) != NGX_OK) {
                ngx_destroy_pool(ha.temp_pool);
                return NGX_CONF_ERROR;
            }

            name = in_addr[a].names.elts;
            for (s = 0; s < in_addr[a].names.nelts; s++) {

                ch = name[s].name.data[0];

                if (ch == '*' || ch == '.') {
                    continue;
                }

                rc = ngx_hash_add_key(&ha, &name[s].name, name[s].core_srv_conf,
                                      0);

                if (rc == NGX_ERROR) {
                    return NGX_CONF_ERROR;
                }

                if (rc == NGX_BUSY) {
                    ngx_log_error(NGX_LOG_WARN, cf->log, 0,
                                  "conflicting server name \"%V\", ignored",
                                  &name[s].name);
                }
            }

            for (s = 0; s < in_addr[a].names.nelts; s++) {

                ch = name[s].name.data[0];

                if (ch != '*' && ch != '.') {
                    continue;
                }

                rc = ngx_hash_add_key(&ha, &name[s].name, name[s].core_srv_conf,
                                      NGX_HASH_WILDCARD_KEY);

                if (rc == NGX_ERROR) {
                    return NGX_CONF_ERROR;
                }

                if (rc == NGX_BUSY) {
                    ngx_log_error(NGX_LOG_WARN, cf->log, 0,
                                  "conflicting server name \"%V\", ignored",
                                  &name[s].name);
                }
            }

            hash.key = ngx_hash_key_lc;
            hash.max_size = cmcf->server_names_hash_max_size;
            hash.bucket_size = cmcf->server_names_hash_bucket_size;
            hash.name = "server_names_hash";
            hash.pool = cf->pool;

            if (ha.keys.nelts) {
                hash.hash = &in_addr[a].hash;
                hash.temp_pool = NULL;

                if (ngx_hash_init(&hash, ha.keys.elts, ha.keys.nelts) != NGX_OK)
                {
                    ngx_destroy_pool(ha.temp_pool);
                    return NGX_CONF_ERROR;
                }
            }

            if (ha.dns_wildcards.nelts) {

                ngx_qsort(ha.dns_wildcards.elts,
                          (size_t) ha.dns_wildcards.nelts,
                          sizeof(ngx_hash_key_t),
                          ngx_http_cmp_dns_wildcards);

                hash.hash = NULL;
                hash.temp_pool = ha.temp_pool;

                if (ngx_hash_wildcard_init(&hash, ha.dns_wildcards.elts,
                                           ha.dns_wildcards.nelts)
                    != NGX_OK)
                {
                    ngx_destroy_pool(ha.temp_pool);
                    return NGX_CONF_ERROR;
                }

                in_addr[a].dns_wildcards = (ngx_hash_wildcard_t *) hash.hash;
            }

            ngx_destroy_pool(ha.temp_pool);
        }

        in_addr = in_port[p].addrs.elts;
        last = in_port[p].addrs.nelts;

        /*
         * if there is the binding to the "*:port" then we need to bind()
         * to the "*:port" only and ignore the other bindings
         */

        if (in_addr[last - 1].addr == INADDR_ANY) {
            in_addr[last - 1].bind = 1;
            bind_all = 0;

        } else {
            bind_all = 1;
        }

        for (a = 0; a < last; /* void */ ) {

            if (!bind_all && !in_addr[a].bind) {
                a++;
                continue;
            }

            ls = ngx_listening_inet_stream_socket(cf, in_addr[a].addr,
                                                  in_port[p].port);
            if (ls == NULL) {
                return NGX_CONF_ERROR;
            }

            ls->addr_ntop = 1;

            ls->handler = ngx_http_init_connection;

            cscf = in_addr[a].core_srv_conf;
            ls->pool_size = cscf->connection_pool_size;
            ls->post_accept_timeout = cscf->client_header_timeout;

            clcf = cscf->ctx->loc_conf[ngx_http_core_module.ctx_index];

            ls->log = *clcf->err_log;
            ls->log.data = &ls->addr_text;
            ls->log.handler = ngx_accept_log_error;

#if (NGX_WIN32)
            iocpcf = ngx_event_get_conf(cf->cycle->conf_ctx, ngx_iocp_module);
            if (iocpcf->acceptex_read) {
                ls->post_accept_buffer_size = cscf->client_header_buffer_size;
            }
#endif

            ls->backlog = in_addr[a].listen_conf->backlog;
            ls->rcvbuf = in_addr[a].listen_conf->rcvbuf;
            ls->sndbuf = in_addr[a].listen_conf->sndbuf;

#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)
            ls->accept_filter = in_addr[a].listen_conf->accept_filter;
#endif

#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT)
            ls->deferred_accept = in_addr[a].listen_conf->deferred_accept;
#endif

            ls->ctx = ctx;

            hip = ngx_palloc(cf->pool, sizeof(ngx_http_in_port_t));
            if (hip == NULL) {
                return NGX_CONF_ERROR;
            }

            hip->port = in_port[p].port;

            hip->port_text.data = ngx_palloc(cf->pool, 7);
            if (hip->port_text.data == NULL) {
                return NGX_CONF_ERROR;
            }

            ls->servers = hip;

            hip->port_text.len = ngx_sprintf(hip->port_text.data, ":%d",
                                             hip->port)
                                 - hip->port_text.data;

            in_addr = in_port[p].addrs.elts;

            if (in_addr[a].bind && in_addr[a].addr != INADDR_ANY) {
                hip->naddrs = 1;
                done = 0;

            } else if (in_port[p].addrs.nelts > 1
                       && in_addr[last - 1].addr == INADDR_ANY)
            {
                hip->naddrs = last;
                done = 1;

            } else {
                hip->naddrs = 1;
                done = 0;
            }

#if 0
            ngx_log_error(NGX_LOG_ALERT, cf->log, 0,
                          "%ui: %V %d %ui %ui",
                          a, &ls->addr_text, in_addr[a].bind,
                          hip->naddrs, last);
#endif

            hip->addrs = ngx_pcalloc(cf->pool,
                                     hip->naddrs * sizeof(ngx_http_in_addr_t));
            if (hip->addrs == NULL) {
                return NGX_CONF_ERROR;
            }

            for (i = 0; i < hip->naddrs; i++) {
                hip->addrs[i].addr = in_addr[i].addr;
                hip->addrs[i].core_srv_conf = in_addr[i].core_srv_conf;

                if (in_addr[i].hash.buckets == NULL
                    && (in_addr[i].dns_wildcards == NULL
                        || in_addr[i].dns_wildcards->hash.buckets == NULL))
                {
                    continue;
                }

                vn = ngx_palloc(cf->pool, sizeof(ngx_http_virtual_names_t));
                if (vn == NULL) {
                    return NGX_CONF_ERROR;
                }
                hip->addrs[i].virtual_names = vn;

                vn->hash = in_addr[i].hash;
                vn->dns_wildcards = in_addr[i].dns_wildcards;
            }

            if (done) {
                break;
            }

            in_addr++;
            in_port[p].addrs.elts = in_addr;
            last--;

            a = 0;
        }
    }

#if 0
    {
    u_char      address[20];
    ngx_uint_t  p, a;

    in_port = in_ports.elts;
    for (p = 0; p < in_ports.nelts; p++) {
        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0,
                      "port: %d %p", in_port[p].port, &in_port[p]);
        in_addr = in_port[p].addrs.elts;
        for (a = 0; a < in_port[p].addrs.nelts; a++) {
            ngx_inet_ntop(AF_INET, &in_addr[a].addr, address, 20);
            ngx_log_debug3(NGX_LOG_DEBUG_HTTP, cf->log, 0,
                           "%s:%d %p",
                           address, in_port[p].port, in_addr[a].core_srv_conf);
            name = in_addr[a].names.elts;
            for (n = 0; n < in_addr[a].names.nelts; n++) {
                 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, cf->log, 0,
                                "%s:%d %V %p",
                                address, in_port[p].port, &name[n].name,
                                name[n].core_srv_conf);
            }
        }
    }
    }
#endif

    return NGX_CONF_OK;
}


/*
 * add the server address, the server names and the server core module
 * configurations to the port (in_port)
 */

static ngx_int_t
ngx_http_add_address(ngx_conf_t *cf, ngx_http_conf_in_port_t *in_port,
    ngx_http_listen_t *lscf, ngx_http_core_srv_conf_t *cscf)
{
    ngx_http_conf_in_addr_t  *in_addr;

    if (in_port->addrs.elts == NULL) {
        if (ngx_array_init(&in_port->addrs, cf->temp_pool, 4,
                           sizeof(ngx_http_conf_in_addr_t)) != NGX_OK)
        {
            return NGX_ERROR;
        }
    }

    in_addr = ngx_array_push(&in_port->addrs);
    if (in_addr == NULL) {
        return NGX_ERROR;
    }

    in_addr->addr = lscf->addr;
    in_addr->hash.buckets = NULL;
    in_addr->hash.size = 0;
    in_addr->dns_wildcards = NULL;
    in_addr->names.elts = NULL;
    in_addr->core_srv_conf = cscf;
    in_addr->default_server = lscf->conf.default_server;
    in_addr->bind = lscf->conf.bind;
    in_addr->listen_conf = &lscf->conf;

#if (NGX_DEBUG)
    {
    u_char text[20];
    ngx_inet_ntop(AF_INET, &in_addr->addr, text, 20);
    ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0, "address: %s:%d",
                   text, in_port->port);
    }
#endif

    return ngx_http_add_names(cf, in_addr, cscf);
}


/*
 * add the server names and the server core module
 * configurations to the address:port (in_addr)
 */

static ngx_int_t
ngx_http_add_names(ngx_conf_t *cf, ngx_http_conf_in_addr_t *in_addr,
    ngx_http_core_srv_conf_t *cscf)
{
    ngx_uint_t               i, n;
    ngx_http_server_name_t  *server_names, *name;

    if (in_addr->names.elts == NULL) {
        if (ngx_array_init(&in_addr->names, cf->temp_pool, 4,
                           sizeof(ngx_http_server_name_t)) != NGX_OK)
        {
            return NGX_ERROR;
        }
    }

    server_names = cscf->server_names.elts;
    for (i = 0; i < cscf->server_names.nelts; i++) {

        for (n = 0; n < server_names[i].name.len; n++) {
            server_names[i].name.data[n] =
                                     ngx_tolower(server_names[i].name.data[n]);
        }

        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0,
                       "name: %V", &server_names[i].name);


        name = ngx_array_push(&in_addr->names);
        if (name == NULL) {
            return NGX_ERROR;
        }
        server_names = cscf->server_names.elts;

        *name = server_names[i];
    }

    return NGX_OK;
}


static char *
ngx_http_merge_locations(ngx_conf_t *cf, ngx_array_t *locations,
    void **loc_conf, ngx_http_module_t *module, ngx_uint_t ctx_index)
{
    char                       *rv;
    ngx_uint_t                  i;
    ngx_http_core_loc_conf_t  **clcfp;

    clcfp = locations->elts;

    for (i = 0; i < locations->nelts; i++) {
        rv = module->merge_loc_conf(cf, loc_conf[ctx_index],
                                    clcfp[i]->loc_conf[ctx_index]);
        if (rv != NGX_CONF_OK) {
            return rv;
        }

        rv = ngx_http_merge_locations(cf, &clcfp[i]->locations,
                                      clcfp[i]->loc_conf, module, ctx_index);
        if (rv != NGX_CONF_OK) {
            return rv;
        }
    }

    return NGX_CONF_OK;
}


static int ngx_libc_cdecl
ngx_http_cmp_conf_in_addrs(const void *one, const void *two)
{
    ngx_http_conf_in_addr_t  *first, *second;

    first = (ngx_http_conf_in_addr_t *) one;
    second = (ngx_http_conf_in_addr_t *) two;

    if (first->addr == INADDR_ANY) {
        /* the INADDR_ANY must be the last resort, shift it to the end */
        return 1;
    }

    if (first->bind && !second->bind) {
        /* shift explicit bind()ed addresses to the start */
        return -1;
    }

    if (!first->bind && second->bind) {
        /* shift explicit bind()ed addresses to the start */
        return 1;
    }

    /* do not sort by default */

    return 0;
}


static int ngx_libc_cdecl
ngx_http_cmp_dns_wildcards(const void *one, const void *two)
{
    ngx_hash_key_t  *first, *second;

    first = (ngx_hash_key_t *) one;
    second = (ngx_hash_key_t *) two;

    return ngx_strcmp(first->key.data, second->key.data);
}