Annotation of embedaddon/nginx/src/core/ngx_hash.c, revision 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>