diff options
Diffstat (limited to 'src/http/ngx_http.c')
-rw-r--r-- | src/http/ngx_http.c | 548 |
1 files changed, 300 insertions, 248 deletions
diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c index 449a4e9bd..d1d64b8a5 100644 --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -14,18 +14,22 @@ static char *ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static int ngx_libc_cdecl ngx_cmp_server_names(const void *one, const void *two); static ngx_int_t ngx_http_add_address(ngx_conf_t *cf, - ngx_http_in_port_t *in_port, ngx_http_listen_t *lscf, + 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_in_addr_t *in_addr, ngx_http_core_srv_conf_t *cscf); + 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_max_module; -ngx_uint_t ngx_http_total_requests; -uint64_t ngx_http_total_sent; +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); @@ -72,19 +76,24 @@ static char * ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *rv; - ngx_uint_t mi, m, s, l, p, a, n, key; - ngx_uint_t port_found, addr_found; - ngx_uint_t virtual_names, separate_binding; + u_char ch; + ngx_int_t rc; + ngx_uint_t mi, m, s, l, p, a, n, 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_in_port_t *in_port, *inport; - ngx_http_in_addr_t *in_addr, *inaddr; - ngx_http_server_name_t *s_name, *name; + 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; @@ -414,7 +423,8 @@ ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) * to quickly find the server core module configuration at run-time */ - if (ngx_array_init(&in_ports, cf->pool, 2, sizeof(ngx_http_in_port_t)) + if (ngx_array_init(&in_ports, cf->temp_pool, 2, + sizeof(ngx_http_conf_in_port_t)) != NGX_OK) { return NGX_CONF_ERROR; @@ -430,137 +440,85 @@ ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) lscf = cscfp[s]->listen.elts; for (l = 0; l < cscfp[s]->listen.nelts; l++) { - port_found = 0; - /* AF_INET only */ in_port = in_ports.elts; for (p = 0; p < in_ports.nelts; p++) { - if (lscf[l].port == in_port[p].port) { - - /* the port is already in the port list */ + if (lscf[l].port != in_port[p].port) { + continue; + } - port_found = 1; - addr_found = 0; + /* 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++) { + 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) { + if (lscf[l].addr != in_addr[a].addr) { + continue; + } - /* the address is already in the address list */ + /* 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; - } + 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 - */ + /* + * check the duplicate "default" server + * for this address:port + */ - if (lscf[l].conf.default_server) { + if (lscf[l].conf.default_server) { - if (in_addr[a].conf.default_server) { - ngx_log_error(NGX_LOG_ERR, cf->log, 0, + 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].conf.default_server = 1; - } - - addr_found = 1; - - break; - - } else if (in_addr[a].addr == INADDR_ANY) { - - /* the INADDR_ANY is always the last address */ - - inaddr = ngx_array_push(&in_port[p].addrs); - if (inaddr == NULL) { - return NGX_CONF_ERROR; - } - in_addr = in_port[p].addrs.elts; - - /* - * the INADDR_ANY must be the last resort - * so we move it to the end of the address list - * and put the new address in its place - */ - - ngx_memcpy(inaddr, &in_addr[a], - sizeof(ngx_http_in_addr_t)); - - in_addr[a].addr = lscf[l].addr; - in_addr[a].names.elts = NULL; - in_addr[a].hash = NULL; - in_addr[a].wildcards.elts = NULL; - in_addr[a].core_srv_conf = cscfp[s]; - in_addr[a].conf = lscf[l].conf; - - if (ngx_http_add_names(cf, &in_addr[a], cscfp[s]) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - - addr_found = 1; - - break; - } - } - - if (!addr_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; } + + in_addr[a].core_srv_conf = cscfp[s]; + in_addr[a].default_server = 1; } - } - } - if (!port_found) { + goto found; + } - /* add the port to the in_port list */ + /* + * add the address to the addresses list that + * bound to this port + */ - in_port = ngx_array_push(&in_ports); - if (in_port == NULL) { + if (ngx_http_add_address(cf, &in_port[p], &lscf[l], cscfp[s]) + != NGX_OK) + { return NGX_CONF_ERROR; } - in_port->port = lscf[l].port; - in_port->addrs.elts = NULL; + goto found; + } - in_port->port_text.data = ngx_palloc(cf->pool, 7); - if (in_port->port_text.data == NULL) { - return NGX_CONF_ERROR; - } + /* add the port to the in_port list */ - in_port->port_text.len = ngx_sprintf(in_port->port_text.data, - ":%d", in_port->port) - - in_port->port_text.data; + in_port = ngx_array_push(&in_ports); + if (in_port == NULL) { + return NGX_CONF_ERROR; + } - if (ngx_http_add_address(cf, in_port, &lscf[l], cscfp[s]) - != NGX_OK) - { - 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; } } @@ -572,7 +530,8 @@ ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) in_port = in_ports.elts; for (p = 0; p < in_ports.nelts; p++) { - separate_binding = 0; + 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 @@ -582,33 +541,13 @@ ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) in_addr = in_port[p].addrs.elts; for (a = 0; a < in_port[p].addrs.nelts; a++) { - if (in_addr[a].conf.bind) { - separate_binding = 1; - } - - virtual_names = 0; - name = in_addr[a].names.elts; for (n = 0; n < in_addr[a].names.nelts; n++) { if (in_addr[a].core_srv_conf != name[n].core_srv_conf || name[n].core_srv_conf->restrict_host_names != NGX_HTTP_RESTRICT_HOST_OFF) { - virtual_names = 1; - break; - } - } - - if (!virtual_names) { - name = in_addr[a].wildcards.elts; - for (n = 0; n < in_addr[a].wildcards.nelts; n++) { - if (in_addr[a].core_srv_conf != name[n].core_srv_conf - || name[n].core_srv_conf->restrict_host_names - != NGX_HTTP_RESTRICT_HOST_OFF) - { - virtual_names = 1; - break; - } + goto virtual_names; } } @@ -618,65 +557,132 @@ ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) * then we do not need to check them at run-time at all */ - if (!virtual_names) { - in_addr[a].names.nelts = 0; - continue; + 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++) { - ngx_qsort(in_addr[a].names.elts, in_addr[a].names.nelts, - sizeof(ngx_http_server_name_t), ngx_cmp_server_names); + ch = name[s].name.data[0]; + if (ch == '*' || ch == '.') { + continue; + } - /* create a hash for many names */ + rc = ngx_hash_add_key(&ha, &name[s].name, name[s].core_srv_conf, + 0); - if (in_addr[a].names.nelts > cmcf->server_names_hash_threshold) { - in_addr[a].hash = ngx_palloc(cf->pool, - cmcf->server_names_hash - * sizeof(ngx_array_t)); - if (in_addr[a].hash == NULL) { + if (rc == NGX_ERROR) { return NGX_CONF_ERROR; } - for (n = 0; n < cmcf->server_names_hash; n++) { - if (ngx_array_init(&in_addr[a].hash[n], cf->pool, 4, - sizeof(ngx_http_server_name_t)) != NGX_OK) - { - 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); } + } - name = in_addr[a].names.elts; - for (s = 0; s < in_addr[a].names.nelts; s++) { - ngx_http_server_names_hash_key(key, name[s].name.data, - name[s].name.len, - cmcf->server_names_hash); + for (s = 0; s < in_addr[a].names.nelts; s++) { - s_name = ngx_array_push(&in_addr[a].hash[key]); - if (s_name == NULL) { - return NGX_CONF_ERROR; - } - name = in_addr[a].names.elts; + ch = name[s].name.data[0]; - *s_name = name[s]; + 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[a - 1].addr == INADDR_ANY && !separate_binding) { - a--; + if (in_addr[last - 1].addr == INADDR_ANY) { + in_addr[last - 1].bind = 1; + bind_all = 0; } else { - a = 0; + bind_all = 1; } - in_addr = in_port[p].addrs.elts; - while (a < in_port[p].addrs.nelts) { + 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); @@ -705,68 +711,98 @@ ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } #endif - ls->backlog = in_addr[a].conf.backlog; - ls->rcvbuf = in_addr[a].conf.rcvbuf; - ls->sndbuf = in_addr[a].conf.sndbuf; + 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].conf.accept_filter; + 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].conf.deferred_accept; + ls->deferred_accept = in_addr[a].listen_conf->deferred_accept; #endif ls->ctx = ctx; - if (in_port[p].addrs.nelts > 1) { - - in_addr = in_port[p].addrs.elts; - if (in_addr[in_port[p].addrs.nelts - 1].addr != INADDR_ANY) { + hip = ngx_palloc(cf->pool, sizeof(ngx_http_in_port_t)); + if (hip == NULL) { + return NGX_CONF_ERROR; + } - /* - * if this port has not the "*:port" binding then create - * the separate ngx_http_in_port_t for the all bindings - */ + hip->port = in_port[p].port; - inport = ngx_palloc(cf->pool, sizeof(ngx_http_in_port_t)); - if (inport == NULL) { - return NGX_CONF_ERROR; - } + hip->port_text.data = ngx_palloc(cf->pool, 7); + if (hip->port_text.data == NULL) { + return NGX_CONF_ERROR; + } - inport->port = in_port[p].port; - inport->port_text = in_port[p].port_text; + ls->servers = hip; - /* init list of the addresses ... */ + hip->port_text.len = ngx_sprintf(hip->port_text.data, ":%d", + hip->port) + - hip->port_text.data; - if (ngx_array_init(&inport->addrs, cf->pool, 1, - sizeof(ngx_http_in_addr_t)) != NGX_OK) - { - return NGX_CONF_ERROR; - } + in_addr = in_port[p].addrs.elts; - /* ... and set up it with the first address */ + if (in_addr[a].bind && in_addr[a].addr != INADDR_ANY) { + hip->naddrs = 1; + done = 0; - inport->addrs.nelts = 1; - inport->addrs.elts = in_port[p].addrs.elts; + } else if (in_port[p].addrs.nelts > 1 + && in_addr[last - 1].addr == INADDR_ANY) + { + hip->naddrs = last; + done = 1; - ls->servers = inport; + } else { + hip->naddrs = 1; + done = 0; + } - /* prepare for the next cycle */ +#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 - in_port[p].addrs.elts = (char *) in_port[p].addrs.elts - + in_port[p].addrs.size; - in_port[p].addrs.nelts--; + hip->addrs = ngx_pcalloc(cf->pool, + hip->naddrs * sizeof(ngx_http_in_addr_t)); + if (hip->addrs == NULL) { + return NGX_CONF_ERROR; + } - in_addr = (ngx_http_in_addr_t *) in_port[p].addrs.elts; - a = 0; + 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; } - ls->servers = &in_port[p]; - a++; + if (done) { + break; + } + + in_addr++; + in_port[p].addrs.elts = in_addr; + last--; + + a = 0; } } @@ -785,12 +821,12 @@ ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) ngx_log_debug3(NGX_LOG_DEBUG_HTTP, cf->log, 0, "%s:%d %p", address, in_port[p].port, in_addr[a].core_srv_conf); - s_name = in_addr[a].names.elts; + 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, &s_name[n].name, - s_name[n].core_srv_conf); + address, in_port[p].port, &name[n].name, + name[n].core_srv_conf); } } } @@ -801,30 +837,20 @@ ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } -static int ngx_libc_cdecl -ngx_cmp_server_names(const void *one, const void *two) -{ - ngx_http_server_name_t *first = (ngx_http_server_name_t *) one; - ngx_http_server_name_t *second = (ngx_http_server_name_t *) two; - - return ngx_strcmp(first->name.data, second->name.data); -} - - /* * 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_in_port_t *in_port, +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_in_addr_t *in_addr; + ngx_http_conf_in_addr_t *in_addr; if (in_port->addrs.elts == NULL) { - if (ngx_array_init(&in_port->addrs, cf->pool, 4, - sizeof(ngx_http_in_addr_t)) != NGX_OK) + if (ngx_array_init(&in_port->addrs, cf->temp_pool, 4, + sizeof(ngx_http_conf_in_addr_t)) != NGX_OK) { return NGX_ERROR; } @@ -836,11 +862,14 @@ ngx_http_add_address(ngx_conf_t *cf, ngx_http_in_port_t *in_port, } 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->hash = NULL; - in_addr->wildcards.elts = NULL; in_addr->core_srv_conf = cscf; - in_addr->conf = lscf->conf; + in_addr->default_server = lscf->conf.default_server; + in_addr->bind = lscf->conf.bind; + in_addr->listen_conf = &lscf->conf; #if (NGX_DEBUG) { @@ -861,23 +890,14 @@ ngx_http_add_address(ngx_conf_t *cf, ngx_http_in_port_t *in_port, */ static ngx_int_t -ngx_http_add_names(ngx_conf_t *cf, ngx_http_in_addr_t *in_addr, +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_array_t *array; ngx_http_server_name_t *server_names, *name; if (in_addr->names.elts == NULL) { - if (ngx_array_init(&in_addr->names, cf->pool, 4, - sizeof(ngx_http_server_name_t)) != NGX_OK) - { - return NGX_ERROR; - } - } - - if (in_addr->wildcards.elts == NULL) { - if (ngx_array_init(&in_addr->wildcards, cf->pool, 1, + if (ngx_array_init(&in_addr->names, cf->temp_pool, 4, sizeof(ngx_http_server_name_t)) != NGX_OK) { return NGX_ERROR; @@ -895,17 +915,8 @@ ngx_http_add_names(ngx_conf_t *cf, ngx_http_in_addr_t *in_addr, ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0, "name: %V", &server_names[i].name); - /* TODO: duplicate names can be checked here */ - - - if (server_names[i].wildcard) { - array = &in_addr->wildcards; - - } else { - array = &in_addr->names; - } - name = ngx_array_push(array); + name = ngx_array_push(&in_addr->names); if (name == NULL) { return NGX_ERROR; } @@ -926,7 +937,7 @@ ngx_http_merge_locations(ngx_conf_t *cf, ngx_array_t *locations, ngx_uint_t i; ngx_http_core_loc_conf_t **clcfp; - clcfp = /* (ngx_http_core_loc_conf_t **) */ locations->elts; + clcfp = locations->elts; for (i = 0; i < locations->nelts; i++) { rv = module->merge_loc_conf(cf, loc_conf[ctx_index], @@ -944,3 +955,44 @@ ngx_http_merge_locations(ngx_conf_t *cf, ngx_array_t *locations, 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); +} |