diff options
Diffstat (limited to 'src/http/ngx_http_config.c')
-rw-r--r-- | src/http/ngx_http_config.c | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/src/http/ngx_http_config.c b/src/http/ngx_http_config.c new file mode 100644 index 000000000..965625d64 --- /dev/null +++ b/src/http/ngx_http_config.c @@ -0,0 +1,214 @@ + +/* + * 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; +} |