# HG changeset patch # User Igor Sysoev # Date 1181764800 -14400 # Node ID 429900ca25ee0bb45391c0c0aec4a2c2b945c5d1 # Parent fcb663e926638ddc127d74ea5d5db0bf76ac1cee nginx 0.6.0 *) Feature: the "server_name", "map", and "valid_referers" directives support the "www.example.*" wildcards. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,10 @@ +Changes with nginx 0.6.0 14 Jun 2007 + + *) Feature: the "server_name", "map", and "valid_referers" directives + supports the "www.example.*" wildcards. + + Changes with nginx 0.5.25 11 Jun 2007 *) Bugfix: nginx could not be built with the diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,10 @@ +Изменения в nginx 0.6.0 14.06.2007 + + *) Добавление: директивы "server_name", "map", and "valid_referers" + поддерживают маски вида "www.example.*". + + Изменения в nginx 0.5.25 11.06.2007 *) Исправление: nginx не собирался с параметром diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,7 +8,7 @@ #define _NGINX_H_INCLUDED_ -#define NGINX_VERSION "0.5.25" +#define NGINX_VERSION "0.6.0" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_hash.c b/src/core/ngx_hash.c --- a/src/core/ngx_hash.c +++ b/src/core/ngx_hash.c @@ -53,7 +53,7 @@ ngx_hash_find(ngx_hash_t *hash, ngx_uint void * -ngx_hash_find_wildcard(ngx_hash_wildcard_t *hwc, u_char *name, size_t len) +ngx_hash_find_wc_head(ngx_hash_wildcard_t *hwc, u_char *name, size_t len) { void *value; ngx_uint_t i, n, key; @@ -63,7 +63,7 @@ ngx_hash_find_wildcard(ngx_hash_wildcard line.len = len; line.data = name; - ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "wc:\"%V\"", &line); + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "wch:\"%V\"", &line); #endif n = len; @@ -112,7 +112,7 @@ ngx_hash_find_wildcard(ngx_hash_wildcard } } - value = ngx_hash_find_wildcard(hwc, name, n - 1); + value = ngx_hash_find_wc_head(hwc, name, n - 1); if (value) { return value; @@ -128,6 +128,104 @@ ngx_hash_find_wildcard(ngx_hash_wildcard } +void * +ngx_hash_find_wc_tail(ngx_hash_wildcard_t *hwc, u_char *name, size_t len) +{ + void *value; + ngx_uint_t i, key; + +#if 0 + ngx_str_t line; + + line.len = len; + line.data = name; + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "wct:\"%V\"", &line); +#endif + + key = 0; + + for (i = 0; i < len; i++) { + if (name[i] == '.') { + break; + } + + key = ngx_hash(key, name[i]); + } + + if (i == len) { + return NULL; + } + +#if 0 + ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "key:\"%ui\"", key); +#endif + + value = ngx_hash_find(&hwc->hash, key, name, i); + + if (value) { + + /* + * the 2 low bits of value have the special meaning: + * 00 - value is data pointer, + * 01 - value is pointer to wildcard hash allowing "example.*". + */ + + if ((uintptr_t) value & 1) { + + i++; + + hwc = (ngx_hash_wildcard_t *) ((uintptr_t) value & (uintptr_t) ~3); + + value = ngx_hash_find_wc_tail(hwc, &name[i], len - i); + + if (value) { + return value; + } + + return hwc->value; + } + + return value; + } + + return hwc->value; +} + + +void * +ngx_hash_find_combined(ngx_hash_combined_t *hash, ngx_uint_t key, u_char *name, + size_t len) +{ + void *value; + + if (hash->hash.buckets) { + value = ngx_hash_find(&hash->hash, key, name, len); + + if (value) { + return value; + } + } + + if (hash->wc_head && hash->wc_head->hash.buckets) { + value = ngx_hash_find_wc_head(hash->wc_head, name, len); + + if (value) { + return value; + } + } + + if (hash->wc_tail && hash->wc_tail->hash.buckets) { + value = ngx_hash_find_wc_tail(hash->wc_tail, name, len); + + if (value) { + return value; + } + } + + return NULL; +} + + #define NGX_HASH_ELT_SIZE(name) \ (sizeof(void *) + ngx_align((name)->key.len + 1, sizeof(void *))) @@ -544,7 +642,14 @@ ngx_hash_keys_array_init(ngx_hash_keys_a return NGX_ERROR; } - if (ngx_array_init(&ha->dns_wildcards, ha->temp_pool, asize, + if (ngx_array_init(&ha->dns_wc_head, ha->temp_pool, asize, + sizeof(ngx_hash_key_t)) + != NGX_OK) + { + return NGX_ERROR; + } + + if (ngx_array_init(&ha->dns_wc_tail, ha->temp_pool, asize, sizeof(ngx_hash_key_t)) != NGX_OK) { @@ -556,9 +661,15 @@ ngx_hash_keys_array_init(ngx_hash_keys_a return NGX_ERROR; } - ha->dns_wildcards_hash = ngx_pcalloc(ha->temp_pool, - sizeof(ngx_array_t) * ha->hsize); - if (ha->dns_wildcards_hash == NULL) { + ha->dns_wc_head_hash = ngx_pcalloc(ha->temp_pool, + sizeof(ngx_array_t) * ha->hsize); + if (ha->dns_wc_head_hash == NULL) { + return NGX_ERROR; + } + + ha->dns_wc_tail_hash = ngx_pcalloc(ha->temp_pool, + sizeof(ngx_array_t) * ha->hsize); + if (ha->dns_wc_tail_hash == NULL) { return NGX_ERROR; } @@ -571,37 +682,144 @@ ngx_hash_add_key(ngx_hash_keys_arrays_t ngx_uint_t flags) { size_t len; - u_char *reverse; + u_char *p; ngx_str_t *name; - ngx_uint_t i, k, n, skip; + ngx_uint_t i, k, n, skip, last; + ngx_array_t *keys, *hwc; ngx_hash_key_t *hk; - if (!(flags & NGX_HASH_WILDCARD_KEY)) { + last = key->len; + + if (flags & NGX_HASH_WILDCARD_KEY) { - /* exact hash */ + /* + * supported wildcards: + * "*.example.com", ".example.com", and "www.example.*" + */ - k = 0; + n = 0; for (i = 0; i < key->len; i++) { - if (!(flags & NGX_HASH_READONLY_KEY)) { - key->data[i] = ngx_tolower(key->data[i]); + + if (key->data[i] == '*') { + if (++n > 1) { + return NGX_DECLINED; + } + } + + if (key->data[i] == '.' && key->data[i + 1] == '.') { + return NGX_DECLINED; } - k = ngx_hash(k, key->data[i]); + } + + if (key->len > 1 && key->data[0] == '.') { + skip = 1; + goto wildcard; + } + + if (key->len > 2) { + + if (key->data[0] == '*' && key->data[1] == '.') { + skip = 2; + goto wildcard; + } + + if (key->data[i - 2] == '.' && key->data[i - 1] == '*') { + skip = 0; + last -= 2; + goto wildcard; + } } - k %= ha->hsize; + if (n) { + return NGX_DECLINED; + } + } + + /* exact hash */ + + k = 0; + + for (i = 0; i < last; i++) { + if (!(flags & NGX_HASH_READONLY_KEY)) { + key->data[i] = ngx_tolower(key->data[i]); + } + k = ngx_hash(k, key->data[i]); + } + + k %= ha->hsize; + + /* check conflicts in exact hash */ + + name = ha->keys_hash[k].elts; + + if (name) { + for (i = 0; i < ha->keys_hash[k].nelts; i++) { + if (last != name[i].len) { + continue; + } + + if (ngx_strncmp(key->data, name[i].data, last) == 0) { + return NGX_BUSY; + } + } - /* check conflicts in exact hash */ + } else { + if (ngx_array_init(&ha->keys_hash[k], ha->temp_pool, 4, + sizeof(ngx_str_t)) + != NGX_OK) + { + return NGX_ERROR; + } + } + + name = ngx_array_push(&ha->keys_hash[k]); + if (name == NULL) { + return NGX_ERROR; + } + + *name = *key; + + hk = ngx_array_push(&ha->keys); + if (hk == NULL) { + return NGX_ERROR; + } + + hk->key = *key; + hk->key_hash = ngx_hash_key(key->data, last); + hk->value = value; + + return NGX_OK; + + +wildcard: + + /* wildcard hash */ + + k = 0; + + for (i = skip; i < last; i++) { + key->data[i] = ngx_tolower(key->data[i]); + k = ngx_hash(k, key->data[i]); + } + + k %= ha->hsize; + + if (skip == 1) { + + /* check conflicts in exact hash for ".example.com" */ name = ha->keys_hash[k].elts; if (name) { + len = last - skip; + for (i = 0; i < ha->keys_hash[k].nelts; i++) { - if (key->len != name[i].len) { + if (len != name[i].len) { continue; } - if (ngx_strncmp(key->data, name[i].data, key->len) == 0) { + if (ngx_strncmp(&key->data[1], name[i].data, len) == 0) { return NGX_BUSY; } } @@ -620,92 +838,36 @@ ngx_hash_add_key(ngx_hash_keys_arrays_t return NGX_ERROR; } - *name = *key; - - hk = ngx_array_push(&ha->keys); - if (hk == NULL) { + name->len = last - 1; + name->data = ngx_palloc(ha->temp_pool, name->len); + if (name->data == 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 %= ha->hsize; - - if (skip == 1) { - - /* check conflicts in exact hash for ".example.com" */ - - name = ha->keys_hash[k].elts; - - if (name) { - len = key->len - skip; + ngx_memcpy(name->data, &key->data[1], name->len); + } - for (i = 0; i < ha->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(&ha->keys_hash[k], ha->temp_pool, 4, - sizeof(ngx_str_t)) - != NGX_OK) - { - return NGX_ERROR; - } - } - - name = ngx_array_push(&ha->keys_hash[k]); - if (name == NULL) { - return NGX_ERROR; - } - - name->len = key->len - 1; - name->data = ngx_palloc(ha->temp_pool, name->len); - if (name->data == NULL) { - return NGX_ERROR; - } - - ngx_memcpy(name->data, &key->data[1], name->len); - } - + if (skip) { /* * convert "*.example.com" to "com.example.\0" * and ".example.com" to "com.example\0" */ - reverse = ngx_palloc(ha->temp_pool, key->len); - if (reverse == NULL) { + p = ngx_palloc(ha->temp_pool, last); + if (p == NULL) { return NGX_ERROR; } len = 0; n = 0; - for (i = key->len - 1; i; i--) { + for (i = last - 1; i; i--) { if (key->data[i] == '.') { - ngx_memcpy(&reverse[n], &key->data[i + 1], len); + ngx_memcpy(&p[n], &key->data[i + 1], len); n += len; - reverse[n++] = '.'; + p[n++] = '.'; len = 0; continue; } @@ -714,63 +876,75 @@ ngx_hash_add_key(ngx_hash_keys_arrays_t } if (len) { - ngx_memcpy(&reverse[n], &key->data[1], len); + ngx_memcpy(&p[n], &key->data[1], len); n += len; } - reverse[n] = '\0'; + p[n] = '\0'; + hwc = &ha->dns_wc_head; + keys = &ha->dns_wc_head_hash[k]; + + } else { - hk = ngx_array_push(&ha->dns_wildcards); - if (hk == NULL) { - return NGX_ERROR; - } + /* convert "www.example.*" to "www.example\0" */ - hk->key.len = key->len - 1; - hk->key.data = reverse; - hk->key_hash = 0; - hk->value = value; + p = key->data; + key->data[last] = '\0'; + last++; + + hwc = &ha->dns_wc_tail; + keys = &ha->dns_wc_tail_hash[k]; + } - /* check conflicts in wildcard hash */ + hk = ngx_array_push(hwc); + if (hk == NULL) { + return NGX_ERROR; + } - name = ha->dns_wildcards_hash[k].elts; + hk->key.len = last - 1; + hk->key.data = p; + hk->key_hash = 0; + hk->value = value; - if (name) { - len = key->len - skip; - for (i = 0; i < ha->dns_wildcards_hash[k].nelts; i++) { - if (len != name[i].len) { - continue; - } + /* check conflicts in wildcard hash */ + + name = keys->elts; - if (ngx_strncmp(key->data + skip, name[i].data, len) == 0) { - return NGX_BUSY; - } + if (name) { + len = last - skip; + + for (i = 0; i < keys->nelts; i++) { + if (len != name[i].len) { + continue; } - } else { - if (ngx_array_init(&ha->dns_wildcards_hash[k], ha->temp_pool, 4, - sizeof(ngx_str_t)) - != NGX_OK) - { - return NGX_ERROR; + if (ngx_strncmp(key->data + skip, name[i].data, len) == 0) { + return NGX_BUSY; } } - name = ngx_array_push(&ha->dns_wildcards_hash[k]); - if (name == NULL) { + } else { + if (ngx_array_init(keys, ha->temp_pool, 4, sizeof(ngx_str_t)) != NGX_OK) + { return NGX_ERROR; } + } - name->len = key->len - skip; - name->data = ngx_palloc(ha->temp_pool, name->len); - if (name->data == NULL) { - return NGX_ERROR; - } + name = ngx_array_push(keys); + if (name == NULL) { + return NGX_ERROR; + } - ngx_memcpy(name->data, key->data + skip, name->len); + name->len = last - skip; + name->data = ngx_palloc(ha->temp_pool, name->len); + if (name->data == NULL) { + return NGX_ERROR; } + ngx_memcpy(name->data, key->data + skip, name->len); + return NGX_OK; } diff --git a/src/core/ngx_hash.h b/src/core/ngx_hash.h --- a/src/core/ngx_hash.h +++ b/src/core/ngx_hash.h @@ -42,6 +42,13 @@ typedef ngx_uint_t (*ngx_hash_key_pt) (u typedef struct { + ngx_hash_t hash; + ngx_hash_wildcard_t *wc_head; + ngx_hash_wildcard_t *wc_tail; +} ngx_hash_combined_t; + + +typedef struct { ngx_hash_t *hash; ngx_hash_key_pt key; @@ -73,8 +80,11 @@ typedef struct { ngx_array_t keys; ngx_array_t *keys_hash; - ngx_array_t dns_wildcards; - ngx_array_t *dns_wildcards_hash; + ngx_array_t dns_wc_head; + ngx_array_t *dns_wc_head_hash; + + ngx_array_t dns_wc_tail; + ngx_array_t *dns_wc_tail_hash; } ngx_hash_keys_arrays_t; @@ -87,8 +97,10 @@ typedef struct { void *ngx_hash_find(ngx_hash_t *hash, ngx_uint_t key, u_char *name, size_t len); -void *ngx_hash_find_wildcard(ngx_hash_wildcard_t *hwc, u_char *name, - size_t len); +void *ngx_hash_find_wc_head(ngx_hash_wildcard_t *hwc, u_char *name, size_t len); +void *ngx_hash_find_wc_tail(ngx_hash_wildcard_t *hwc, u_char *name, size_t len); +void *ngx_hash_find_combined(ngx_hash_combined_t *hash, ngx_uint_t key, + u_char *name, size_t len); ngx_int_t ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts); diff --git a/src/http/modules/ngx_http_map_module.c b/src/http/modules/ngx_http_map_module.c --- a/src/http/modules/ngx_http_map_module.c +++ b/src/http/modules/ngx_http_map_module.c @@ -26,8 +26,7 @@ typedef struct { typedef struct { - ngx_hash_t hash; - ngx_hash_wildcard_t *dns_wildcards; + ngx_hash_combined_t hash; ngx_int_t index; ngx_http_variable_value_t *default_value; ngx_uint_t hostnames; /* unsigned hostnames:1 */ @@ -142,28 +141,13 @@ ngx_http_map_variable(ngx_http_request_t key = ngx_hash(key, name[i]); } - value = NULL; - - if (map->hash.buckets) { - value = ngx_hash_find(&map->hash, key, name, len); - } + value = ngx_hash_find_combined(&map->hash, key, name, len); if (value) { *v = *value; } else { - if (map->dns_wildcards && map->dns_wildcards->hash.buckets) { - value = ngx_hash_find_wildcard(map->dns_wildcards, name, len); - if (value) { - *v = *value; - - } else { - *v = *map->default_value; - } - - } else { - *v = *map->default_value; - } + *v = *map->default_value; } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -282,6 +266,9 @@ ngx_http_map_block(ngx_conf_t *cf, ngx_c return rv; } + map->default_value = ctx.default_value ? ctx.default_value: + &ngx_http_variable_null_value; + hash.key = ngx_hash_key_lc; hash.max_size = mcf->hash_max_size; hash.bucket_size = mcf->hash_bucket_size; @@ -289,7 +276,7 @@ ngx_http_map_block(ngx_conf_t *cf, ngx_c hash.pool = cf->pool; if (ctx.keys.keys.nelts) { - hash.hash = &map->hash; + hash.hash = &map->hash.hash; hash.temp_pool = NULL; if (ngx_hash_init(&hash, ctx.keys.keys.elts, ctx.keys.keys.nelts) @@ -300,27 +287,44 @@ ngx_http_map_block(ngx_conf_t *cf, ngx_c } } - map->default_value = ctx.default_value ? ctx.default_value: - &ngx_http_variable_null_value; + if (ctx.keys.dns_wc_head.nelts) { - if (ctx.keys.dns_wildcards.nelts) { - - ngx_qsort(ctx.keys.dns_wildcards.elts, - (size_t) ctx.keys.dns_wildcards.nelts, + ngx_qsort(ctx.keys.dns_wc_head.elts, + (size_t) ctx.keys.dns_wc_head.nelts, sizeof(ngx_hash_key_t), ngx_http_map_cmp_dns_wildcards); hash.hash = NULL; hash.temp_pool = pool; - if (ngx_hash_wildcard_init(&hash, ctx.keys.dns_wildcards.elts, - ctx.keys.dns_wildcards.nelts) + if (ngx_hash_wildcard_init(&hash, ctx.keys.dns_wc_head.elts, + ctx.keys.dns_wc_head.nelts) != NGX_OK) { ngx_destroy_pool(pool); return NGX_CONF_ERROR; } - map->dns_wildcards = (ngx_hash_wildcard_t *) hash.hash; + map->hash.wc_head = (ngx_hash_wildcard_t *) hash.hash; + } + + if (ctx.keys.dns_wc_tail.nelts) { + + ngx_qsort(ctx.keys.dns_wc_tail.elts, + (size_t) ctx.keys.dns_wc_tail.nelts, + sizeof(ngx_hash_key_t), ngx_http_map_cmp_dns_wildcards); + + hash.hash = NULL; + hash.temp_pool = pool; + + if (ngx_hash_wildcard_init(&hash, ctx.keys.dns_wc_tail.elts, + ctx.keys.dns_wc_tail.nelts) + != NGX_OK) + { + ngx_destroy_pool(pool); + return NGX_CONF_ERROR; + } + + map->hash.wc_tail = (ngx_hash_wildcard_t *) hash.hash; } ngx_destroy_pool(pool); @@ -344,10 +348,9 @@ ngx_http_map_cmp_dns_wildcards(const voi static char * ngx_http_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) { - u_char ch; ngx_int_t rc; ngx_str_t *value, file; - ngx_uint_t i, key, flags; + ngx_uint_t i, key; ngx_http_map_conf_ctx_t *ctx; ngx_http_variable_value_t *var, **vp; @@ -439,50 +442,36 @@ ngx_http_map(ngx_conf_t *cf, ngx_command found: - ch = value[0].data[0]; - - if ((ch != '*' && ch != '.') || ctx->hostnames == 0) { - - if (ngx_strcmp(value[0].data, "default") == 0) { - - if (ctx->default_value) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "duplicate default map parameter"); - return NGX_CONF_ERROR; - } - - ctx->default_value = var; + if (ngx_strcmp(value[0].data, "default") == 0) { - return NGX_CONF_OK; - } - - if (value[0].len && ch == '!') { - value[0].len--; - value[0].data++; - } - - flags = 0; - - } else { - - if ((ch == '*' && (value[0].len < 3 || value[0].data[1] != '.')) - || (ch == '.' && value[0].len < 2)) - { + if (ctx->default_value) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid DNS wildcard \"%V\"", &value[0]); - + "duplicate default map parameter"); return NGX_CONF_ERROR; } - flags = NGX_HASH_WILDCARD_KEY; + ctx->default_value = var; + + return NGX_CONF_OK; } - rc = ngx_hash_add_key(&ctx->keys, &value[0], var, flags); + if (value[0].len && value[0].data[0] == '!') { + value[0].len--; + value[0].data++; + } + + rc = ngx_hash_add_key(&ctx->keys, &value[0], var, + (ctx->hostnames) ? NGX_HASH_WILDCARD_KEY : 0); if (rc == NGX_OK) { return NGX_CONF_OK; } + if (rc == NGX_DECLINED) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid hostname or wildcard \"%V\"", &value[0]); + } + if (rc == NGX_BUSY) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "conflicting parameter \"%V\"", &value[0]); diff --git a/src/http/modules/ngx_http_referer_module.c b/src/http/modules/ngx_http_referer_module.c --- a/src/http/modules/ngx_http_referer_module.c +++ b/src/http/modules/ngx_http_referer_module.c @@ -12,8 +12,7 @@ #define NGX_HTTP_REFERER_NO_URI_PART ((void *) 4) typedef struct { - ngx_hash_t hash; - ngx_hash_wildcard_t *dns_wildcards; + ngx_hash_combined_t hash; ngx_flag_t no_referer; ngx_flag_t blocked_referer; @@ -90,7 +89,10 @@ ngx_http_referer_variable(ngx_http_reque rlcf = ngx_http_get_module_loc_conf(r, ngx_http_referer_module); - if (rlcf->hash.buckets == NULL && rlcf->dns_wildcards == NULL) { + if (rlcf->hash.hash.buckets == NULL + && rlcf->hash.wc_head == NULL + && rlcf->hash.wc_tail == NULL) + { goto valid; } @@ -135,18 +137,10 @@ ngx_http_referer_variable(ngx_http_reque len = p - ref; - if (rlcf->hash.buckets) { - uri = ngx_hash_find(&rlcf->hash, key, buf, len); - if (uri) { - goto uri; - } - } + uri = ngx_hash_find_combined(&rlcf->hash, key, buf, len); - if (rlcf->dns_wildcards) { - uri = ngx_hash_find_wildcard(rlcf->dns_wildcards, buf, len); - if (uri) { - goto uri; - } + if (uri) { + goto uri; } invalid: @@ -208,7 +202,6 @@ ngx_http_referer_merge_conf(ngx_conf_t * if (conf->keys == NULL) { conf->hash = prev->hash; - conf->dns_wildcards = prev->dns_wildcards; ngx_conf_merge_value(conf->no_referer, prev->no_referer, 0); ngx_conf_merge_value(conf->blocked_referer, prev->blocked_referer, 0); @@ -217,7 +210,9 @@ ngx_http_referer_merge_conf(ngx_conf_t * } if ((conf->no_referer == 1 || conf->blocked_referer == 1) - && conf->keys->keys.nelts == 0 && conf->keys->dns_wildcards.nelts == 0) + && conf->keys->keys.nelts == 0 + && conf->keys->dns_wc_head.nelts == 0 + && conf->keys->dns_wc_tail.nelts == 0) { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "the \"none\" or \"blocked\" referers are specified " @@ -233,7 +228,7 @@ ngx_http_referer_merge_conf(ngx_conf_t * hash.pool = cf->pool; if (conf->keys->keys.nelts) { - hash.hash = &conf->hash; + hash.hash = &conf->hash.hash; hash.temp_pool = NULL; if (ngx_hash_init(&hash, conf->keys->keys.elts, conf->keys->keys.nelts) @@ -243,24 +238,44 @@ ngx_http_referer_merge_conf(ngx_conf_t * } } - if (conf->keys->dns_wildcards.nelts) { + if (conf->keys->dns_wc_head.nelts) { - ngx_qsort(conf->keys->dns_wildcards.elts, - (size_t) conf->keys->dns_wildcards.nelts, + ngx_qsort(conf->keys->dns_wc_head.elts, + (size_t) conf->keys->dns_wc_head.nelts, sizeof(ngx_hash_key_t), ngx_http_cmp_referer_wildcards); hash.hash = NULL; hash.temp_pool = cf->temp_pool; - if (ngx_hash_wildcard_init(&hash, conf->keys->dns_wildcards.elts, - conf->keys->dns_wildcards.nelts) + if (ngx_hash_wildcard_init(&hash, conf->keys->dns_wc_head.elts, + conf->keys->dns_wc_head.nelts) != NGX_OK) { return NGX_CONF_ERROR; } - conf->dns_wildcards = (ngx_hash_wildcard_t *) hash.hash; + conf->hash.wc_head = (ngx_hash_wildcard_t *) hash.hash; + } + + if (conf->keys->dns_wc_tail.nelts) { + + ngx_qsort(conf->keys->dns_wc_tail.elts, + (size_t) conf->keys->dns_wc_tail.nelts, + sizeof(ngx_hash_key_t), + ngx_http_cmp_referer_wildcards); + + hash.hash = NULL; + hash.temp_pool = cf->temp_pool; + + if (ngx_hash_wildcard_init(&hash, conf->keys->dns_wc_tail.elts, + conf->keys->dns_wc_tail.nelts) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + conf->hash.wc_tail = (ngx_hash_wildcard_t *) hash.hash; } if (conf->no_referer == NGX_CONF_UNSET) { @@ -373,23 +388,8 @@ static char * ngx_http_add_referer(ngx_conf_t *cf, ngx_hash_keys_arrays_t *keys, ngx_str_t *value, ngx_str_t *uri) { - u_char ch; - ngx_int_t rc; - ngx_str_t *u; - ngx_uint_t flags; - - ch = value->data[0]; - - if ((ch == '*' && (value->len < 3 || value->data[1] != '.')) - || (ch == '.' && value->len < 2)) - { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid DNS wildcard \"%V\"", value); - - return NGX_CONF_ERROR; - } - - flags = (ch == '*' || ch == '.') ? NGX_HASH_WILDCARD_KEY : 0; + ngx_int_t rc; + ngx_str_t *u; if (uri->len == 0) { u = NGX_HTTP_REFERER_NO_URI_PART; @@ -403,12 +403,17 @@ ngx_http_add_referer(ngx_conf_t *cf, ngx *u = *uri; } - rc = ngx_hash_add_key(keys, value, u, flags); + rc = ngx_hash_add_key(keys, value, u, NGX_HASH_WILDCARD_KEY); if (rc == NGX_OK) { return NGX_CONF_OK; } + if (rc == NGX_DECLINED) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid hostname or wildcard \"%V\"", value); + } + if (rc == NGX_BUSY) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "conflicting parameter \"%V\"", value); diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm --- a/src/http/modules/perl/nginx.pm +++ b/src/http/modules/perl/nginx.pm @@ -47,7 +47,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '0.5.25'; +our $VERSION = '0.6.0'; require XSLoader; XSLoader::load('nginx', $VERSION); diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -73,7 +73,6 @@ static char * ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *rv; - u_char ch; ngx_int_t rc, j; ngx_uint_t mi, m, s, l, p, a, i, n; ngx_uint_t find_config_index, use_rewrite, use_access; @@ -648,40 +647,20 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma } 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); + 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\" on %s, ignored", + if (rc == NGX_DECLINED) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "invalid server name or wildcard \"%V\" on %s", &name[s].name, in_addr[a].listen_conf->addr); - } - } - - 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; } @@ -709,25 +688,46 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma } } - if (ha.dns_wildcards.nelts) { + if (ha.dns_wc_head.nelts) { - ngx_qsort(ha.dns_wildcards.elts, - (size_t) ha.dns_wildcards.nelts, + ngx_qsort(ha.dns_wc_head.elts, + (size_t) ha.dns_wc_head.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) + if (ngx_hash_wildcard_init(&hash, ha.dns_wc_head.elts, + ha.dns_wc_head.nelts) != NGX_OK) { ngx_destroy_pool(ha.temp_pool); return NGX_CONF_ERROR; } - in_addr[a].dns_wildcards = (ngx_hash_wildcard_t *) hash.hash; + in_addr[a].wc_head = (ngx_hash_wildcard_t *) hash.hash; + } + + if (ha.dns_wc_tail.nelts) { + + ngx_qsort(ha.dns_wc_tail.elts, + (size_t) ha.dns_wc_tail.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_wc_tail.elts, + ha.dns_wc_tail.nelts) + != NGX_OK) + { + ngx_destroy_pool(ha.temp_pool); + return NGX_CONF_ERROR; + } + + in_addr[a].wc_tail = (ngx_hash_wildcard_t *) hash.hash; } ngx_destroy_pool(ha.temp_pool); @@ -848,8 +848,10 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma 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)) + && (in_addr[i].wc_head == NULL + || in_addr[i].wc_head->hash.buckets == NULL) + && (in_addr[i].wc_head == NULL + || in_addr[i].wc_head->hash.buckets == NULL)) { continue; } @@ -861,7 +863,8 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma hip->addrs[i].virtual_names = vn; vn->hash = in_addr[i].hash; - vn->dns_wildcards = in_addr[i].dns_wildcards; + vn->wc_head = in_addr[i].wc_head; + vn->wc_tail = in_addr[i].wc_tail; } if (done) { @@ -934,7 +937,8 @@ ngx_http_add_address(ngx_conf_t *cf, ngx in_addr->addr = lscf->addr; in_addr->hash.buckets = NULL; in_addr->hash.size = 0; - in_addr->dns_wildcards = NULL; + in_addr->wc_head = NULL; + in_addr->wc_tail = NULL; in_addr->names.elts = NULL; in_addr->core_srv_conf = cscf; in_addr->default_server = lscf->conf.default_server; diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -2618,7 +2618,7 @@ ngx_http_core_server_name(ngx_conf_t *cf ch = value[1].data[0]; if (cscf->server_name.data == NULL && value[1].len) { - if (ch == '*') { + if (ngx_strchr(value[1].data, '*')) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "first server name \"%V\" must not be wildcard", &value[1]); diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -173,7 +173,8 @@ typedef struct { in_addr_t addr; ngx_hash_t hash; - ngx_hash_wildcard_t *dns_wildcards; + ngx_hash_wildcard_t *wc_head; + ngx_hash_wildcard_t *wc_tail; ngx_array_t names; /* array of ngx_http_server_name_t */ diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1459,19 +1459,10 @@ ngx_http_find_virtual_server(ngx_http_re vn = r->virtual_names; - if (vn->hash.buckets) { - cscf = ngx_hash_find(&vn->hash, hash, host, len); - if (cscf) { - goto found; - } - } - - if (vn->dns_wildcards && vn->dns_wildcards->hash.buckets) { - cscf = ngx_hash_find_wildcard(vn->dns_wildcards, host, len); - - if (cscf) { - goto found; - } + cscf = ngx_hash_find_combined(vn, hash, host, len); + + if (cscf) { + goto found; } cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -275,10 +275,7 @@ typedef struct { } ngx_http_connection_t; -typedef struct { - ngx_hash_t hash; - ngx_hash_wildcard_t *dns_wildcards; -} ngx_http_virtual_names_t; +typedef ngx_hash_combined_t ngx_http_virtual_names_t; typedef void (*ngx_http_cleanup_pt)(void *data);