3 * Copyright (C) Igor Sysoev
7 #include <ngx_config.h>
12 ngx_hash_find(ngx_hash_t
*hash
, ngx_uint_t key
, u_char
*name
, size_t len
)
22 ngx_log_error(NGX_LOG_ALERT
, ngx_cycle
->log
, 0, "hf:\"%V\"", &line
);
25 elt
= hash
->buckets
[key
% hash
->size
];
32 if (len
!= (size_t) elt
->len
) {
36 for (i
= 0; i
< len
; i
++) {
37 if (name
[i
] != elt
->name
[i
]) {
46 elt
= (ngx_hash_elt_t
*) ngx_align_ptr(&elt
->name
[0] + elt
->len
,
56 ngx_hash_find_wc_head(ngx_hash_wildcard_t
*hwc
, u_char
*name
, size_t len
)
66 ngx_log_error(NGX_LOG_ALERT
, ngx_cycle
->log
, 0, "wch:\"%V\"", &line
);
72 if (name
[n
- 1] == '.') {
81 for (i
= n
; i
< len
; i
++) {
82 key
= ngx_hash(key
, name
[i
]);
86 ngx_log_error(NGX_LOG_ALERT
, ngx_cycle
->log
, 0, "key:\"%ui\"", key
);
89 value
= ngx_hash_find(&hwc
->hash
, key
, &name
[n
], len
- n
);
94 * the 2 low bits of value have the special meaning:
95 * 00 - value is data pointer,
96 * 01 - value is pointer to wildcard hash allowing
97 * "*.example.com" only,
98 * 11 - value is pointer to wildcard hash allowing
99 * both "example.com" and "*.example.com".
102 if ((uintptr_t) value
& 1) {
104 hwc
= (ngx_hash_wildcard_t
*) ((uintptr_t) value
& (uintptr_t) ~3);
107 if ((uintptr_t) value
& 2) {
115 value
= ngx_hash_find_wc_head(hwc
, name
, n
- 1);
132 ngx_hash_find_wc_tail(ngx_hash_wildcard_t
*hwc
, u_char
*name
, size_t len
)
142 ngx_log_error(NGX_LOG_ALERT
, ngx_cycle
->log
, 0, "wct:\"%V\"", &line
);
147 for (i
= 0; i
< len
; i
++) {
148 if (name
[i
] == '.') {
152 key
= ngx_hash(key
, name
[i
]);
160 ngx_log_error(NGX_LOG_ALERT
, ngx_cycle
->log
, 0, "key:\"%ui\"", key
);
163 value
= ngx_hash_find(&hwc
->hash
, key
, name
, i
);
168 * the 2 low bits of value have the special meaning:
169 * 00 - value is data pointer,
170 * 01 - value is pointer to wildcard hash allowing "example.*".
173 if ((uintptr_t) value
& 1) {
177 hwc
= (ngx_hash_wildcard_t
*) ((uintptr_t) value
& (uintptr_t) ~3);
179 value
= ngx_hash_find_wc_tail(hwc
, &name
[i
], len
- i
);
196 ngx_hash_find_combined(ngx_hash_combined_t
*hash
, ngx_uint_t key
, u_char
*name
,
201 if (hash
->hash
.buckets
) {
202 value
= ngx_hash_find(&hash
->hash
, key
, name
, len
);
209 if (hash
->wc_head
&& hash
->wc_head
->hash
.buckets
) {
210 value
= ngx_hash_find_wc_head(hash
->wc_head
, name
, len
);
217 if (hash
->wc_tail
&& hash
->wc_tail
->hash
.buckets
) {
218 value
= ngx_hash_find_wc_tail(hash
->wc_tail
, name
, len
);
229 #define NGX_HASH_ELT_SIZE(name) \
230 (sizeof(void *) + ngx_align((name)->key.len + 1, sizeof(void *)))
233 ngx_hash_init(ngx_hash_init_t
*hinit
, ngx_hash_key_t
*names
, ngx_uint_t nelts
)
238 ngx_uint_t i
, n
, key
, size
, start
, bucket_size
;
239 ngx_hash_elt_t
*elt
, **buckets
;
241 for (n
= 0; n
< nelts
; n
++) {
242 if (names
[n
].key
.len
>= 255) {
243 ngx_log_error(NGX_LOG_EMERG
, hinit
->pool
->log
, 0,
244 "the \"%V\" value to hash is to long: %uz bytes, "
245 "the maximum length can be 255 bytes only",
246 &names
[n
].key
, names
[n
].key
.len
);
250 if (hinit
->bucket_size
< NGX_HASH_ELT_SIZE(&names
[n
]) + sizeof(void *))
252 ngx_log_error(NGX_LOG_EMERG
, hinit
->pool
->log
, 0,
253 "could not build the %s, you should "
254 "increase %s_bucket_size: %i",
255 hinit
->name
, hinit
->name
, hinit
->bucket_size
);
260 test
= ngx_alloc(hinit
->max_size
* sizeof(u_short
), hinit
->pool
->log
);
265 bucket_size
= hinit
->bucket_size
- sizeof(void *);
267 start
= nelts
/ (bucket_size
/ (2 * sizeof(void *)));
268 start
= start
? start
: 1;
270 if (hinit
->max_size
> 10000 && hinit
->max_size
/ nelts
< 100) {
271 start
= hinit
->max_size
- 1000;
274 for (size
= start
; size
< hinit
->max_size
; size
++) {
276 ngx_memzero(test
, size
* sizeof(u_short
));
278 for (n
= 0; n
< nelts
; n
++) {
279 if (names
[n
].key
.data
== NULL
) {
283 key
= names
[n
].key_hash
% size
;
284 test
[key
] = (u_short
) (test
[key
] + NGX_HASH_ELT_SIZE(&names
[n
]));
287 ngx_log_error(NGX_LOG_ALERT
, hinit
->pool
->log
, 0,
288 "%ui: %ui %ui \"%V\"",
289 size
, key
, test
[key
], &names
[n
].key
);
292 if (test
[key
] > (u_short
) bucket_size
) {
304 ngx_log_error(NGX_LOG_EMERG
, hinit
->pool
->log
, 0,
305 "could not build the %s, you should increase "
306 "either %s_max_size: %i or %s_bucket_size: %i",
307 hinit
->name
, hinit
->name
, hinit
->max_size
,
308 hinit
->name
, hinit
->bucket_size
);
316 for (i
= 0; i
< size
; i
++) {
317 test
[i
] = sizeof(void *);
320 for (n
= 0; n
< nelts
; n
++) {
321 if (names
[n
].key
.data
== NULL
) {
325 key
= names
[n
].key_hash
% size
;
326 test
[key
] = (u_short
) (test
[key
] + NGX_HASH_ELT_SIZE(&names
[n
]));
331 for (i
= 0; i
< size
; i
++) {
332 if (test
[i
] == sizeof(void *)) {
336 test
[i
] = (u_short
) (ngx_align(test
[i
], ngx_cacheline_size
));
341 if (hinit
->hash
== NULL
) {
342 hinit
->hash
= ngx_pcalloc(hinit
->pool
, sizeof(ngx_hash_wildcard_t
)
343 + size
* sizeof(ngx_hash_elt_t
*));
344 if (hinit
->hash
== NULL
) {
349 buckets
= (ngx_hash_elt_t
**)
350 ((u_char
*) hinit
->hash
+ sizeof(ngx_hash_wildcard_t
));
353 buckets
= ngx_pcalloc(hinit
->pool
, size
* sizeof(ngx_hash_elt_t
*));
354 if (buckets
== NULL
) {
360 elts
= ngx_palloc(hinit
->pool
, len
+ ngx_cacheline_size
);
366 elts
= ngx_align_ptr(elts
, ngx_cacheline_size
);
368 for (i
= 0; i
< size
; i
++) {
369 if (test
[i
] == sizeof(void *)) {
373 buckets
[i
] = (ngx_hash_elt_t
*) elts
;
378 for (i
= 0; i
< size
; i
++) {
382 for (n
= 0; n
< nelts
; n
++) {
383 if (names
[n
].key
.data
== NULL
) {
387 key
= names
[n
].key_hash
% size
;
388 elt
= (ngx_hash_elt_t
*) ((u_char
*) buckets
[key
] + test
[key
]);
390 elt
->value
= names
[n
].value
;
391 elt
->len
= (u_char
) names
[n
].key
.len
;
393 ngx_strlow(elt
->name
, names
[n
].key
.data
, names
[n
].key
.len
);
395 test
[key
] = (u_short
) (test
[key
] + NGX_HASH_ELT_SIZE(&names
[n
]));
398 for (i
= 0; i
< size
; i
++) {
399 if (buckets
[i
] == NULL
) {
403 elt
= (ngx_hash_elt_t
*) ((u_char
*) buckets
[i
] + test
[i
]);
410 hinit
->hash
->buckets
= buckets
;
411 hinit
->hash
->size
= size
;
415 for (i
= 0; i
< size
; i
++) {
422 ngx_log_error(NGX_LOG_ALERT
, hinit
->pool
->log
, 0,
429 val
.data
= &elt
->name
[0];
431 key
= hinit
->key(val
.data
, val
.len
);
433 ngx_log_error(NGX_LOG_ALERT
, hinit
->pool
->log
, 0,
434 "%ui: %p \"%V\" %ui", i
, elt
, &val
, key
);
436 elt
= (ngx_hash_elt_t
*) ngx_align_ptr(&elt
->name
[0] + elt
->len
,
448 ngx_hash_wildcard_init(ngx_hash_init_t
*hinit
, ngx_hash_key_t
*names
,
452 ngx_uint_t i
, n
, dot
;
453 ngx_array_t curr_names
, next_names
;
454 ngx_hash_key_t
*name
, *next_name
;
456 ngx_hash_wildcard_t
*wdc
;
458 if (ngx_array_init(&curr_names
, hinit
->temp_pool
, nelts
,
459 sizeof(ngx_hash_key_t
))
465 if (ngx_array_init(&next_names
, hinit
->temp_pool
, nelts
,
466 sizeof(ngx_hash_key_t
))
472 for (n
= 0; n
< nelts
; n
= i
) {
475 ngx_log_error(NGX_LOG_ALERT
, hinit
->pool
->log
, 0,
476 "wc0: \"%V\"", &names
[n
].key
);
481 for (len
= 0; len
< names
[n
].key
.len
; len
++) {
482 if (names
[n
].key
.data
[len
] == '.') {
488 name
= ngx_array_push(&curr_names
);
494 name
->key
.data
= names
[n
].key
.data
;
495 name
->key_hash
= hinit
->key(name
->key
.data
, name
->key
.len
);
496 name
->value
= names
[n
].value
;
499 ngx_log_error(NGX_LOG_ALERT
, hinit
->pool
->log
, 0,
500 "wc1: \"%V\" %ui", &name
->key
, dot
);
509 next_names
.nelts
= 0;
511 if (names
[n
].key
.len
!= len
) {
512 next_name
= ngx_array_push(&next_names
);
513 if (next_name
== NULL
) {
517 next_name
->key
.len
= names
[n
].key
.len
- len
;
518 next_name
->key
.data
= names
[n
].key
.data
+ len
;
519 next_name
->key_hash
= 0;
520 next_name
->value
= names
[n
].value
;
523 ngx_log_error(NGX_LOG_ALERT
, hinit
->pool
->log
, 0,
524 "wc2: \"%V\"", &next_name
->key
);
528 for (i
= n
+ 1; i
< nelts
; i
++) {
529 if (ngx_strncmp(names
[n
].key
.data
, names
[i
].key
.data
, len
) != 0) {
534 && names
[i
].key
.len
> len
535 && names
[i
].key
.data
[len
] != '.')
540 next_name
= ngx_array_push(&next_names
);
541 if (next_name
== NULL
) {
545 next_name
->key
.len
= names
[i
].key
.len
- dot_len
;
546 next_name
->key
.data
= names
[i
].key
.data
+ dot_len
;
547 next_name
->key_hash
= 0;
548 next_name
->value
= names
[i
].value
;
551 ngx_log_error(NGX_LOG_ALERT
, hinit
->pool
->log
, 0,
552 "wc3: \"%V\"", &next_name
->key
);
556 if (next_names
.nelts
) {
561 if (ngx_hash_wildcard_init(&h
, (ngx_hash_key_t
*) next_names
.elts
,
568 wdc
= (ngx_hash_wildcard_t
*) h
.hash
;
570 if (names
[n
].key
.len
== len
) {
571 wdc
->value
= names
[n
].value
;
573 ngx_log_error(NGX_LOG_ALERT
, hinit
->pool
->log
, 0,
574 "wdc: \"%V\"", wdc
->value
);
578 name
->value
= (void *) ((uintptr_t) wdc
| (dot
? 1 : 3));
582 if (ngx_hash_init(hinit
, (ngx_hash_key_t
*) curr_names
.elts
,
594 ngx_hash_key(u_char
*data
, size_t len
)
600 for (i
= 0; i
< len
; i
++) {
601 key
= ngx_hash(key
, data
[i
]);
609 ngx_hash_key_lc(u_char
*data
, size_t len
)
615 for (i
= 0; i
< len
; i
++) {
616 key
= ngx_hash(key
, ngx_tolower(data
[i
]));
624 ngx_hash_strlow(u_char
*dst
, u_char
*src
, size_t n
)
631 *dst
= ngx_tolower(*src
);
632 key
= ngx_hash(key
, *dst
);
642 ngx_hash_keys_array_init(ngx_hash_keys_arrays_t
*ha
, ngx_uint_t type
)
646 if (type
== NGX_HASH_SMALL
) {
651 asize
= NGX_HASH_LARGE_ASIZE
;
652 ha
->hsize
= NGX_HASH_LARGE_HSIZE
;
655 if (ngx_array_init(&ha
->keys
, ha
->temp_pool
, asize
, sizeof(ngx_hash_key_t
))
661 if (ngx_array_init(&ha
->dns_wc_head
, ha
->temp_pool
, asize
,
662 sizeof(ngx_hash_key_t
))
668 if (ngx_array_init(&ha
->dns_wc_tail
, ha
->temp_pool
, asize
,
669 sizeof(ngx_hash_key_t
))
675 ha
->keys_hash
= ngx_pcalloc(ha
->temp_pool
, sizeof(ngx_array_t
) * ha
->hsize
);
676 if (ha
->keys_hash
== NULL
) {
680 ha
->dns_wc_head_hash
= ngx_pcalloc(ha
->temp_pool
,
681 sizeof(ngx_array_t
) * ha
->hsize
);
682 if (ha
->dns_wc_head_hash
== NULL
) {
686 ha
->dns_wc_tail_hash
= ngx_pcalloc(ha
->temp_pool
,
687 sizeof(ngx_array_t
) * ha
->hsize
);
688 if (ha
->dns_wc_tail_hash
== NULL
) {
697 ngx_hash_add_key(ngx_hash_keys_arrays_t
*ha
, ngx_str_t
*key
, void *value
,
703 ngx_uint_t i
, k
, n
, skip
, last
;
704 ngx_array_t
*keys
, *hwc
;
709 if (flags
& NGX_HASH_WILDCARD_KEY
) {
712 * supported wildcards:
713 * "*.example.com", ".example.com", and "www.example.*"
718 for (i
= 0; i
< key
->len
; i
++) {
720 if (key
->data
[i
] == '*') {
726 if (key
->data
[i
] == '.' && key
->data
[i
+ 1] == '.') {
731 if (key
->len
> 1 && key
->data
[0] == '.') {
738 if (key
->data
[0] == '*' && key
->data
[1] == '.') {
743 if (key
->data
[i
- 2] == '.' && key
->data
[i
- 1] == '*') {
759 for (i
= 0; i
< last
; i
++) {
760 if (!(flags
& NGX_HASH_READONLY_KEY
)) {
761 key
->data
[i
] = ngx_tolower(key
->data
[i
]);
763 k
= ngx_hash(k
, key
->data
[i
]);
768 /* check conflicts in exact hash */
770 name
= ha
->keys_hash
[k
].elts
;
773 for (i
= 0; i
< ha
->keys_hash
[k
].nelts
; i
++) {
774 if (last
!= name
[i
].len
) {
778 if (ngx_strncmp(key
->data
, name
[i
].data
, last
) == 0) {
784 if (ngx_array_init(&ha
->keys_hash
[k
], ha
->temp_pool
, 4,
792 name
= ngx_array_push(&ha
->keys_hash
[k
]);
799 hk
= ngx_array_push(&ha
->keys
);
805 hk
->key_hash
= ngx_hash_key(key
->data
, last
);
815 k
= ngx_hash_strlow(&key
->data
[skip
], &key
->data
[skip
], last
- skip
);
821 /* check conflicts in exact hash for ".example.com" */
823 name
= ha
->keys_hash
[k
].elts
;
828 for (i
= 0; i
< ha
->keys_hash
[k
].nelts
; i
++) {
829 if (len
!= name
[i
].len
) {
833 if (ngx_strncmp(&key
->data
[1], name
[i
].data
, len
) == 0) {
839 if (ngx_array_init(&ha
->keys_hash
[k
], ha
->temp_pool
, 4,
847 name
= ngx_array_push(&ha
->keys_hash
[k
]);
852 name
->len
= last
- 1;
853 name
->data
= ngx_pnalloc(ha
->temp_pool
, name
->len
);
854 if (name
->data
== NULL
) {
858 ngx_memcpy(name
->data
, &key
->data
[1], name
->len
);
865 * convert "*.example.com" to "com.example.\0"
866 * and ".example.com" to "com.example\0"
869 p
= ngx_pnalloc(ha
->temp_pool
, last
);
877 for (i
= last
- 1; i
; i
--) {
878 if (key
->data
[i
] == '.') {
879 ngx_memcpy(&p
[n
], &key
->data
[i
+ 1], len
);
890 ngx_memcpy(&p
[n
], &key
->data
[1], len
);
896 hwc
= &ha
->dns_wc_head
;
897 keys
= &ha
->dns_wc_head_hash
[k
];
901 /* convert "www.example.*" to "www.example\0" */
905 p
= ngx_pnalloc(ha
->temp_pool
, last
);
910 ngx_cpystrn(p
, key
->data
, last
);
912 hwc
= &ha
->dns_wc_tail
;
913 keys
= &ha
->dns_wc_tail_hash
[k
];
917 hk
= ngx_array_push(hwc
);
922 hk
->key
.len
= last
- 1;
928 /* check conflicts in wildcard hash */
935 for (i
= 0; i
< keys
->nelts
; i
++) {
936 if (len
!= name
[i
].len
) {
940 if (ngx_strncmp(key
->data
+ skip
, name
[i
].data
, len
) == 0) {
946 if (ngx_array_init(keys
, ha
->temp_pool
, 4, sizeof(ngx_str_t
)) != NGX_OK
)
952 name
= ngx_array_push(keys
);
957 name
->len
= last
- skip
;
958 name
->data
= ngx_pnalloc(ha
->temp_pool
, name
->len
);
959 if (name
->data
== NULL
) {
963 ngx_memcpy(name
->data
, key
->data
+ skip
, name
->len
);