Annotation of embedaddon/nginx/src/core/ngx_hash.c, revision 1.1.1.1

1.1       misho       1: 
                      2: /*
                      3:  * Copyright (C) Igor Sysoev
                      4:  * Copyright (C) Nginx, Inc.
                      5:  */
                      6: 
                      7: 
                      8: #include <ngx_config.h>
                      9: #include <ngx_core.h>
                     10: 
                     11: 
                     12: void *
                     13: ngx_hash_find(ngx_hash_t *hash, ngx_uint_t key, u_char *name, size_t len)
                     14: {
                     15:     ngx_uint_t       i;
                     16:     ngx_hash_elt_t  *elt;
                     17: 
                     18: #if 0
                     19:     ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "hf:\"%*s\"", len, name);
                     20: #endif
                     21: 
                     22:     elt = hash->buckets[key % hash->size];
                     23: 
                     24:     if (elt == NULL) {
                     25:         return NULL;
                     26:     }
                     27: 
                     28:     while (elt->value) {
                     29:         if (len != (size_t) elt->len) {
                     30:             goto next;
                     31:         }
                     32: 
                     33:         for (i = 0; i < len; i++) {
                     34:             if (name[i] != elt->name[i]) {
                     35:                 goto next;
                     36:             }
                     37:         }
                     38: 
                     39:         return elt->value;
                     40: 
                     41:     next:
                     42: 
                     43:         elt = (ngx_hash_elt_t *) ngx_align_ptr(&elt->name[0] + elt->len,
                     44:                                                sizeof(void *));
                     45:         continue;
                     46:     }
                     47: 
                     48:     return NULL;
                     49: }
                     50: 
                     51: 
                     52: void *
                     53: ngx_hash_find_wc_head(ngx_hash_wildcard_t *hwc, u_char *name, size_t len)
                     54: {
                     55:     void        *value;
                     56:     ngx_uint_t   i, n, key;
                     57: 
                     58: #if 0
                     59:     ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "wch:\"%*s\"", len, name);
                     60: #endif
                     61: 
                     62:     n = len;
                     63: 
                     64:     while (n) {
                     65:         if (name[n - 1] == '.') {
                     66:             break;
                     67:         }
                     68: 
                     69:         n--;
                     70:     }
                     71: 
                     72:     key = 0;
                     73: 
                     74:     for (i = n; i < len; i++) {
                     75:         key = ngx_hash(key, name[i]);
                     76:     }
                     77: 
                     78: #if 0
                     79:     ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "key:\"%ui\"", key);
                     80: #endif
                     81: 
                     82:     value = ngx_hash_find(&hwc->hash, key, &name[n], len - n);
                     83: 
                     84: #if 0
                     85:     ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "value:\"%p\"", value);
                     86: #endif
                     87: 
                     88:     if (value) {
                     89: 
                     90:         /*
                     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.
                     99:          */
                    100: 
                    101:         if ((uintptr_t) value & 2) {
                    102: 
                    103:             if (n == 0) {
                    104: 
                    105:                 /* "example.com" */
                    106: 
                    107:                 if ((uintptr_t) value & 1) {
                    108:                     return NULL;
                    109:                 }
                    110: 
                    111:                 hwc = (ngx_hash_wildcard_t *)
                    112:                                           ((uintptr_t) value & (uintptr_t) ~3);
                    113:                 return hwc->value;
                    114:             }
                    115: 
                    116:             hwc = (ngx_hash_wildcard_t *) ((uintptr_t) value & (uintptr_t) ~3);
                    117: 
                    118:             value = ngx_hash_find_wc_head(hwc, name, n - 1);
                    119: 
                    120:             if (value) {
                    121:                 return value;
                    122:             }
                    123: 
                    124:             return hwc->value;
                    125:         }
                    126: 
                    127:         if ((uintptr_t) value & 1) {
                    128: 
                    129:             if (n == 0) {
                    130: 
                    131:                 /* "example.com" */
                    132: 
                    133:                 return NULL;
                    134:             }
                    135: 
                    136:             return (void *) ((uintptr_t) value & (uintptr_t) ~3);
                    137:         }
                    138: 
                    139:         return value;
                    140:     }
                    141: 
                    142:     return hwc->value;
                    143: }
                    144: 
                    145: 
                    146: void *
                    147: ngx_hash_find_wc_tail(ngx_hash_wildcard_t *hwc, u_char *name, size_t len)
                    148: {
                    149:     void        *value;
                    150:     ngx_uint_t   i, key;
                    151: 
                    152: #if 0
                    153:     ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "wct:\"%*s\"", len, name);
                    154: #endif
                    155: 
                    156:     key = 0;
                    157: 
                    158:     for (i = 0; i < len; i++) {
                    159:         if (name[i] == '.') {
                    160:             break;
                    161:         }
                    162: 
                    163:         key = ngx_hash(key, name[i]);
                    164:     }
                    165: 
                    166:     if (i == len) {
                    167:         return NULL;
                    168:     }
                    169: 
                    170: #if 0
                    171:     ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "key:\"%ui\"", key);
                    172: #endif
                    173: 
                    174:     value = ngx_hash_find(&hwc->hash, key, name, i);
                    175: 
                    176: #if 0
                    177:     ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "value:\"%p\"", value);
                    178: #endif
                    179: 
                    180:     if (value) {
                    181: 
                    182:         /*
                    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.*".
                    186:          */
                    187: 
                    188:         if ((uintptr_t) value & 2) {
                    189: 
                    190:             i++;
                    191: 
                    192:             hwc = (ngx_hash_wildcard_t *) ((uintptr_t) value & (uintptr_t) ~3);
                    193: 
                    194:             value = ngx_hash_find_wc_tail(hwc, &name[i], len - i);
                    195: 
                    196:             if (value) {
                    197:                 return value;
                    198:             }
                    199: 
                    200:             return hwc->value;
                    201:         }
                    202: 
                    203:         return value;
                    204:     }
                    205: 
                    206:     return hwc->value;
                    207: }
                    208: 
                    209: 
                    210: void *
                    211: ngx_hash_find_combined(ngx_hash_combined_t *hash, ngx_uint_t key, u_char *name,
                    212:     size_t len)
                    213: {
                    214:     void  *value;
                    215: 
                    216:     if (hash->hash.buckets) {
                    217:         value = ngx_hash_find(&hash->hash, key, name, len);
                    218: 
                    219:         if (value) {
                    220:             return value;
                    221:         }
                    222:     }
                    223: 
                    224:     if (len == 0) {
                    225:         return NULL;
                    226:     }
                    227: 
                    228:     if (hash->wc_head && hash->wc_head->hash.buckets) {
                    229:         value = ngx_hash_find_wc_head(hash->wc_head, name, len);
                    230: 
                    231:         if (value) {
                    232:             return value;
                    233:         }
                    234:     }
                    235: 
                    236:     if (hash->wc_tail && hash->wc_tail->hash.buckets) {
                    237:         value = ngx_hash_find_wc_tail(hash->wc_tail, name, len);
                    238: 
                    239:         if (value) {
                    240:             return value;
                    241:         }
                    242:     }
                    243: 
                    244:     return NULL;
                    245: }
                    246: 
                    247: 
                    248: #define NGX_HASH_ELT_SIZE(name)                                               \
                    249:     (sizeof(void *) + ngx_align((name)->key.len + 2, sizeof(void *)))
                    250: 
                    251: ngx_int_t
                    252: ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts)
                    253: {
                    254:     u_char          *elts;
                    255:     size_t           len;
                    256:     u_short         *test;
                    257:     ngx_uint_t       i, n, key, size, start, bucket_size;
                    258:     ngx_hash_elt_t  *elt, **buckets;
                    259: 
                    260:     for (n = 0; n < nelts; n++) {
                    261:         if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names[n]) + sizeof(void *))
                    262:         {
                    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);
                    267:             return NGX_ERROR;
                    268:         }
                    269:     }
                    270: 
                    271:     test = ngx_alloc(hinit->max_size * sizeof(u_short), hinit->pool->log);
                    272:     if (test == NULL) {
                    273:         return NGX_ERROR;
                    274:     }
                    275: 
                    276:     bucket_size = hinit->bucket_size - sizeof(void *);
                    277: 
                    278:     start = nelts / (bucket_size / (2 * sizeof(void *)));
                    279:     start = start ? start : 1;
                    280: 
                    281:     if (hinit->max_size > 10000 && nelts && hinit->max_size / nelts < 100) {
                    282:         start = hinit->max_size - 1000;
                    283:     }
                    284: 
                    285:     for (size = start; size < hinit->max_size; size++) {
                    286: 
                    287:         ngx_memzero(test, size * sizeof(u_short));
                    288: 
                    289:         for (n = 0; n < nelts; n++) {
                    290:             if (names[n].key.data == NULL) {
                    291:                 continue;
                    292:             }
                    293: 
                    294:             key = names[n].key_hash % size;
                    295:             test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n]));
                    296: 
                    297: #if 0
                    298:             ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
                    299:                           "%ui: %ui %ui \"%V\"",
                    300:                           size, key, test[key], &names[n].key);
                    301: #endif
                    302: 
                    303:             if (test[key] > (u_short) bucket_size) {
                    304:                 goto next;
                    305:             }
                    306:         }
                    307: 
                    308:         goto found;
                    309: 
                    310:     next:
                    311: 
                    312:         continue;
                    313:     }
                    314: 
                    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);
                    320: 
                    321:     ngx_free(test);
                    322: 
                    323:     return NGX_ERROR;
                    324: 
                    325: found:
                    326: 
                    327:     for (i = 0; i < size; i++) {
                    328:         test[i] = sizeof(void *);
                    329:     }
                    330: 
                    331:     for (n = 0; n < nelts; n++) {
                    332:         if (names[n].key.data == NULL) {
                    333:             continue;
                    334:         }
                    335: 
                    336:         key = names[n].key_hash % size;
                    337:         test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n]));
                    338:     }
                    339: 
                    340:     len = 0;
                    341: 
                    342:     for (i = 0; i < size; i++) {
                    343:         if (test[i] == sizeof(void *)) {
                    344:             continue;
                    345:         }
                    346: 
                    347:         test[i] = (u_short) (ngx_align(test[i], ngx_cacheline_size));
                    348: 
                    349:         len += test[i];
                    350:     }
                    351: 
                    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) {
                    356:             ngx_free(test);
                    357:             return NGX_ERROR;
                    358:         }
                    359: 
                    360:         buckets = (ngx_hash_elt_t **)
                    361:                       ((u_char *) hinit->hash + sizeof(ngx_hash_wildcard_t));
                    362: 
                    363:     } else {
                    364:         buckets = ngx_pcalloc(hinit->pool, size * sizeof(ngx_hash_elt_t *));
                    365:         if (buckets == NULL) {
                    366:             ngx_free(test);
                    367:             return NGX_ERROR;
                    368:         }
                    369:     }
                    370: 
                    371:     elts = ngx_palloc(hinit->pool, len + ngx_cacheline_size);
                    372:     if (elts == NULL) {
                    373:         ngx_free(test);
                    374:         return NGX_ERROR;
                    375:     }
                    376: 
                    377:     elts = ngx_align_ptr(elts, ngx_cacheline_size);
                    378: 
                    379:     for (i = 0; i < size; i++) {
                    380:         if (test[i] == sizeof(void *)) {
                    381:             continue;
                    382:         }
                    383: 
                    384:         buckets[i] = (ngx_hash_elt_t *) elts;
                    385:         elts += test[i];
                    386: 
                    387:     }
                    388: 
                    389:     for (i = 0; i < size; i++) {
                    390:         test[i] = 0;
                    391:     }
                    392: 
                    393:     for (n = 0; n < nelts; n++) {
                    394:         if (names[n].key.data == NULL) {
                    395:             continue;
                    396:         }
                    397: 
                    398:         key = names[n].key_hash % size;
                    399:         elt = (ngx_hash_elt_t *) ((u_char *) buckets[key] + test[key]);
                    400: 
                    401:         elt->value = names[n].value;
                    402:         elt->len = (u_short) names[n].key.len;
                    403: 
                    404:         ngx_strlow(elt->name, names[n].key.data, names[n].key.len);
                    405: 
                    406:         test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n]));
                    407:     }
                    408: 
                    409:     for (i = 0; i < size; i++) {
                    410:         if (buckets[i] == NULL) {
                    411:             continue;
                    412:         }
                    413: 
                    414:         elt = (ngx_hash_elt_t *) ((u_char *) buckets[i] + test[i]);
                    415: 
                    416:         elt->value = NULL;
                    417:     }
                    418: 
                    419:     ngx_free(test);
                    420: 
                    421:     hinit->hash->buckets = buckets;
                    422:     hinit->hash->size = size;
                    423: 
                    424: #if 0
                    425: 
                    426:     for (i = 0; i < size; i++) {
                    427:         ngx_str_t   val;
                    428:         ngx_uint_t  key;
                    429: 
                    430:         elt = buckets[i];
                    431: 
                    432:         if (elt == NULL) {
                    433:             ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
                    434:                           "%ui: NULL", i);
                    435:             continue;
                    436:         }
                    437: 
                    438:         while (elt->value) {
                    439:             val.len = elt->len;
                    440:             val.data = &elt->name[0];
                    441: 
                    442:             key = hinit->key(val.data, val.len);
                    443: 
                    444:             ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
                    445:                           "%ui: %p \"%V\" %ui", i, elt, &val, key);
                    446: 
                    447:             elt = (ngx_hash_elt_t *) ngx_align_ptr(&elt->name[0] + elt->len,
                    448:                                                    sizeof(void *));
                    449:         }
                    450:     }
                    451: 
                    452: #endif
                    453: 
                    454:     return NGX_OK;
                    455: }
                    456: 
                    457: 
                    458: ngx_int_t
                    459: ngx_hash_wildcard_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names,
                    460:     ngx_uint_t nelts)
                    461: {
                    462:     size_t                len, dot_len;
                    463:     ngx_uint_t            i, n, dot;
                    464:     ngx_array_t           curr_names, next_names;
                    465:     ngx_hash_key_t       *name, *next_name;
                    466:     ngx_hash_init_t       h;
                    467:     ngx_hash_wildcard_t  *wdc;
                    468: 
                    469:     if (ngx_array_init(&curr_names, hinit->temp_pool, nelts,
                    470:                        sizeof(ngx_hash_key_t))
                    471:         != NGX_OK)
                    472:     {
                    473:         return NGX_ERROR;
                    474:     }
                    475: 
                    476:     if (ngx_array_init(&next_names, hinit->temp_pool, nelts,
                    477:                        sizeof(ngx_hash_key_t))
                    478:         != NGX_OK)
                    479:     {
                    480:         return NGX_ERROR;
                    481:     }
                    482: 
                    483:     for (n = 0; n < nelts; n = i) {
                    484: 
                    485: #if 0
                    486:         ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
                    487:                       "wc0: \"%V\"", &names[n].key);
                    488: #endif
                    489: 
                    490:         dot = 0;
                    491: 
                    492:         for (len = 0; len < names[n].key.len; len++) {
                    493:             if (names[n].key.data[len] == '.') {
                    494:                 dot = 1;
                    495:                 break;
                    496:             }
                    497:         }
                    498: 
                    499:         name = ngx_array_push(&curr_names);
                    500:         if (name == NULL) {
                    501:             return NGX_ERROR;
                    502:         }
                    503: 
                    504:         name->key.len = len;
                    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;
                    508: 
                    509: #if 0
                    510:         ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
                    511:                       "wc1: \"%V\" %ui", &name->key, dot);
                    512: #endif
                    513: 
                    514:         dot_len = len + 1;
                    515: 
                    516:         if (dot) {
                    517:             len++;
                    518:         }
                    519: 
                    520:         next_names.nelts = 0;
                    521: 
                    522:         if (names[n].key.len != len) {
                    523:             next_name = ngx_array_push(&next_names);
                    524:             if (next_name == NULL) {
                    525:                 return NGX_ERROR;
                    526:             }
                    527: 
                    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;
                    532: 
                    533: #if 0
                    534:             ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
                    535:                           "wc2: \"%V\"", &next_name->key);
                    536: #endif
                    537:         }
                    538: 
                    539:         for (i = n + 1; i < nelts; i++) {
                    540:             if (ngx_strncmp(names[n].key.data, names[i].key.data, len) != 0) {
                    541:                 break;
                    542:             }
                    543: 
                    544:             if (!dot
                    545:                 && names[i].key.len > len
                    546:                 && names[i].key.data[len] != '.')
                    547:             {
                    548:                 break;
                    549:             }
                    550: 
                    551:             next_name = ngx_array_push(&next_names);
                    552:             if (next_name == NULL) {
                    553:                 return NGX_ERROR;
                    554:             }
                    555: 
                    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;
                    560: 
                    561: #if 0
                    562:             ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
                    563:                           "wc3: \"%V\"", &next_name->key);
                    564: #endif
                    565:         }
                    566: 
                    567:         if (next_names.nelts) {
                    568: 
                    569:             h = *hinit;
                    570:             h.hash = NULL;
                    571: 
                    572:             if (ngx_hash_wildcard_init(&h, (ngx_hash_key_t *) next_names.elts,
                    573:                                        next_names.nelts)
                    574:                 != NGX_OK)
                    575:             {
                    576:                 return NGX_ERROR;
                    577:             }
                    578: 
                    579:             wdc = (ngx_hash_wildcard_t *) h.hash;
                    580: 
                    581:             if (names[n].key.len == len) {
                    582:                 wdc->value = names[n].value;
                    583:             }
                    584: 
                    585:             name->value = (void *) ((uintptr_t) wdc | (dot ? 3 : 2));
                    586: 
                    587:         } else if (dot) {
                    588:             name->value = (void *) ((uintptr_t) name->value | 1);
                    589:         }
                    590:     }
                    591: 
                    592:     if (ngx_hash_init(hinit, (ngx_hash_key_t *) curr_names.elts,
                    593:                       curr_names.nelts)
                    594:         != NGX_OK)
                    595:     {
                    596:         return NGX_ERROR;
                    597:     }
                    598: 
                    599:     return NGX_OK;
                    600: }
                    601: 
                    602: 
                    603: ngx_uint_t
                    604: ngx_hash_key(u_char *data, size_t len)
                    605: {
                    606:     ngx_uint_t  i, key;
                    607: 
                    608:     key = 0;
                    609: 
                    610:     for (i = 0; i < len; i++) {
                    611:         key = ngx_hash(key, data[i]);
                    612:     }
                    613: 
                    614:     return key;
                    615: }
                    616: 
                    617: 
                    618: ngx_uint_t
                    619: ngx_hash_key_lc(u_char *data, size_t len)
                    620: {
                    621:     ngx_uint_t  i, key;
                    622: 
                    623:     key = 0;
                    624: 
                    625:     for (i = 0; i < len; i++) {
                    626:         key = ngx_hash(key, ngx_tolower(data[i]));
                    627:     }
                    628: 
                    629:     return key;
                    630: }
                    631: 
                    632: 
                    633: ngx_uint_t
                    634: ngx_hash_strlow(u_char *dst, u_char *src, size_t n)
                    635: {
                    636:     ngx_uint_t  key;
                    637: 
                    638:     key = 0;
                    639: 
                    640:     while (n--) {
                    641:         *dst = ngx_tolower(*src);
                    642:         key = ngx_hash(key, *dst);
                    643:         dst++;
                    644:         src++;
                    645:     }
                    646: 
                    647:     return key;
                    648: }
                    649: 
                    650: 
                    651: ngx_int_t
                    652: ngx_hash_keys_array_init(ngx_hash_keys_arrays_t *ha, ngx_uint_t type)
                    653: {
                    654:     ngx_uint_t  asize;
                    655: 
                    656:     if (type == NGX_HASH_SMALL) {
                    657:         asize = 4;
                    658:         ha->hsize = 107;
                    659: 
                    660:     } else {
                    661:         asize = NGX_HASH_LARGE_ASIZE;
                    662:         ha->hsize = NGX_HASH_LARGE_HSIZE;
                    663:     }
                    664: 
                    665:     if (ngx_array_init(&ha->keys, ha->temp_pool, asize, sizeof(ngx_hash_key_t))
                    666:         != NGX_OK)
                    667:     {
                    668:         return NGX_ERROR;
                    669:     }
                    670: 
                    671:     if (ngx_array_init(&ha->dns_wc_head, ha->temp_pool, asize,
                    672:                        sizeof(ngx_hash_key_t))
                    673:         != NGX_OK)
                    674:     {
                    675:         return NGX_ERROR;
                    676:     }
                    677: 
                    678:     if (ngx_array_init(&ha->dns_wc_tail, ha->temp_pool, asize,
                    679:                        sizeof(ngx_hash_key_t))
                    680:         != NGX_OK)
                    681:     {
                    682:         return NGX_ERROR;
                    683:     }
                    684: 
                    685:     ha->keys_hash = ngx_pcalloc(ha->temp_pool, sizeof(ngx_array_t) * ha->hsize);
                    686:     if (ha->keys_hash == NULL) {
                    687:         return NGX_ERROR;
                    688:     }
                    689: 
                    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) {
                    693:         return NGX_ERROR;
                    694:     }
                    695: 
                    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) {
                    699:         return NGX_ERROR;
                    700:     }
                    701: 
                    702:     return NGX_OK;
                    703: }
                    704: 
                    705: 
                    706: ngx_int_t
                    707: ngx_hash_add_key(ngx_hash_keys_arrays_t *ha, ngx_str_t *key, void *value,
                    708:     ngx_uint_t flags)
                    709: {
                    710:     size_t           len;
                    711:     u_char          *p;
                    712:     ngx_str_t       *name;
                    713:     ngx_uint_t       i, k, n, skip, last;
                    714:     ngx_array_t     *keys, *hwc;
                    715:     ngx_hash_key_t  *hk;
                    716: 
                    717:     last = key->len;
                    718: 
                    719:     if (flags & NGX_HASH_WILDCARD_KEY) {
                    720: 
                    721:         /*
                    722:          * supported wildcards:
                    723:          *     "*.example.com", ".example.com", and "www.example.*"
                    724:          */
                    725: 
                    726:         n = 0;
                    727: 
                    728:         for (i = 0; i < key->len; i++) {
                    729: 
                    730:             if (key->data[i] == '*') {
                    731:                 if (++n > 1) {
                    732:                     return NGX_DECLINED;
                    733:                 }
                    734:             }
                    735: 
                    736:             if (key->data[i] == '.' && key->data[i + 1] == '.') {
                    737:                 return NGX_DECLINED;
                    738:             }
                    739:         }
                    740: 
                    741:         if (key->len > 1 && key->data[0] == '.') {
                    742:             skip = 1;
                    743:             goto wildcard;
                    744:         }
                    745: 
                    746:         if (key->len > 2) {
                    747: 
                    748:             if (key->data[0] == '*' && key->data[1] == '.') {
                    749:                 skip = 2;
                    750:                 goto wildcard;
                    751:             }
                    752: 
                    753:             if (key->data[i - 2] == '.' && key->data[i - 1] == '*') {
                    754:                 skip = 0;
                    755:                 last -= 2;
                    756:                 goto wildcard;
                    757:             }
                    758:         }
                    759: 
                    760:         if (n) {
                    761:             return NGX_DECLINED;
                    762:         }
                    763:     }
                    764: 
                    765:     /* exact hash */
                    766: 
                    767:     k = 0;
                    768: 
                    769:     for (i = 0; i < last; i++) {
                    770:         if (!(flags & NGX_HASH_READONLY_KEY)) {
                    771:             key->data[i] = ngx_tolower(key->data[i]);
                    772:         }
                    773:         k = ngx_hash(k, key->data[i]);
                    774:     }
                    775: 
                    776:     k %= ha->hsize;
                    777: 
                    778:     /* check conflicts in exact hash */
                    779: 
                    780:     name = ha->keys_hash[k].elts;
                    781: 
                    782:     if (name) {
                    783:         for (i = 0; i < ha->keys_hash[k].nelts; i++) {
                    784:             if (last != name[i].len) {
                    785:                 continue;
                    786:             }
                    787: 
                    788:             if (ngx_strncmp(key->data, name[i].data, last) == 0) {
                    789:                 return NGX_BUSY;
                    790:             }
                    791:         }
                    792: 
                    793:     } else {
                    794:         if (ngx_array_init(&ha->keys_hash[k], ha->temp_pool, 4,
                    795:                            sizeof(ngx_str_t))
                    796:             != NGX_OK)
                    797:         {
                    798:             return NGX_ERROR;
                    799:         }
                    800:     }
                    801: 
                    802:     name = ngx_array_push(&ha->keys_hash[k]);
                    803:     if (name == NULL) {
                    804:         return NGX_ERROR;
                    805:     }
                    806: 
                    807:     *name = *key;
                    808: 
                    809:     hk = ngx_array_push(&ha->keys);
                    810:     if (hk == NULL) {
                    811:         return NGX_ERROR;
                    812:     }
                    813: 
                    814:     hk->key = *key;
                    815:     hk->key_hash = ngx_hash_key(key->data, last);
                    816:     hk->value = value;
                    817: 
                    818:     return NGX_OK;
                    819: 
                    820: 
                    821: wildcard:
                    822: 
                    823:     /* wildcard hash */
                    824: 
                    825:     k = ngx_hash_strlow(&key->data[skip], &key->data[skip], last - skip);
                    826: 
                    827:     k %= ha->hsize;
                    828: 
                    829:     if (skip == 1) {
                    830: 
                    831:         /* check conflicts in exact hash for ".example.com" */
                    832: 
                    833:         name = ha->keys_hash[k].elts;
                    834: 
                    835:         if (name) {
                    836:             len = last - skip;
                    837: 
                    838:             for (i = 0; i < ha->keys_hash[k].nelts; i++) {
                    839:                 if (len != name[i].len) {
                    840:                     continue;
                    841:                 }
                    842: 
                    843:                 if (ngx_strncmp(&key->data[1], name[i].data, len) == 0) {
                    844:                     return NGX_BUSY;
                    845:                 }
                    846:             }
                    847: 
                    848:         } else {
                    849:             if (ngx_array_init(&ha->keys_hash[k], ha->temp_pool, 4,
                    850:                                sizeof(ngx_str_t))
                    851:                 != NGX_OK)
                    852:             {
                    853:                 return NGX_ERROR;
                    854:             }
                    855:         }
                    856: 
                    857:         name = ngx_array_push(&ha->keys_hash[k]);
                    858:         if (name == NULL) {
                    859:             return NGX_ERROR;
                    860:         }
                    861: 
                    862:         name->len = last - 1;
                    863:         name->data = ngx_pnalloc(ha->temp_pool, name->len);
                    864:         if (name->data == NULL) {
                    865:             return NGX_ERROR;
                    866:         }
                    867: 
                    868:         ngx_memcpy(name->data, &key->data[1], name->len);
                    869:     }
                    870: 
                    871: 
                    872:     if (skip) {
                    873: 
                    874:         /*
                    875:          * convert "*.example.com" to "com.example.\0"
                    876:          *      and ".example.com" to "com.example\0"
                    877:          */
                    878: 
                    879:         p = ngx_pnalloc(ha->temp_pool, last);
                    880:         if (p == NULL) {
                    881:             return NGX_ERROR;
                    882:         }
                    883: 
                    884:         len = 0;
                    885:         n = 0;
                    886: 
                    887:         for (i = last - 1; i; i--) {
                    888:             if (key->data[i] == '.') {
                    889:                 ngx_memcpy(&p[n], &key->data[i + 1], len);
                    890:                 n += len;
                    891:                 p[n++] = '.';
                    892:                 len = 0;
                    893:                 continue;
                    894:             }
                    895: 
                    896:             len++;
                    897:         }
                    898: 
                    899:         if (len) {
                    900:             ngx_memcpy(&p[n], &key->data[1], len);
                    901:             n += len;
                    902:         }
                    903: 
                    904:         p[n] = '\0';
                    905: 
                    906:         hwc = &ha->dns_wc_head;
                    907:         keys = &ha->dns_wc_head_hash[k];
                    908: 
                    909:     } else {
                    910: 
                    911:         /* convert "www.example.*" to "www.example\0" */
                    912: 
                    913:         last++;
                    914: 
                    915:         p = ngx_pnalloc(ha->temp_pool, last);
                    916:         if (p == NULL) {
                    917:             return NGX_ERROR;
                    918:         }
                    919: 
                    920:         ngx_cpystrn(p, key->data, last);
                    921: 
                    922:         hwc = &ha->dns_wc_tail;
                    923:         keys = &ha->dns_wc_tail_hash[k];
                    924:     }
                    925: 
                    926: 
                    927:     /* check conflicts in wildcard hash */
                    928: 
                    929:     name = keys->elts;
                    930: 
                    931:     if (name) {
                    932:         len = last - skip;
                    933: 
                    934:         for (i = 0; i < keys->nelts; i++) {
                    935:             if (len != name[i].len) {
                    936:                 continue;
                    937:             }
                    938: 
                    939:             if (ngx_strncmp(key->data + skip, name[i].data, len) == 0) {
                    940:                 return NGX_BUSY;
                    941:             }
                    942:         }
                    943: 
                    944:     } else {
                    945:         if (ngx_array_init(keys, ha->temp_pool, 4, sizeof(ngx_str_t)) != NGX_OK)
                    946:         {
                    947:             return NGX_ERROR;
                    948:         }
                    949:     }
                    950: 
                    951:     name = ngx_array_push(keys);
                    952:     if (name == NULL) {
                    953:         return NGX_ERROR;
                    954:     }
                    955: 
                    956:     name->len = last - skip;
                    957:     name->data = ngx_pnalloc(ha->temp_pool, name->len);
                    958:     if (name->data == NULL) {
                    959:         return NGX_ERROR;
                    960:     }
                    961: 
                    962:     ngx_memcpy(name->data, key->data + skip, name->len);
                    963: 
                    964: 
                    965:     /* add to wildcard hash */
                    966: 
                    967:     hk = ngx_array_push(hwc);
                    968:     if (hk == NULL) {
                    969:         return NGX_ERROR;
                    970:     }
                    971: 
                    972:     hk->key.len = last - 1;
                    973:     hk->key.data = p;
                    974:     hk->key_hash = 0;
                    975:     hk->value = value;
                    976: 
                    977:     return NGX_OK;
                    978: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>