blob: 965625d64acb3214008f4a53de8ee76e19112e43 [file] [log] [blame]
/*
* Copyright (C) Igor Sysoev
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_event.h>
#include <ngx_http.h>
ngx_int_t
ngx_http_config_add_hash(ngx_http_hash_conf_t *h, ngx_str_t *key, void *value,
ngx_uint_t flags)
{
size_t len;
ngx_str_t *name;
ngx_uint_t i, k, n, skip;
ngx_hash_key_t *hk;
u_char buf[2048];
if (!(flags & NGX_HTTP_WILDCARD_HASH)) {
/* exact hash */
k = 0;
for (i = 0; i < key->len; i++) {
key->data[i] = ngx_tolower(key->data[i]);
k = ngx_hash(k, key->data[i]);
}
k %= NGX_HTTP_CONFIG_HASH;
/* check conflicts in exact hash */
name = h->keys_hash[k].elts;
if (name) {
for (i = 0; i < h->keys_hash[k].nelts; i++) {
if (key->len != name[i].len) {
continue;
}
if (ngx_strncmp(key->data, name[i].data, key->len) == 0) {
return NGX_BUSY;
}
}
} else {
if (ngx_array_init(&h->keys_hash[k], h->temp_pool, 4,
sizeof(ngx_str_t))
!= NGX_OK)
{
return NGX_ERROR;
}
}
name = ngx_array_push(&h->keys_hash[k]);
if (name == NULL) {
return NGX_ERROR;
}
*name = *key;
hk = ngx_array_push(&h->keys);
if (hk == NULL) {
return NGX_ERROR;
}
hk->key = *key;
hk->key_hash = ngx_hash_key(key->data, key->len);
hk->value = value;
} else {
/* wildcard hash */
skip = (key->data[0] == '*') ? 2 : 1;
k = 0;
for (i = skip; i < key->len; i++) {
key->data[i] = ngx_tolower(key->data[i]);
k = ngx_hash(k, key->data[i]);
}
k %= NGX_HTTP_CONFIG_HASH;
if (skip == 1) {
/* check conflicts in exact hash for ".example.com" */
name = h->keys_hash[k].elts;
if (name) {
len = key->len - skip;
for (i = 0; i < h->keys_hash[k].nelts; i++) {
if (len != name[i].len) {
continue;
}
if (ngx_strncmp(&key->data[1], name[i].data, len) == 0) {
return NGX_BUSY;
}
}
} else {
if (ngx_array_init(&h->keys_hash[k], h->temp_pool, 4,
sizeof(ngx_str_t))
!= NGX_OK)
{
return NGX_ERROR;
}
}
name = ngx_array_push(&h->keys_hash[k]);
if (name == NULL) {
return NGX_ERROR;
}
name->len = key->len - 1;
name->data = ngx_palloc(h->temp_pool, name->len);
if (name->data == NULL) {
return NGX_ERROR;
}
ngx_memcpy(name->data, &key->data[1], name->len);
}
/*
* convert "*.example.com" to "com.example.\0"
* and ".example.com" to "com.example\0"
*/
len = 0;
n = 0;
for (i = key->len - 1; i; i--) {
if (key->data[i] == '.') {
ngx_memcpy(&buf[n], &key->data[i + 1], len);
n += len;
buf[n++] = '.';
len = 0;
continue;
}
len++;
}
if (len) {
ngx_memcpy(&buf[n], &key->data[1], len);
n += len;
}
buf[n] = '\0';
/* check conflicts in wildcard hash */
name = h->dns_hash[k].elts;
if (name) {
len = key->len - skip;
for (i = 0; i < h->dns_hash[k].nelts; i++) {
if (len != name[i].len) {
continue;
}
if (ngx_strncmp(key->data + skip, name[i].data, len) == 0) {
return NGX_BUSY;
}
}
} else {
if (ngx_array_init(&h->dns_hash[k], h->temp_pool, 4,
sizeof(ngx_str_t))
!= NGX_OK)
{
return NGX_ERROR;
}
}
name = ngx_array_push(&h->dns_hash[k]);
if (name == NULL) {
return NGX_ERROR;
}
name->len = key->len - skip;
name->data = ngx_palloc(h->temp_pool, name->len);
if (name->data == NULL) {
return NGX_ERROR;
}
ngx_memcpy(name->data, key->data + skip, name->len);
ngx_memcpy(key->data, buf, key->len);
key->len--;
hk = ngx_array_push(&h->dns_wildcards);
if (hk == NULL) {
return NGX_ERROR;
}
hk->key = *key;
hk->key_hash = 0;
hk->value = value;
}
return NGX_OK;
}