/* * Copyright (C) Igor Sysoev */ #include #include #include #include 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; }