3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
8 #include <ngx_config.h>
13 ngx_hash_find(ngx_hash_t
*hash
, ngx_uint_t key
, u_char
*name
, size_t len
)
19 ngx_log_error(NGX_LOG_ALERT
, ngx_cycle
->log
, 0, "hf:\"%*s\"", len
, name
);
22 elt
= hash
->buckets
[key
% hash
->size
];
29 if (len
!= (size_t) elt
->len
) {
33 for (i
= 0; i
< len
; i
++) {
34 if (name
[i
] != elt
->name
[i
]) {
43 elt
= (ngx_hash_elt_t
*) ngx_align_ptr(&elt
->name
[0] + elt
->len
,
53 ngx_hash_find_wc_head(ngx_hash_wildcard_t
*hwc
, u_char
*name
, size_t len
)
59 ngx_log_error(NGX_LOG_ALERT
, ngx_cycle
->log
, 0, "wch:\"%*s\"", len
, name
);
65 if (name
[n
- 1] == '.') {
74 for (i
= n
; i
< len
; i
++) {
75 key
= ngx_hash(key
, name
[i
]);
79 ngx_log_error(NGX_LOG_ALERT
, ngx_cycle
->log
, 0, "key:\"%ui\"", key
);
82 value
= ngx_hash_find(&hwc
->hash
, key
, &name
[n
], len
- n
);
85 ngx_log_error(NGX_LOG_ALERT
, ngx_cycle
->log
, 0, "value:\"%p\"", value
);
91 * the 2 low bits of value have the special meaning:
92 * 00 - value is data pointer for both "example.com"
93 * and "*.example.com";
94 * 01 - value is data pointer for "*.example.com" only;
95 * 10 - value is pointer to wildcard hash allowing
96 * both "example.com" and "*.example.com";
97 * 11 - value is pointer to wildcard hash allowing
98 * "*.example.com" only.
101 if ((uintptr_t) value
& 2) {
107 if ((uintptr_t) value
& 1) {
111 hwc
= (ngx_hash_wildcard_t
*)
112 ((uintptr_t) value
& (uintptr_t) ~3);
116 hwc
= (ngx_hash_wildcard_t
*) ((uintptr_t) value
& (uintptr_t) ~3);
118 value
= ngx_hash_find_wc_head(hwc
, name
, n
- 1);
127 if ((uintptr_t) value
& 1) {
136 return (void *) ((uintptr_t) value
& (uintptr_t) ~3);
147 ngx_hash_find_wc_tail(ngx_hash_wildcard_t
*hwc
, u_char
*name
, size_t len
)
153 ngx_log_error(NGX_LOG_ALERT
, ngx_cycle
->log
, 0, "wct:\"%*s\"", len
, name
);
158 for (i
= 0; i
< len
; i
++) {
159 if (name
[i
] == '.') {
163 key
= ngx_hash(key
, name
[i
]);
171 ngx_log_error(NGX_LOG_ALERT
, ngx_cycle
->log
, 0, "key:\"%ui\"", key
);
174 value
= ngx_hash_find(&hwc
->hash
, key
, name
, i
);
177 ngx_log_error(NGX_LOG_ALERT
, ngx_cycle
->log
, 0, "value:\"%p\"", value
);
183 * the 2 low bits of value have the special meaning:
184 * 00 - value is data pointer;
185 * 11 - value is pointer to wildcard hash allowing "example.*".
188 if ((uintptr_t) value
& 2) {
192 hwc
= (ngx_hash_wildcard_t
*) ((uintptr_t) value
& (uintptr_t) ~3);
194 value
= ngx_hash_find_wc_tail(hwc
, &name
[i
], len
- i
);
211 ngx_hash_find_combined(ngx_hash_combined_t
*hash
, ngx_uint_t key
, u_char
*name
,
216 if (hash
->hash
.buckets
) {
217 value
= ngx_hash_find(&hash
->hash
, key
, name
, len
);
228 if (hash
->wc_head
&& hash
->wc_head
->hash
.buckets
) {
229 value
= ngx_hash_find_wc_head(hash
->wc_head
, name
, len
);
236 if (hash
->wc_tail
&& hash
->wc_tail
->hash
.buckets
) {
237 value
= ngx_hash_find_wc_tail(hash
->wc_tail
, name
, len
);
248 #define NGX_HASH_ELT_SIZE(name) \
249 (sizeof(void *) + ngx_align((name)->key.len + 2, sizeof(void *)))
252 ngx_hash_init(ngx_hash_init_t
*hinit
, ngx_hash_key_t
*names
, ngx_uint_t nelts
)
257 ngx_uint_t i
, n
, key
, size
, start
, bucket_size
;
258 ngx_hash_elt_t
*elt
, **buckets
;
260 for (n
= 0; n
< nelts
; n
++) {
261 if (hinit
->bucket_size
< NGX_HASH_ELT_SIZE(&names
[n
]) + sizeof(void *))
263 ngx_log_error(NGX_LOG_EMERG
, hinit
->pool
->log
, 0,
264 "could not build the %s, you should "
265 "increase %s_bucket_size: %i",
266 hinit
->name
, hinit
->name
, hinit
->bucket_size
);
271 test
= ngx_alloc(hinit
->max_size
* sizeof(u_short
), hinit
->pool
->log
);
276 bucket_size
= hinit
->bucket_size
- sizeof(void *);
278 start
= nelts
/ (bucket_size
/ (2 * sizeof(void *)));
279 start
= start
? start
: 1;
281 if (hinit
->max_size
> 10000 && nelts
&& hinit
->max_size
/ nelts
< 100) {
282 start
= hinit
->max_size
- 1000;
285 for (size
= start
; size
< hinit
->max_size
; size
++) {
287 ngx_memzero(test
, size
* sizeof(u_short
));
289 for (n
= 0; n
< nelts
; n
++) {
290 if (names
[n
].key
.data
== NULL
) {
294 key
= names
[n
].key_hash
% size
;
295 test
[key
] = (u_short
) (test
[key
] + NGX_HASH_ELT_SIZE(&names
[n
]));
298 ngx_log_error(NGX_LOG_ALERT
, hinit
->pool
->log
, 0,
299 "%ui: %ui %ui \"%V\"",
300 size
, key
, test
[key
], &names
[n
].key
);
303 if (test
[key
] > (u_short
) bucket_size
) {
315 ngx_log_error(NGX_LOG_EMERG
, hinit
->pool
->log
, 0,
316 "could not build the %s, you should increase "
317 "either %s_max_size: %i or %s_bucket_size: %i",
318 hinit
->name
, hinit
->name
, hinit
->max_size
,
319 hinit
->name
, hinit
->bucket_size
);
327 for (i
= 0; i
< size
; i
++) {
328 test
[i
] = sizeof(void *);
331 for (n
= 0; n
< nelts
; n
++) {
332 if (names
[n
].key
.data
== NULL
) {
336 key
= names
[n
].key_hash
% size
;
337 test
[key
] = (u_short
) (test
[key
] + NGX_HASH_ELT_SIZE(&names
[n
]));
342 for (i
= 0; i
< size
; i
++) {
343 if (test
[i
] == sizeof(void *)) {
347 test
[i
] = (u_short
) (ngx_align(test
[i
], ngx_cacheline_size
));
352 if (hinit
->hash
== NULL
) {
353 hinit
->hash
= ngx_pcalloc(hinit
->pool
, sizeof(ngx_hash_wildcard_t
)
354 + size
* sizeof(ngx_hash_elt_t
*));
355 if (hinit
->hash
== NULL
) {
360 buckets
= (ngx_hash_elt_t
**)
361 ((u_char
*) hinit
->hash
+ sizeof(ngx_hash_wildcard_t
));
364 buckets
= ngx_pcalloc(hinit
->pool
, size
* sizeof(ngx_hash_elt_t
*));
365 if (buckets
== NULL
) {
371 elts
= ngx_palloc(hinit
->pool
, len
+ ngx_cacheline_size
);
377 elts
= ngx_align_ptr(elts
, ngx_cacheline_size
);
379 for (i
= 0; i
< size
; i
++) {
380 if (test
[i
] == sizeof(void *)) {
384 buckets
[i
] = (ngx_hash_elt_t
*) elts
;
389 for (i
= 0; i
< size
; i
++) {
393 for (n
= 0; n
< nelts
; n
++) {
394 if (names
[n
].key
.data
== NULL
) {
398 key
= names
[n
].key_hash
% size
;
399 elt
= (ngx_hash_elt_t
*) ((u_char
*) buckets
[key
] + test
[key
]);
401 elt
->value
= names
[n
].value
;
402 elt
->len
= (u_short
) names
[n
].key
.len
;
404 ngx_strlow(elt
->name
, names
[n
].key
.data
, names
[n
].key
.len
);
406 test
[key
] = (u_short
) (test
[key
] + NGX_HASH_ELT_SIZE(&names
[n
]));
409 for (i
= 0; i
< size
; i
++) {
410 if (buckets
[i
] == NULL
) {
414 elt
= (ngx_hash_elt_t
*) ((u_char
*) buckets
[i
] + test
[i
]);
421 hinit
->hash
->buckets
= buckets
;
422 hinit
->hash
->size
= size
;
426 for (i
= 0; i
< size
; i
++) {
433 ngx_log_error(NGX_LOG_ALERT
, hinit
->pool
->log
, 0,
440 val
.data
= &elt
->name
[0];
442 key
= hinit
->key(val
.data
, val
.len
);
444 ngx_log_error(NGX_LOG_ALERT
, hinit
->pool
->log
, 0,
445 "%ui: %p \"%V\" %ui", i
, elt
, &val
, key
);
447 elt
= (ngx_hash_elt_t
*) ngx_align_ptr(&elt
->name
[0] + elt
->len
,
459 ngx_hash_wildcard_init(ngx_hash_init_t
*hinit
, ngx_hash_key_t
*names
,
463 ngx_uint_t i
, n
, dot
;
464 ngx_array_t curr_names
, next_names
;
465 ngx_hash_key_t
*name
, *next_name
;
467 ngx_hash_wildcard_t
*wdc
;
469 if (ngx_array_init(&curr_names
, hinit
->temp_pool
, nelts
,
470 sizeof(ngx_hash_key_t
))
476 if (ngx_array_init(&next_names
, hinit
->temp_pool
, nelts
,
477 sizeof(ngx_hash_key_t
))
483 for (n
= 0; n
< nelts
; n
= i
) {
486 ngx_log_error(NGX_LOG_ALERT
, hinit
->pool
->log
, 0,
487 "wc0: \"%V\"", &names
[n
].key
);
492 for (len
= 0; len
< names
[n
].key
.len
; len
++) {
493 if (names
[n
].key
.data
[len
] == '.') {
499 name
= ngx_array_push(&curr_names
);
505 name
->key
.data
= names
[n
].key
.data
;
506 name
->key_hash
= hinit
->key(name
->key
.data
, name
->key
.len
);
507 name
->value
= names
[n
].value
;
510 ngx_log_error(NGX_LOG_ALERT
, hinit
->pool
->log
, 0,
511 "wc1: \"%V\" %ui", &name
->key
, dot
);
520 next_names
.nelts
= 0;
522 if (names
[n
].key
.len
!= len
) {
523 next_name
= ngx_array_push(&next_names
);
524 if (next_name
== NULL
) {
528 next_name
->key
.len
= names
[n
].key
.len
- len
;
529 next_name
->key
.data
= names
[n
].key
.data
+ len
;
530 next_name
->key_hash
= 0;
531 next_name
->value
= names
[n
].value
;
534 ngx_log_error(NGX_LOG_ALERT
, hinit
->pool
->log
, 0,
535 "wc2: \"%V\"", &next_name
->key
);
539 for (i
= n
+ 1; i
< nelts
; i
++) {
540 if (ngx_strncmp(names
[n
].key
.data
, names
[i
].key
.data
, len
) != 0) {
545 && names
[i
].key
.len
> len
546 && names
[i
].key
.data
[len
] != '.')
551 next_name
= ngx_array_push(&next_names
);
552 if (next_name
== NULL
) {
556 next_name
->key
.len
= names
[i
].key
.len
- dot_len
;
557 next_name
->key
.data
= names
[i
].key
.data
+ dot_len
;
558 next_name
->key_hash
= 0;
559 next_name
->value
= names
[i
].value
;
562 ngx_log_error(NGX_LOG_ALERT
, hinit
->pool
->log
, 0,
563 "wc3: \"%V\"", &next_name
->key
);
567 if (next_names
.nelts
) {
572 if (ngx_hash_wildcard_init(&h
, (ngx_hash_key_t
*) next_names
.elts
,
579 wdc
= (ngx_hash_wildcard_t
*) h
.hash
;
581 if (names
[n
].key
.len
== len
) {
582 wdc
->value
= names
[n
].value
;
585 name
->value
= (void *) ((uintptr_t) wdc
| (dot
? 3 : 2));
588 name
->value
= (void *) ((uintptr_t) name
->value
| 1);
592 if (ngx_hash_init(hinit
, (ngx_hash_key_t
*) curr_names
.elts
,
604 ngx_hash_key(u_char
*data
, size_t len
)
610 for (i
= 0; i
< len
; i
++) {
611 key
= ngx_hash(key
, data
[i
]);
619 ngx_hash_key_lc(u_char
*data
, size_t len
)
625 for (i
= 0; i
< len
; i
++) {
626 key
= ngx_hash(key
, ngx_tolower(data
[i
]));
634 ngx_hash_strlow(u_char
*dst
, u_char
*src
, size_t n
)
641 *dst
= ngx_tolower(*src
);
642 key
= ngx_hash(key
, *dst
);
652 ngx_hash_keys_array_init(ngx_hash_keys_arrays_t
*ha
, ngx_uint_t type
)
656 if (type
== NGX_HASH_SMALL
) {
661 asize
= NGX_HASH_LARGE_ASIZE
;
662 ha
->hsize
= NGX_HASH_LARGE_HSIZE
;
665 if (ngx_array_init(&ha
->keys
, ha
->temp_pool
, asize
, sizeof(ngx_hash_key_t
))
671 if (ngx_array_init(&ha
->dns_wc_head
, ha
->temp_pool
, asize
,
672 sizeof(ngx_hash_key_t
))
678 if (ngx_array_init(&ha
->dns_wc_tail
, ha
->temp_pool
, asize
,
679 sizeof(ngx_hash_key_t
))
685 ha
->keys_hash
= ngx_pcalloc(ha
->temp_pool
, sizeof(ngx_array_t
) * ha
->hsize
);
686 if (ha
->keys_hash
== NULL
) {
690 ha
->dns_wc_head_hash
= ngx_pcalloc(ha
->temp_pool
,
691 sizeof(ngx_array_t
) * ha
->hsize
);
692 if (ha
->dns_wc_head_hash
== NULL
) {
696 ha
->dns_wc_tail_hash
= ngx_pcalloc(ha
->temp_pool
,
697 sizeof(ngx_array_t
) * ha
->hsize
);
698 if (ha
->dns_wc_tail_hash
== NULL
) {
707 ngx_hash_add_key(ngx_hash_keys_arrays_t
*ha
, ngx_str_t
*key
, void *value
,
713 ngx_uint_t i
, k
, n
, skip
, last
;
714 ngx_array_t
*keys
, *hwc
;
719 if (flags
& NGX_HASH_WILDCARD_KEY
) {
722 * supported wildcards:
723 * "*.example.com", ".example.com", and "www.example.*"
728 for (i
= 0; i
< key
->len
; i
++) {
730 if (key
->data
[i
] == '*') {
736 if (key
->data
[i
] == '.' && key
->data
[i
+ 1] == '.') {
741 if (key
->len
> 1 && key
->data
[0] == '.') {
748 if (key
->data
[0] == '*' && key
->data
[1] == '.') {
753 if (key
->data
[i
- 2] == '.' && key
->data
[i
- 1] == '*') {
769 for (i
= 0; i
< last
; i
++) {
770 if (!(flags
& NGX_HASH_READONLY_KEY
)) {
771 key
->data
[i
] = ngx_tolower(key
->data
[i
]);
773 k
= ngx_hash(k
, key
->data
[i
]);
778 /* check conflicts in exact hash */
780 name
= ha
->keys_hash
[k
].elts
;
783 for (i
= 0; i
< ha
->keys_hash
[k
].nelts
; i
++) {
784 if (last
!= name
[i
].len
) {
788 if (ngx_strncmp(key
->data
, name
[i
].data
, last
) == 0) {
794 if (ngx_array_init(&ha
->keys_hash
[k
], ha
->temp_pool
, 4,
802 name
= ngx_array_push(&ha
->keys_hash
[k
]);
809 hk
= ngx_array_push(&ha
->keys
);
815 hk
->key_hash
= ngx_hash_key(key
->data
, last
);
825 k
= ngx_hash_strlow(&key
->data
[skip
], &key
->data
[skip
], last
- skip
);
831 /* check conflicts in exact hash for ".example.com" */
833 name
= ha
->keys_hash
[k
].elts
;
838 for (i
= 0; i
< ha
->keys_hash
[k
].nelts
; i
++) {
839 if (len
!= name
[i
].len
) {
843 if (ngx_strncmp(&key
->data
[1], name
[i
].data
, len
) == 0) {
849 if (ngx_array_init(&ha
->keys_hash
[k
], ha
->temp_pool
, 4,
857 name
= ngx_array_push(&ha
->keys_hash
[k
]);
862 name
->len
= last
- 1;
863 name
->data
= ngx_pnalloc(ha
->temp_pool
, name
->len
);
864 if (name
->data
== NULL
) {
868 ngx_memcpy(name
->data
, &key
->data
[1], name
->len
);
875 * convert "*.example.com" to "com.example.\0"
876 * and ".example.com" to "com.example\0"
879 p
= ngx_pnalloc(ha
->temp_pool
, last
);
887 for (i
= last
- 1; i
; i
--) {
888 if (key
->data
[i
] == '.') {
889 ngx_memcpy(&p
[n
], &key
->data
[i
+ 1], len
);
900 ngx_memcpy(&p
[n
], &key
->data
[1], len
);
906 hwc
= &ha
->dns_wc_head
;
907 keys
= &ha
->dns_wc_head_hash
[k
];
911 /* convert "www.example.*" to "www.example\0" */
915 p
= ngx_pnalloc(ha
->temp_pool
, last
);
920 ngx_cpystrn(p
, key
->data
, last
);
922 hwc
= &ha
->dns_wc_tail
;
923 keys
= &ha
->dns_wc_tail_hash
[k
];
927 /* check conflicts in wildcard hash */
934 for (i
= 0; i
< keys
->nelts
; i
++) {
935 if (len
!= name
[i
].len
) {
939 if (ngx_strncmp(key
->data
+ skip
, name
[i
].data
, len
) == 0) {
945 if (ngx_array_init(keys
, ha
->temp_pool
, 4, sizeof(ngx_str_t
)) != NGX_OK
)
951 name
= ngx_array_push(keys
);
956 name
->len
= last
- skip
;
957 name
->data
= ngx_pnalloc(ha
->temp_pool
, name
->len
);
958 if (name
->data
== NULL
) {
962 ngx_memcpy(name
->data
, key
->data
+ skip
, name
->len
);
965 /* add to wildcard hash */
967 hk
= ngx_array_push(hwc
);
972 hk
->key
.len
= last
- 1;