src/core/ngx_hash.c - nginx source code

Functions defined

Macros defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>


  7. void *
  8. ngx_hash_find(ngx_hash_t *hash, ngx_uint_t key, u_char *name, size_t len)
  9. {
  10.     ngx_uint_t       i;
  11.     ngx_hash_elt_t  *elt;

  12. #if 0
  13.     ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "hf:\"%*s\"", len, name);
  14. #endif

  15.     elt = hash->buckets[key % hash->size];

  16.     if (elt == NULL) {
  17.         return NULL;
  18.     }

  19.     while (elt->value) {
  20.         if (len != (size_t) elt->len) {
  21.             goto next;
  22.         }

  23.         for (i = 0; i < len; i++) {
  24.             if (name[i] != elt->name[i]) {
  25.                 goto next;
  26.             }
  27.         }

  28.         return elt->value;

  29.     next:

  30.         elt = (ngx_hash_elt_t *) ngx_align_ptr(&elt->name[0] + elt->len,
  31.                                                sizeof(void *));
  32.         continue;
  33.     }

  34.     return NULL;
  35. }


  36. void *
  37. ngx_hash_find_wc_head(ngx_hash_wildcard_t *hwc, u_char *name, size_t len)
  38. {
  39.     void        *value;
  40.     ngx_uint_t   i, n, key;

  41. #if 0
  42.     ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "wch:\"%*s\"", len, name);
  43. #endif

  44.     n = len;

  45.     while (n) {
  46.         if (name[n - 1] == '.') {
  47.             break;
  48.         }

  49.         n--;
  50.     }

  51.     key = 0;

  52.     for (i = n; i < len; i++) {
  53.         key = ngx_hash(key, name[i]);
  54.     }

  55. #if 0
  56.     ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "key:\"%ui\"", key);
  57. #endif

  58.     value = ngx_hash_find(&hwc->hash, key, &name[n], len - n);

  59. #if 0
  60.     ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "value:\"%p\"", value);
  61. #endif

  62.     if (value) {

  63.         /*
  64.          * the 2 low bits of value have the special meaning:
  65.          *     00 - value is data pointer for both "example.com"
  66.          *          and "*.example.com";
  67.          *     01 - value is data pointer for "*.example.com" only;
  68.          *     10 - value is pointer to wildcard hash allowing
  69.          *          both "example.com" and "*.example.com";
  70.          *     11 - value is pointer to wildcard hash allowing
  71.          *          "*.example.com" only.
  72.          */

  73.         if ((uintptr_t) value & 2) {

  74.             if (n == 0) {

  75.                 /* "example.com" */

  76.                 if ((uintptr_t) value & 1) {
  77.                     return NULL;
  78.                 }

  79.                 hwc = (ngx_hash_wildcard_t *)
  80.                                           ((uintptr_t) value & (uintptr_t) ~3);
  81.                 return hwc->value;
  82.             }

  83.             hwc = (ngx_hash_wildcard_t *) ((uintptr_t) value & (uintptr_t) ~3);

  84.             value = ngx_hash_find_wc_head(hwc, name, n - 1);

  85.             if (value) {
  86.                 return value;
  87.             }

  88.             return hwc->value;
  89.         }

  90.         if ((uintptr_t) value & 1) {

  91.             if (n == 0) {

  92.                 /* "example.com" */

  93.                 return NULL;
  94.             }

  95.             return (void *) ((uintptr_t) value & (uintptr_t) ~3);
  96.         }

  97.         return value;
  98.     }

  99.     return hwc->value;
  100. }


  101. void *
  102. ngx_hash_find_wc_tail(ngx_hash_wildcard_t *hwc, u_char *name, size_t len)
  103. {
  104.     void        *value;
  105.     ngx_uint_t   i, key;

  106. #if 0
  107.     ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "wct:\"%*s\"", len, name);
  108. #endif

  109.     key = 0;

  110.     for (i = 0; i < len; i++) {
  111.         if (name[i] == '.') {
  112.             break;
  113.         }

  114.         key = ngx_hash(key, name[i]);
  115.     }

  116.     if (i == len) {
  117.         return NULL;
  118.     }

  119. #if 0
  120.     ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "key:\"%ui\"", key);
  121. #endif

  122.     value = ngx_hash_find(&hwc->hash, key, name, i);

  123. #if 0
  124.     ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, "value:\"%p\"", value);
  125. #endif

  126.     if (value) {

  127.         /*
  128.          * the 2 low bits of value have the special meaning:
  129.          *     00 - value is data pointer;
  130.          *     11 - value is pointer to wildcard hash allowing "example.*".
  131.          */

  132.         if ((uintptr_t) value & 2) {

  133.             i++;

  134.             hwc = (ngx_hash_wildcard_t *) ((uintptr_t) value & (uintptr_t) ~3);

  135.             value = ngx_hash_find_wc_tail(hwc, &name[i], len - i);

  136.             if (value) {
  137.                 return value;
  138.             }

  139.             return hwc->value;
  140.         }

  141.         return value;
  142.     }

  143.     return hwc->value;
  144. }


  145. void *
  146. ngx_hash_find_combined(ngx_hash_combined_t *hash, ngx_uint_t key, u_char *name,
  147.     size_t len)
  148. {
  149.     void  *value;

  150.     if (hash->hash.buckets) {
  151.         value = ngx_hash_find(&hash->hash, key, name, len);

  152.         if (value) {
  153.             return value;
  154.         }
  155.     }

  156.     if (len == 0) {
  157.         return NULL;
  158.     }

  159.     if (hash->wc_head && hash->wc_head->hash.buckets) {
  160.         value = ngx_hash_find_wc_head(hash->wc_head, name, len);

  161.         if (value) {
  162.             return value;
  163.         }
  164.     }

  165.     if (hash->wc_tail && hash->wc_tail->hash.buckets) {
  166.         value = ngx_hash_find_wc_tail(hash->wc_tail, name, len);

  167.         if (value) {
  168.             return value;
  169.         }
  170.     }

  171.     return NULL;
  172. }


  173. #define NGX_HASH_ELT_SIZE(name)                                               \
  174.     (sizeof(void *) + ngx_align((name)->key.len + 2, sizeof(void *)))

  175. ngx_int_t
  176. ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names, ngx_uint_t nelts)
  177. {
  178.     u_char          *elts;
  179.     size_t           len;
  180.     u_short         *test;
  181.     ngx_uint_t       i, n, key, size, start, bucket_size;
  182.     ngx_hash_elt_t  *elt, **buckets;

  183.     if (hinit->max_size == 0) {
  184.         ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,
  185.                       "could not build %s, you should "
  186.                       "increase %s_max_size: %i",
  187.                       hinit->name, hinit->name, hinit->max_size);
  188.         return NGX_ERROR;
  189.     }

  190.     if (hinit->bucket_size > 65536 - ngx_cacheline_size) {
  191.         ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,
  192.                       "could not build %s, too large "
  193.                       "%s_bucket_size: %i",
  194.                       hinit->name, hinit->name, hinit->bucket_size);
  195.         return NGX_ERROR;
  196.     }

  197.     for (n = 0; n < nelts; n++) {
  198.         if (names[n].key.data == NULL) {
  199.             continue;
  200.         }

  201.         if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names[n]) + sizeof(void *))
  202.         {
  203.             ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,
  204.                           "could not build %s, you should "
  205.                           "increase %s_bucket_size: %i",
  206.                           hinit->name, hinit->name, hinit->bucket_size);
  207.             return NGX_ERROR;
  208.         }
  209.     }

  210.     test = ngx_alloc(hinit->max_size * sizeof(u_short), hinit->pool->log);
  211.     if (test == NULL) {
  212.         return NGX_ERROR;
  213.     }

  214.     bucket_size = hinit->bucket_size - sizeof(void *);

  215.     start = nelts / (bucket_size / (2 * sizeof(void *)));
  216.     start = start ? start : 1;

  217.     if (hinit->max_size > 10000 && nelts && hinit->max_size / nelts < 100) {
  218.         start = hinit->max_size - 1000;
  219.     }

  220.     for (size = start; size <= hinit->max_size; size++) {

  221.         ngx_memzero(test, size * sizeof(u_short));

  222.         for (n = 0; n < nelts; n++) {
  223.             if (names[n].key.data == NULL) {
  224.                 continue;
  225.             }

  226.             key = names[n].key_hash % size;
  227.             len = test[key] + NGX_HASH_ELT_SIZE(&names[n]);

  228. #if 0
  229.             ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
  230.                           "%ui: %ui %uz \"%V\"",
  231.                           size, key, len, &names[n].key);
  232. #endif

  233.             if (len > bucket_size) {
  234.                 goto next;
  235.             }

  236.             test[key] = (u_short) len;
  237.         }

  238.         goto found;

  239.     next:

  240.         continue;
  241.     }

  242.     size = hinit->max_size;

  243.     ngx_log_error(NGX_LOG_WARN, hinit->pool->log, 0,
  244.                   "could not build optimal %s, you should increase "
  245.                   "either %s_max_size: %i or %s_bucket_size: %i; "
  246.                   "ignoring %s_bucket_size",
  247.                   hinit->name, hinit->name, hinit->max_size,
  248.                   hinit->name, hinit->bucket_size, hinit->name);

  249. found:

  250.     for (i = 0; i < size; i++) {
  251.         test[i] = sizeof(void *);
  252.     }

  253.     for (n = 0; n < nelts; n++) {
  254.         if (names[n].key.data == NULL) {
  255.             continue;
  256.         }

  257.         key = names[n].key_hash % size;
  258.         len = test[key] + NGX_HASH_ELT_SIZE(&names[n]);

  259.         if (len > 65536 - ngx_cacheline_size) {
  260.             ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,
  261.                           "could not build %s, you should "
  262.                           "increase %s_max_size: %i",
  263.                           hinit->name, hinit->name, hinit->max_size);
  264.             ngx_free(test);
  265.             return NGX_ERROR;
  266.         }

  267.         test[key] = (u_short) len;
  268.     }

  269.     len = 0;

  270.     for (i = 0; i < size; i++) {
  271.         if (test[i] == sizeof(void *)) {
  272.             continue;
  273.         }

  274.         test[i] = (u_short) (ngx_align(test[i], ngx_cacheline_size));

  275.         len += test[i];
  276.     }

  277.     if (hinit->hash == NULL) {
  278.         hinit->hash = ngx_pcalloc(hinit->pool, sizeof(ngx_hash_wildcard_t)
  279.                                              + size * sizeof(ngx_hash_elt_t *));
  280.         if (hinit->hash == NULL) {
  281.             ngx_free(test);
  282.             return NGX_ERROR;
  283.         }

  284.         buckets = (ngx_hash_elt_t **)
  285.                       ((u_char *) hinit->hash + sizeof(ngx_hash_wildcard_t));

  286.     } else {
  287.         buckets = ngx_pcalloc(hinit->pool, size * sizeof(ngx_hash_elt_t *));
  288.         if (buckets == NULL) {
  289.             ngx_free(test);
  290.             return NGX_ERROR;
  291.         }
  292.     }

  293.     elts = ngx_palloc(hinit->pool, len + ngx_cacheline_size);
  294.     if (elts == NULL) {
  295.         ngx_free(test);
  296.         return NGX_ERROR;
  297.     }

  298.     elts = ngx_align_ptr(elts, ngx_cacheline_size);

  299.     for (i = 0; i < size; i++) {
  300.         if (test[i] == sizeof(void *)) {
  301.             continue;
  302.         }

  303.         buckets[i] = (ngx_hash_elt_t *) elts;
  304.         elts += test[i];
  305.     }

  306.     for (i = 0; i < size; i++) {
  307.         test[i] = 0;
  308.     }

  309.     for (n = 0; n < nelts; n++) {
  310.         if (names[n].key.data == NULL) {
  311.             continue;
  312.         }

  313.         key = names[n].key_hash % size;
  314.         elt = (ngx_hash_elt_t *) ((u_char *) buckets[key] + test[key]);

  315.         elt->value = names[n].value;
  316.         elt->len = (u_short) names[n].key.len;

  317.         ngx_strlow(elt->name, names[n].key.data, names[n].key.len);

  318.         test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n]));
  319.     }

  320.     for (i = 0; i < size; i++) {
  321.         if (buckets[i] == NULL) {
  322.             continue;
  323.         }

  324.         elt = (ngx_hash_elt_t *) ((u_char *) buckets[i] + test[i]);

  325.         elt->value = NULL;
  326.     }

  327.     ngx_free(test);

  328.     hinit->hash->buckets = buckets;
  329.     hinit->hash->size = size;

  330. #if 0

  331.     for (i = 0; i < size; i++) {
  332.         ngx_str_t   val;
  333.         ngx_uint_t  key;

  334.         elt = buckets[i];

  335.         if (elt == NULL) {
  336.             ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
  337.                           "%ui: NULL", i);
  338.             continue;
  339.         }

  340.         while (elt->value) {
  341.             val.len = elt->len;
  342.             val.data = &elt->name[0];

  343.             key = hinit->key(val.data, val.len);

  344.             ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
  345.                           "%ui: %p \"%V\" %ui", i, elt, &val, key);

  346.             elt = (ngx_hash_elt_t *) ngx_align_ptr(&elt->name[0] + elt->len,
  347.                                                    sizeof(void *));
  348.         }
  349.     }

  350. #endif

  351.     return NGX_OK;
  352. }


  353. ngx_int_t
  354. ngx_hash_wildcard_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names,
  355.     ngx_uint_t nelts)
  356. {
  357.     size_t                len, dot_len;
  358.     ngx_uint_t            i, n, dot;
  359.     ngx_array_t           curr_names, next_names;
  360.     ngx_hash_key_t       *name, *next_name;
  361.     ngx_hash_init_t       h;
  362.     ngx_hash_wildcard_t  *wdc;

  363.     if (ngx_array_init(&curr_names, hinit->temp_pool, nelts,
  364.                        sizeof(ngx_hash_key_t))
  365.         != NGX_OK)
  366.     {
  367.         return NGX_ERROR;
  368.     }

  369.     if (ngx_array_init(&next_names, hinit->temp_pool, nelts,
  370.                        sizeof(ngx_hash_key_t))
  371.         != NGX_OK)
  372.     {
  373.         return NGX_ERROR;
  374.     }

  375.     for (n = 0; n < nelts; n = i) {

  376. #if 0
  377.         ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
  378.                       "wc0: \"%V\"", &names[n].key);
  379. #endif

  380.         dot = 0;

  381.         for (len = 0; len < names[n].key.len; len++) {
  382.             if (names[n].key.data[len] == '.') {
  383.                 dot = 1;
  384.                 break;
  385.             }
  386.         }

  387.         name = ngx_array_push(&curr_names);
  388.         if (name == NULL) {
  389.             return NGX_ERROR;
  390.         }

  391.         name->key.len = len;
  392.         name->key.data = names[n].key.data;
  393.         name->key_hash = hinit->key(name->key.data, name->key.len);
  394.         name->value = names[n].value;

  395. #if 0
  396.         ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
  397.                       "wc1: \"%V\" %ui", &name->key, dot);
  398. #endif

  399.         dot_len = len + 1;

  400.         if (dot) {
  401.             len++;
  402.         }

  403.         next_names.nelts = 0;

  404.         if (names[n].key.len != len) {
  405.             next_name = ngx_array_push(&next_names);
  406.             if (next_name == NULL) {
  407.                 return NGX_ERROR;
  408.             }

  409.             next_name->key.len = names[n].key.len - len;
  410.             next_name->key.data = names[n].key.data + len;
  411.             next_name->key_hash = 0;
  412.             next_name->value = names[n].value;

  413. #if 0
  414.             ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
  415.                           "wc2: \"%V\"", &next_name->key);
  416. #endif
  417.         }

  418.         for (i = n + 1; i < nelts; i++) {
  419.             if (ngx_strncmp(names[n].key.data, names[i].key.data, len) != 0) {
  420.                 break;
  421.             }

  422.             if (!dot
  423.                 && names[i].key.len > len
  424.                 && names[i].key.data[len] != '.')
  425.             {
  426.                 break;
  427.             }

  428.             next_name = ngx_array_push(&next_names);
  429.             if (next_name == NULL) {
  430.                 return NGX_ERROR;
  431.             }

  432.             next_name->key.len = names[i].key.len - dot_len;
  433.             next_name->key.data = names[i].key.data + dot_len;
  434.             next_name->key_hash = 0;
  435.             next_name->value = names[i].value;

  436. #if 0
  437.             ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
  438.                           "wc3: \"%V\"", &next_name->key);
  439. #endif
  440.         }

  441.         if (next_names.nelts) {

  442.             h = *hinit;
  443.             h.hash = NULL;

  444.             if (ngx_hash_wildcard_init(&h, (ngx_hash_key_t *) next_names.elts,
  445.                                        next_names.nelts)
  446.                 != NGX_OK)
  447.             {
  448.                 return NGX_ERROR;
  449.             }

  450.             wdc = (ngx_hash_wildcard_t *) h.hash;

  451.             if (names[n].key.len == len) {
  452.                 wdc->value = names[n].value;
  453.             }

  454.             name->value = (void *) ((uintptr_t) wdc | (dot ? 3 : 2));

  455.         } else if (dot) {
  456.             name->value = (void *) ((uintptr_t) name->value | 1);
  457.         }
  458.     }

  459.     if (ngx_hash_init(hinit, (ngx_hash_key_t *) curr_names.elts,
  460.                       curr_names.nelts)
  461.         != NGX_OK)
  462.     {
  463.         return NGX_ERROR;
  464.     }

  465.     return NGX_OK;
  466. }


  467. ngx_uint_t
  468. ngx_hash_key(u_char *data, size_t len)
  469. {
  470.     ngx_uint_t  i, key;

  471.     key = 0;

  472.     for (i = 0; i < len; i++) {
  473.         key = ngx_hash(key, data[i]);
  474.     }

  475.     return key;
  476. }


  477. ngx_uint_t
  478. ngx_hash_key_lc(u_char *data, size_t len)
  479. {
  480.     ngx_uint_t  i, key;

  481.     key = 0;

  482.     for (i = 0; i < len; i++) {
  483.         key = ngx_hash(key, ngx_tolower(data[i]));
  484.     }

  485.     return key;
  486. }


  487. ngx_uint_t
  488. ngx_hash_strlow(u_char *dst, u_char *src, size_t n)
  489. {
  490.     ngx_uint_t  key;

  491.     key = 0;

  492.     while (n--) {
  493.         *dst = ngx_tolower(*src);
  494.         key = ngx_hash(key, *dst);
  495.         dst++;
  496.         src++;
  497.     }

  498.     return key;
  499. }


  500. ngx_int_t
  501. ngx_hash_keys_array_init(ngx_hash_keys_arrays_t *ha, ngx_uint_t type)
  502. {
  503.     ngx_uint_t  asize;

  504.     if (type == NGX_HASH_SMALL) {
  505.         asize = 4;
  506.         ha->hsize = 107;

  507.     } else {
  508.         asize = NGX_HASH_LARGE_ASIZE;
  509.         ha->hsize = NGX_HASH_LARGE_HSIZE;
  510.     }

  511.     if (ngx_array_init(&ha->keys, ha->temp_pool, asize, sizeof(ngx_hash_key_t))
  512.         != NGX_OK)
  513.     {
  514.         return NGX_ERROR;
  515.     }

  516.     if (ngx_array_init(&ha->dns_wc_head, ha->temp_pool, asize,
  517.                        sizeof(ngx_hash_key_t))
  518.         != NGX_OK)
  519.     {
  520.         return NGX_ERROR;
  521.     }

  522.     if (ngx_array_init(&ha->dns_wc_tail, ha->temp_pool, asize,
  523.                        sizeof(ngx_hash_key_t))
  524.         != NGX_OK)
  525.     {
  526.         return NGX_ERROR;
  527.     }

  528.     ha->keys_hash = ngx_pcalloc(ha->temp_pool, sizeof(ngx_array_t) * ha->hsize);
  529.     if (ha->keys_hash == NULL) {
  530.         return NGX_ERROR;
  531.     }

  532.     ha->dns_wc_head_hash = ngx_pcalloc(ha->temp_pool,
  533.                                        sizeof(ngx_array_t) * ha->hsize);
  534.     if (ha->dns_wc_head_hash == NULL) {
  535.         return NGX_ERROR;
  536.     }

  537.     ha->dns_wc_tail_hash = ngx_pcalloc(ha->temp_pool,
  538.                                        sizeof(ngx_array_t) * ha->hsize);
  539.     if (ha->dns_wc_tail_hash == NULL) {
  540.         return NGX_ERROR;
  541.     }

  542.     return NGX_OK;
  543. }


  544. ngx_int_t
  545. ngx_hash_add_key(ngx_hash_keys_arrays_t *ha, ngx_str_t *key, void *value,
  546.     ngx_uint_t flags)
  547. {
  548.     size_t           len;
  549.     u_char          *p;
  550.     ngx_str_t       *name;
  551.     ngx_uint_t       i, k, n, skip, last;
  552.     ngx_array_t     *keys, *hwc;
  553.     ngx_hash_key_t  *hk;

  554.     last = key->len;

  555.     if (flags & NGX_HASH_WILDCARD_KEY) {

  556.         /*
  557.          * supported wildcards:
  558.          *     "*.example.com", ".example.com", and "www.example.*"
  559.          */

  560.         n = 0;

  561.         for (i = 0; i < key->len; i++) {

  562.             if (key->data[i] == '*') {
  563.                 if (++n > 1) {
  564.                     return NGX_DECLINED;
  565.                 }
  566.             }

  567.             if (key->data[i] == '.' && key->data[i + 1] == '.') {
  568.                 return NGX_DECLINED;
  569.             }

  570.             if (key->data[i] == '\0') {
  571.                 return NGX_DECLINED;
  572.             }
  573.         }

  574.         if (key->len > 1 && key->data[0] == '.') {
  575.             skip = 1;
  576.             goto wildcard;
  577.         }

  578.         if (key->len > 2) {

  579.             if (key->data[0] == '*' && key->data[1] == '.') {
  580.                 skip = 2;
  581.                 goto wildcard;
  582.             }

  583.             if (key->data[i - 2] == '.' && key->data[i - 1] == '*') {
  584.                 skip = 0;
  585.                 last -= 2;
  586.                 goto wildcard;
  587.             }
  588.         }

  589.         if (n) {
  590.             return NGX_DECLINED;
  591.         }
  592.     }

  593.     /* exact hash */

  594.     k = 0;

  595.     for (i = 0; i < last; i++) {
  596.         if (!(flags & NGX_HASH_READONLY_KEY)) {
  597.             key->data[i] = ngx_tolower(key->data[i]);
  598.         }
  599.         k = ngx_hash(k, key->data[i]);
  600.     }

  601.     k %= ha->hsize;

  602.     /* check conflicts in exact hash */

  603.     name = ha->keys_hash[k].elts;

  604.     if (name) {
  605.         for (i = 0; i < ha->keys_hash[k].nelts; i++) {
  606.             if (last != name[i].len) {
  607.                 continue;
  608.             }

  609.             if (ngx_strncmp(key->data, name[i].data, last) == 0) {
  610.                 return NGX_BUSY;
  611.             }
  612.         }

  613.     } else {
  614.         if (ngx_array_init(&ha->keys_hash[k], ha->temp_pool, 4,
  615.                            sizeof(ngx_str_t))
  616.             != NGX_OK)
  617.         {
  618.             return NGX_ERROR;
  619.         }
  620.     }

  621.     name = ngx_array_push(&ha->keys_hash[k]);
  622.     if (name == NULL) {
  623.         return NGX_ERROR;
  624.     }

  625.     *name = *key;

  626.     hk = ngx_array_push(&ha->keys);
  627.     if (hk == NULL) {
  628.         return NGX_ERROR;
  629.     }

  630.     hk->key = *key;
  631.     hk->key_hash = ngx_hash_key(key->data, last);
  632.     hk->value = value;

  633.     return NGX_OK;


  634. wildcard:

  635.     /* wildcard hash */

  636.     k = ngx_hash_strlow(&key->data[skip], &key->data[skip], last - skip);

  637.     k %= ha->hsize;

  638.     if (skip == 1) {

  639.         /* check conflicts in exact hash for ".example.com" */

  640.         name = ha->keys_hash[k].elts;

  641.         if (name) {
  642.             len = last - skip;

  643.             for (i = 0; i < ha->keys_hash[k].nelts; i++) {
  644.                 if (len != name[i].len) {
  645.                     continue;
  646.                 }

  647.                 if (ngx_strncmp(&key->data[1], name[i].data, len) == 0) {
  648.                     return NGX_BUSY;
  649.                 }
  650.             }

  651.         } else {
  652.             if (ngx_array_init(&ha->keys_hash[k], ha->temp_pool, 4,
  653.                                sizeof(ngx_str_t))
  654.                 != NGX_OK)
  655.             {
  656.                 return NGX_ERROR;
  657.             }
  658.         }

  659.         name = ngx_array_push(&ha->keys_hash[k]);
  660.         if (name == NULL) {
  661.             return NGX_ERROR;
  662.         }

  663.         name->len = last - 1;
  664.         name->data = ngx_pnalloc(ha->temp_pool, name->len);
  665.         if (name->data == NULL) {
  666.             return NGX_ERROR;
  667.         }

  668.         ngx_memcpy(name->data, &key->data[1], name->len);
  669.     }


  670.     if (skip) {

  671.         /*
  672.          * convert "*.example.com" to "com.example.\0"
  673.          *      and ".example.com" to "com.example\0"
  674.          */

  675.         p = ngx_pnalloc(ha->temp_pool, last);
  676.         if (p == NULL) {
  677.             return NGX_ERROR;
  678.         }

  679.         len = 0;
  680.         n = 0;

  681.         for (i = last - 1; i; i--) {
  682.             if (key->data[i] == '.') {
  683.                 ngx_memcpy(&p[n], &key->data[i + 1], len);
  684.                 n += len;
  685.                 p[n++] = '.';
  686.                 len = 0;
  687.                 continue;
  688.             }

  689.             len++;
  690.         }

  691.         if (len) {
  692.             ngx_memcpy(&p[n], &key->data[1], len);
  693.             n += len;
  694.         }

  695.         p[n] = '\0';

  696.         hwc = &ha->dns_wc_head;
  697.         keys = &ha->dns_wc_head_hash[k];

  698.     } else {

  699.         /* convert "www.example.*" to "www.example\0" */

  700.         last++;

  701.         p = ngx_pnalloc(ha->temp_pool, last);
  702.         if (p == NULL) {
  703.             return NGX_ERROR;
  704.         }

  705.         ngx_cpystrn(p, key->data, last);

  706.         hwc = &ha->dns_wc_tail;
  707.         keys = &ha->dns_wc_tail_hash[k];
  708.     }


  709.     /* check conflicts in wildcard hash */

  710.     name = keys->elts;

  711.     if (name) {
  712.         len = last - skip;

  713.         for (i = 0; i < keys->nelts; i++) {
  714.             if (len != name[i].len) {
  715.                 continue;
  716.             }

  717.             if (ngx_strncmp(key->data + skip, name[i].data, len) == 0) {
  718.                 return NGX_BUSY;
  719.             }
  720.         }

  721.     } else {
  722.         if (ngx_array_init(keys, ha->temp_pool, 4, sizeof(ngx_str_t)) != NGX_OK)
  723.         {
  724.             return NGX_ERROR;
  725.         }
  726.     }

  727.     name = ngx_array_push(keys);
  728.     if (name == NULL) {
  729.         return NGX_ERROR;
  730.     }

  731.     name->len = last - skip;
  732.     name->data = ngx_pnalloc(ha->temp_pool, name->len);
  733.     if (name->data == NULL) {
  734.         return NGX_ERROR;
  735.     }

  736.     ngx_memcpy(name->data, key->data + skip, name->len);


  737.     /* add to wildcard hash */

  738.     hk = ngx_array_push(hwc);
  739.     if (hk == NULL) {
  740.         return NGX_ERROR;
  741.     }

  742.     hk->key.len = last - 1;
  743.     hk->key.data = p;
  744.     hk->key_hash = 0;
  745.     hk->value = value;

  746.     return NGX_OK;
  747. }