sign * in server_name
Igor Sysoev
is at rambler-co.ru
Wed Jun 6 23:22:45 MSD 2007
On Wed, Jun 06, 2007 at 12:53:30PM +0400, Igor Sysoev wrote:
> On Wed, Jun 06, 2007 at 08:50:47AM +0200, Martin Minka wrote:
>
> > There is written in Wiki documentation that it is possible to use * as
> > first part of name in server_name directive.
> > I need to catch all servers directed to my server which name starts with
> > a word.
> >
> > For example will this work ?
> >
> > server {
> > listen 80;
> > server_name main.server.com partner.* affiliate.* ;
> > ......
> >
> > If not, is there another way to achieve this ?
>
> nginx currently does not support such wildcards, but it is relatively easy
> to add them, because their handling is the same as "*.site.com".
The attached patch adds the "www.text.*" wildcards (full tail part only)
to the "server_name", "map", and "valid_referer" directives.
Could you test it ?
--
Igor Sysoev
http://sysoev.ru/en/
-------------- next part --------------
Index: src/http/modules/ngx_http_referer_module.c
===================================================================
--- src/http/modules/ngx_http_referer_module.c (revision 559)
+++ src/http/modules/ngx_http_referer_module.c (working copy)
@@ -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 @@
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 @@
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 @@
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 @@
}
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 @@
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,26 +238,46 @@
}
}
- 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) {
conf->no_referer = 0;
}
@@ -352,7 +367,7 @@
continue;
}
- p = (u_char *) ngx_strstr(value[i].data, "/");
+ p = (u_char *) ngx_strchr(value[i].data, '/');
if (p) {
uri.len = (value[i].data + value[i].len) - p;
@@ -373,24 +388,9 @@
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;
+ ngx_int_t rc;
+ ngx_str_t *u;
- 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;
-
if (uri->len == 0) {
u = NGX_HTTP_REFERER_NO_URI_PART;
@@ -403,12 +403,17 @@
*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);
Index: src/http/modules/ngx_http_map_module.c
===================================================================
--- src/http/modules/ngx_http_map_module.c (revision 562)
+++ src/http/modules/ngx_http_map_module.c (working copy)
@@ -26,8 +26,7 @@
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 @@
key = ngx_hash(key, name[i]);
}
- value = NULL;
+ value = ngx_hash_find_combined(&map->hash, key, name, len);
- if (map->hash.buckets) {
- value = ngx_hash_find(&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 @@
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 @@
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 @@
}
}
- 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_wc_head.elts,
+ (size_t) ctx.keys.dns_wc_head.nelts,
+ sizeof(ngx_hash_key_t), ngx_http_map_cmp_dns_wildcards);
- ngx_qsort(ctx.keys.dns_wildcards.elts,
- (size_t) ctx.keys.dns_wildcards.nelts,
+ hash.hash = NULL;
+ hash.temp_pool = pool;
+
+ 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->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_wildcards.elts,
- ctx.keys.dns_wildcards.nelts)
+ 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->dns_wildcards = (ngx_hash_wildcard_t *) hash.hash;
+ map->hash.wc_tail = (ngx_hash_wildcard_t *) hash.hash;
}
ngx_destroy_pool(pool);
@@ -344,10 +348,9 @@
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 @@
found:
- ch = value[0].data[0];
+ if (ngx_strcmp(value[0].data, "default") == 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;
-
- 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]);
Index: src/http/ngx_http_request.c
===================================================================
--- src/http/ngx_http_request.c (revision 562)
+++ src/http/ngx_http_request.c (working copy)
@@ -1459,19 +1459,10 @@
vn = r->virtual_names;
- if (vn->hash.buckets) {
- cscf = ngx_hash_find(&vn->hash, hash, host, len);
- if (cscf) {
- goto found;
- }
- }
+ cscf = ngx_hash_find_combined(vn, hash, host, len);
- if (vn->dns_wildcards && vn->dns_wildcards->hash.buckets) {
- cscf = ngx_hash_find_wildcard(vn->dns_wildcards, host, len);
-
- if (cscf) {
- goto found;
- }
+ if (cscf) {
+ goto found;
}
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
Index: src/http/ngx_http_core_module.c
===================================================================
--- src/http/ngx_http_core_module.c (revision 562)
+++ src/http/ngx_http_core_module.c (working copy)
@@ -2608,7 +2608,7 @@
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]);
Index: src/http/ngx_http_request.h
===================================================================
--- src/http/ngx_http_request.h (revision 562)
+++ src/http/ngx_http_request.h (working copy)
@@ -275,10 +275,7 @@
} 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);
Index: src/http/ngx_http_core_module.h
===================================================================
--- src/http/ngx_http_core_module.h (revision 562)
+++ src/http/ngx_http_core_module.h (working copy)
@@ -173,7 +173,8 @@
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 */
Index: src/http/ngx_http.c
===================================================================
--- src/http/ngx_http.c (revision 562)
+++ src/http/ngx_http.c (working copy)
@@ -73,7 +73,6 @@
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 @@
}
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,27 +688,48 @@
}
}
- 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 @@
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 @@
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 @@
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;
Index: src/core/ngx_hash.h
===================================================================
--- src/core/ngx_hash.h (revision 559)
+++ src/core/ngx_hash.h (working copy)
@@ -42,6 +42,13 @@
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,24 +80,15 @@
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;
typedef struct {
- void **buckets;
- ngx_uint_t hash_size;
-
- ngx_uint_t max_size;
- ngx_uint_t bucket_limit;
- size_t bucket_size;
- char *name;
- ngx_uint_t min_buckets;
-} ngx_hash0_t;
-
-
-typedef struct {
ngx_uint_t hash;
ngx_str_t key;
ngx_str_t value;
@@ -99,8 +97,10 @@
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);
Index: src/core/ngx_hash.c
===================================================================
--- src/core/ngx_hash.c (revision 562)
+++ src/core/ngx_hash.c (working copy)
@@ -53,7 +53,7 @@
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 @@
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 @@
}
}
- 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 @@
}
+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,24 +642,37 @@
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)
+ {
+ return NGX_ERROR;
+ }
+
ha->keys_hash = ngx_pcalloc(ha->temp_pool, sizeof(ngx_array_t) * ha->hsize);
if (ha->keys_hash == NULL) {
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;
+ }
+
return NGX_OK;
}
@@ -571,141 +682,192 @@
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;
- /* exact hash */
+ if (flags & NGX_HASH_WILDCARD_KEY) {
- k = 0;
+ /*
+ * supported wildcards:
+ * "*.example.com", ".example.com", and "www.example.*"
+ */
+ 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;
+ }
}
- k = ngx_hash(k, key->data[i]);
+
+ if (key->data[i] == '.' && key->data[i + 1] == '.') {
+ return NGX_DECLINED;
+ }
}
- k %= ha->hsize;
+ if (key->len > 1 && key->data[0] == '.') {
+ skip = 1;
+ goto wildcard;
+ }
- /* check conflicts in exact hash */
+ if (key->len > 2) {
- name = ha->keys_hash[k].elts;
+ if (key->data[0] == '*' && key->data[1] == '.') {
+ skip = 2;
+ goto wildcard;
+ }
- if (name) {
- for (i = 0; i < ha->keys_hash[k].nelts; i++) {
- if (key->len != name[i].len) {
- continue;
- }
+ if (key->data[i - 2] == '.' && key->data[i - 1] == '*') {
+ skip = 0;
+ last -= 2;
+ goto wildcard;
+ }
+ }
- if (ngx_strncmp(key->data, name[i].data, key->len) == 0) {
- return NGX_BUSY;
- }
+ 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;
}
- } else {
- if (ngx_array_init(&ha->keys_hash[k], ha->temp_pool, 4,
- sizeof(ngx_str_t))
- != NGX_OK)
- {
- return NGX_ERROR;
+ if (ngx_strncmp(key->data, name[i].data, last) == 0) {
+ return NGX_BUSY;
}
}
- name = ngx_array_push(&ha->keys_hash[k]);
- if (name == NULL) {
+ } else {
+ if (ngx_array_init(&ha->keys_hash[k], ha->temp_pool, 4,
+ sizeof(ngx_str_t))
+ != NGX_OK)
+ {
return NGX_ERROR;
}
+ }
- *name = *key;
+ name = ngx_array_push(&ha->keys_hash[k]);
+ if (name == NULL) {
+ return NGX_ERROR;
+ }
- hk = ngx_array_push(&ha->keys);
- if (hk == NULL) {
- return NGX_ERROR;
- }
+ *name = *key;
- hk->key = *key;
- hk->key_hash = ngx_hash_key(key->data, key->len);
- hk->value = value;
+ hk = ngx_array_push(&ha->keys);
+ if (hk == NULL) {
+ return NGX_ERROR;
+ }
- } else {
+ hk->key = *key;
+ hk->key_hash = ngx_hash_key(key->data, last);
+ hk->value = value;
- /* wildcard hash */
+ return NGX_OK;
- 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]);
- }
+wildcard:
- k %= ha->hsize;
+ /* wildcard hash */
- if (skip == 1) {
+ k = 0;
- /* check conflicts in exact hash for ".example.com" */
+ for (i = skip; i < last; i++) {
+ key->data[i] = ngx_tolower(key->data[i]);
+ k = ngx_hash(k, key->data[i]);
+ }
- name = ha->keys_hash[k].elts;
+ k %= ha->hsize;
- if (name) {
- len = key->len - skip;
+ if (skip == 1) {
- for (i = 0; i < ha->keys_hash[k].nelts; i++) {
- if (len != name[i].len) {
- continue;
- }
+ /* check conflicts in exact hash for ".example.com" */
- if (ngx_strncmp(&key->data[1], name[i].data, len) == 0) {
- return NGX_BUSY;
- }
+ name = ha->keys_hash[k].elts;
+
+ if (name) {
+ len = last - skip;
+
+ for (i = 0; i < ha->keys_hash[k].nelts; i++) {
+ if (len != name[i].len) {
+ continue;
}
- } else {
- if (ngx_array_init(&ha->keys_hash[k], ha->temp_pool, 4,
- sizeof(ngx_str_t))
- != NGX_OK)
- {
- return NGX_ERROR;
+ if (ngx_strncmp(&key->data[1], name[i].data, len) == 0) {
+ return NGX_BUSY;
}
}
- name = ngx_array_push(&ha->keys_hash[k]);
- if (name == NULL) {
+ } else {
+ if (ngx_array_init(&ha->keys_hash[k], ha->temp_pool, 4,
+ sizeof(ngx_str_t))
+ != NGX_OK)
+ {
return NGX_ERROR;
}
+ }
- name->len = key->len - 1;
- name->data = ngx_palloc(ha->temp_pool, name->len);
- if (name->data == NULL) {
- return NGX_ERROR;
- }
+ name = ngx_array_push(&ha->keys_hash[k]);
+ if (name == NULL) {
+ return NGX_ERROR;
+ }
- ngx_memcpy(name->data, &key->data[1], name->len);
+ name->len = last - 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 @@
}
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];
- hk = ngx_array_push(&ha->dns_wildcards);
- if (hk == NULL) {
- return NGX_ERROR;
- }
+ } else {
- hk->key.len = key->len - 1;
- hk->key.data = reverse;
- hk->key_hash = 0;
- hk->value = value;
+ /* convert "www.example.*" to "www.example\0" */
+ p = key->data;
+ key->data[last] = '\0';
+ last++;
- /* check conflicts in wildcard hash */
+ hwc = &ha->dns_wc_tail;
+ keys = &ha->dns_wc_tail_hash[k];
+ }
- name = ha->dns_wildcards_hash[k].elts;
- if (name) {
- len = key->len - skip;
+ hk = ngx_array_push(hwc);
+ if (hk == NULL) {
+ return NGX_ERROR;
+ }
- for (i = 0; i < ha->dns_wildcards_hash[k].nelts; i++) {
- if (len != name[i].len) {
- continue;
- }
+ hk->key.len = last - 1;
+ hk->key.data = p;
+ hk->key_hash = 0;
+ hk->value = value;
- if (ngx_strncmp(key->data + skip, name[i].data, len) == 0) {
- return NGX_BUSY;
- }
+
+ /* check conflicts in wildcard hash */
+
+ name = keys->elts;
+
+ 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;
}
More information about the nginx
mailing list