src/core/ngx_hash.c - nginx-1.7.10

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.     for (n = 0; n < nelts; n++) {
  184.         if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names[n]) + sizeof(void *))
  185.         {
  186.             ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0,
  187.                           "could not build the %s, you should "
  188.                           "increase %s_bucket_size: %i",
  189.                           hinit->name, hinit->name, hinit->bucket_size);
  190.             return NGX_ERROR;
  191.         }
  192.     }

  193.     test = ngx_alloc(hinit->max_size * sizeof(u_short), hinit->pool->log);
  194.     if (test == NULL) {
  195.         return NGX_ERROR;
  196.     }

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

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

  200.     if (hinit->max_size > 10000 && nelts && hinit->max_size / nelts < 100) {
  201.         start = hinit->max_size - 1000;
  202.     }

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

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

  205.         for (n = 0; n < nelts; n++) {
  206.             if (names[n].key.data == NULL) {
  207.                 continue;
  208.             }

  209.             key = names[n].key_hash % size;
  210.             test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n]));

  211. #if 0
  212.             ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
  213.                           "%ui: %ui %ui \"%V\"",
  214.                           size, key, test[key], &names[n].key);
  215. #endif

  216.             if (test[key] > (u_short) bucket_size) {
  217.                 goto next;
  218.             }
  219.         }

  220.         goto found;

  221.     next:

  222.         continue;
  223.     }

  224.     size--;

  225.     ngx_log_error(NGX_LOG_WARN, hinit->pool->log, 0,
  226.                   "could not build optimal %s, you should increase "
  227.                   "either %s_max_size: %i or %s_bucket_size: %i; "
  228.                   "ignoring %s_bucket_size",
  229.                   hinit->name, hinit->name, hinit->max_size,
  230.                   hinit->name, hinit->bucket_size, hinit->name);

  231. found:

  232.     for (i = 0; i < size; i++) {
  233.         test[i] = sizeof(void *);
  234.     }

  235.     for (n = 0; n < nelts; n++) {
  236.         if (names[n].key.data == NULL) {
  237.             continue;
  238.         }

  239.         key = names[n].key_hash % size;
  240.         test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n]));
  241.     }

  242.     len = 0;

  243.     for (i = 0; i < size; i++) {
  244.         if (test[i] == sizeof(void *)) {
  245.             continue;
  246.         }

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

  248.         len += test[i];
  249.     }

  250.     if (hinit->hash == NULL) {
  251.         hinit->hash = ngx_pcalloc(hinit->pool, sizeof(ngx_hash_wildcard_t)
  252.                                              + size * sizeof(ngx_hash_elt_t *));
  253.         if (hinit->hash == NULL) {
  254.             ngx_free(test);
  255.             return NGX_ERROR;
  256.         }

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

  259.     } else {
  260.         buckets = ngx_pcalloc(hinit->pool, size * sizeof(ngx_hash_elt_t *));
  261.         if (buckets == NULL) {
  262.             ngx_free(test);
  263.             return NGX_ERROR;
  264.         }
  265.     }

  266.     elts = ngx_palloc(hinit->pool, len + ngx_cacheline_size);
  267.     if (elts == NULL) {
  268.         ngx_free(test);
  269.         return NGX_ERROR;
  270.     }

  271.     elts = ngx_align_ptr(elts, ngx_cacheline_size);

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

  276.         buckets[i] = (ngx_hash_elt_t *) elts;
  277.         elts += test[i];

  278.     }

  279.     for (i = 0; i < size; i++) {
  280.         test[i] = 0;
  281.     }

  282.     for (n = 0; n < nelts; n++) {
  283.         if (names[n].key.data == NULL) {
  284.             continue;
  285.         }

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

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

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

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

  293.     for (i = 0; i < size; i++) {
  294.         if (buckets[i] == NULL) {
  295.             continue;
  296.         }

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

  298.         elt->value = NULL;
  299.     }

  300.     ngx_free(test);

  301.     hinit->hash->buckets = buckets;
  302.     hinit->hash->size = size;

  303. #if 0

  304.     for (i = 0; i < size; i++) {
  305.         ngx_str_t   val;
  306.         ngx_uint_t  key;

  307.         elt = buckets[i];

  308.         if (elt == NULL) {
  309.             ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
  310.                           "%ui: NULL", i);
  311.             continue;
  312.         }

  313.         while (elt->value) {
  314.             val.len = elt->len;
  315.             val.data = &elt->name[0];

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

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

  319.             elt = (ngx_hash_elt_t *) ngx_align_ptr(&elt->name[0] + elt->len,
  320.                                                    sizeof(void *));
  321.         }
  322.     }

  323. #endif

  324.     return NGX_OK;
  325. }


  326. ngx_int_t
  327. ngx_hash_wildcard_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names,
  328.     ngx_uint_t nelts)
  329. {
  330.     size_t                len, dot_len;
  331.     ngx_uint_t            i, n, dot;
  332.     ngx_array_t           curr_names, next_names;
  333.     ngx_hash_key_t       *name, *next_name;
  334.     ngx_hash_init_t       h;
  335.     ngx_hash_wildcard_t  *wdc;

  336.     if (ngx_array_init(&curr_names, hinit->temp_pool, nelts,
  337.                        sizeof(ngx_hash_key_t))
  338.         != NGX_OK)
  339.     {
  340.         return NGX_ERROR;
  341.     }

  342.     if (ngx_array_init(&next_names, hinit->temp_pool, nelts,
  343.                        sizeof(ngx_hash_key_t))
  344.         != NGX_OK)
  345.     {
  346.         return NGX_ERROR;
  347.     }

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

  349. #if 0
  350.         ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
  351.                       "wc0: \"%V\"", &names[n].key);
  352. #endif

  353.         dot = 0;

  354.         for (len = 0; len < names[n].key.len; len++) {
  355.             if (names[n].key.data[len] == '.') {
  356.                 dot = 1;
  357.                 break;
  358.             }
  359.         }

  360.         name = ngx_array_push(&curr_names);
  361.         if (name == NULL) {
  362.             return NGX_ERROR;
  363.         }

  364.         name->key.len = len;
  365.         name->key.data = names[n].key.data;
  366.         name->key_hash = hinit->key(name->key.data, name->key.len);
  367.         name->value = names[n].value;

  368. #if 0
  369.         ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
  370.                       "wc1: \"%V\" %ui", &name->key, dot);
  371. #endif

  372.         dot_len = len + 1;

  373.         if (dot) {
  374.             len++;
  375.         }

  376.         next_names.nelts = 0;

  377.         if (names[n].key.len != len) {
  378.             next_name = ngx_array_push(&next_names);
  379.             if (next_name == NULL) {
  380.                 return NGX_ERROR;
  381.             }

  382.             next_name->key.len = names[n].key.len - len;
  383.             next_name->key.data = names[n].key.data + len;
  384.             next_name->key_hash = 0;
  385.             next_name->value = names[n].value;

  386. #if 0
  387.             ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
  388.                           "wc2: \"%V\"", &next_name->key);
  389. #endif
  390.         }

  391.         for (i = n + 1; i < nelts; i++) {
  392.             if (ngx_strncmp(names[n].key.data, names[i].key.data, len) != 0) {
  393.                 break;
  394.             }

  395.             if (!dot
  396.                 && names[i].key.len > len
  397.                 && names[i].key.data[len] != '.')
  398.             {
  399.                 break;
  400.             }

  401.             next_name = ngx_array_push(&next_names);
  402.             if (next_name == NULL) {
  403.                 return NGX_ERROR;
  404.             }

  405.             next_name->key.len = names[i].key.len - dot_len;
  406.             next_name->key.data = names[i].key.data + dot_len;
  407.             next_name->key_hash = 0;
  408.             next_name->value = names[i].value;

  409. #if 0
  410.             ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0,
  411.                           "wc3: \"%V\"", &next_name->key);
  412. #endif
  413.         }

  414.         if (next_names.nelts) {

  415.             h = *hinit;
  416.             h.hash = NULL;

  417.             if (ngx_hash_wildcard_init(&h, (ngx_hash_key_t *) next_names.elts,
  418.                                        next_names.nelts)
  419.                 != NGX_OK)
  420.             {
  421.                 return NGX_ERROR;
  422.             }

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

  424.             if (names[n].key.len == len) {
  425.                 wdc->value = names[n].value;
  426.             }

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

  428.         } else if (dot) {
  429.             name->value = (void *) ((uintptr_t) name->value | 1);
  430.         }
  431.     }

  432.     if (ngx_hash_init(hinit, (ngx_hash_key_t *) curr_names.elts,
  433.                       curr_names.nelts)
  434.         != NGX_OK)
  435.     {
  436.         return NGX_ERROR;
  437.     }

  438.     return NGX_OK;
  439. }


  440. ngx_uint_t
  441. ngx_hash_key(u_char *data, size_t len)
  442. {
  443.     ngx_uint_t  i, key;

  444.     key = 0;

  445.     for (i = 0; i < len; i++) {
  446.         key = ngx_hash(key, data[i]);
  447.     }

  448.     return key;
  449. }


  450. ngx_uint_t
  451. ngx_hash_key_lc(u_char *data, size_t len)
  452. {
  453.     ngx_uint_t  i, key;

  454.     key = 0;

  455.     for (i = 0; i < len; i++) {
  456.         key = ngx_hash(key, ngx_tolower(data[i]));
  457.     }

  458.     return key;
  459. }


  460. ngx_uint_t
  461. ngx_hash_strlow(u_char *dst, u_char *src, size_t n)
  462. {
  463.     ngx_uint_t  key;

  464.     key = 0;

  465.     while (n--) {
  466.         *dst = ngx_tolower(*src);
  467.         key = ngx_hash(key, *dst);
  468.         dst++;
  469.         src++;
  470.     }

  471.     return key;
  472. }


  473. ngx_int_t
  474. ngx_hash_keys_array_init(ngx_hash_keys_arrays_t *ha, ngx_uint_t type)
  475. {
  476.     ngx_uint_t  asize;

  477.     if (type == NGX_HASH_SMALL) {
  478.         asize = 4;
  479.         ha->hsize = 107;

  480.     } else {
  481.         asize = NGX_HASH_LARGE_ASIZE;
  482.         ha->hsize = NGX_HASH_LARGE_HSIZE;
  483.     }

  484.     if (ngx_array_init(&ha->keys, ha->temp_pool, asize, sizeof(ngx_hash_key_t))
  485.         != NGX_OK)
  486.     {
  487.         return NGX_ERROR;
  488.     }

  489.     if (ngx_array_init(&ha->dns_wc_head, ha->temp_pool, asize,
  490.                        sizeof(ngx_hash_key_t))
  491.         != NGX_OK)
  492.     {
  493.         return NGX_ERROR;
  494.     }

  495.     if (ngx_array_init(&ha->dns_wc_tail, ha->temp_pool, asize,
  496.                        sizeof(ngx_hash_key_t))
  497.         != NGX_OK)
  498.     {
  499.         return NGX_ERROR;
  500.     }

  501.     ha->keys_hash = ngx_pcalloc(ha->temp_pool, sizeof(ngx_array_t) * ha->hsize);
  502.     if (ha->keys_hash == NULL) {
  503.         return NGX_ERROR;
  504.     }

  505.     ha->dns_wc_head_hash = ngx_pcalloc(ha->temp_pool,
  506.                                        sizeof(ngx_array_t) * ha->hsize);
  507.     if (ha->dns_wc_head_hash == NULL) {
  508.         return NGX_ERROR;
  509.     }

  510.     ha->dns_wc_tail_hash = ngx_pcalloc(ha->temp_pool,
  511.                                        sizeof(ngx_array_t) * ha->hsize);
  512.     if (ha->dns_wc_tail_hash == NULL) {
  513.         return NGX_ERROR;
  514.     }

  515.     return NGX_OK;
  516. }


  517. ngx_int_t
  518. ngx_hash_add_key(ngx_hash_keys_arrays_t *ha, ngx_str_t *key, void *value,
  519.     ngx_uint_t flags)
  520. {
  521.     size_t           len;
  522.     u_char          *p;
  523.     ngx_str_t       *name;
  524.     ngx_uint_t       i, k, n, skip, last;
  525.     ngx_array_t     *keys, *hwc;
  526.     ngx_hash_key_t  *hk;

  527.     last = key->len;

  528.     if (flags & NGX_HASH_WILDCARD_KEY) {

  529.         /*
  530.          * supported wildcards:
  531.          *     "*.example.com", ".example.com", and "www.example.*"
  532.          */

  533.         n = 0;

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

  535.             if (key->data[i] == '*') {
  536.                 if (++n > 1) {
  537.                     return NGX_DECLINED;
  538.                 }
  539.             }

  540.             if (key->data[i] == '.' && key->data[i + 1] == '.') {
  541.                 return NGX_DECLINED;
  542.             }
  543.         }

  544.         if (key->len > 1 && key->data[0] == '.') {
  545.             skip = 1;
  546.             goto wildcard;
  547.         }

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

  549.             if (key->data[0] == '*' && key->data[1] == '.') {
  550.                 skip = 2;
  551.                 goto wildcard;
  552.             }

  553.             if (key->data[i - 2] == '.' && key->data[i - 1] == '*') {
  554.                 skip = 0;
  555.                 last -= 2;
  556.                 goto wildcard;
  557.             }
  558.         }

  559.         if (n) {
  560.             return NGX_DECLINED;
  561.         }
  562.     }

  563.     /* exact hash */

  564.     k = 0;

  565.     for (i = 0; i < last; i++) {
  566.         if (!(flags & NGX_HASH_READONLY_KEY)) {
  567.             key->data[i] = ngx_tolower(key->data[i]);
  568.         }
  569.         k = ngx_hash(k, key->data[i]);
  570.     }

  571.     k %= ha->hsize;

  572.     /* check conflicts in exact hash */

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

  574.     if (name) {
  575.         for (i = 0; i < ha->keys_hash[k].nelts; i++) {
  576.             if (last != name[i].len) {
  577.                 continue;
  578.             }

  579.             if (ngx_strncmp(key->data, name[i].data, last) == 0) {
  580.                 return NGX_BUSY;
  581.             }
  582.         }

  583.     } else {
  584.         if (ngx_array_init(&ha->keys_hash[k], ha->temp_pool, 4,
  585.                            sizeof(ngx_str_t))
  586.             != NGX_OK)
  587.         {
  588.             return NGX_ERROR;
  589.         }
  590.     }

  591.     name = ngx_array_push(&ha->keys_hash[k]);
  592.     if (name == NULL) {
  593.         return NGX_ERROR;
  594.     }

  595.     *name = *key;

  596.     hk = ngx_array_push(&ha->keys);
  597.     if (hk == NULL) {
  598.         return NGX_ERROR;
  599.     }

  600.     hk->key = *key;
  601.     hk->key_hash = ngx_hash_key(key->data, last);
  602.     hk->value = value;

  603.     return NGX_OK;


  604. wildcard:

  605.     /* wildcard hash */

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

  607.     k %= ha->hsize;

  608.     if (skip == 1) {

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

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

  611.         if (name) {
  612.             len = last - skip;

  613.             for (i = 0; i < ha->keys_hash[k].nelts; i++) {
  614.                 if (len != name[i].len) {
  615.                     continue;
  616.                 }

  617.                 if (ngx_strncmp(&key->data[1], name[i].data, len) == 0) {
  618.                     return NGX_BUSY;
  619.                 }
  620.             }

  621.         } else {
  622.             if (ngx_array_init(&ha->keys_hash[k], ha->temp_pool, 4,
  623.                                sizeof(ngx_str_t))
  624.                 != NGX_OK)
  625.             {
  626.                 return NGX_ERROR;
  627.             }
  628.         }

  629.         name = ngx_array_push(&ha->keys_hash[k]);
  630.         if (name == NULL) {
  631.             return NGX_ERROR;
  632.         }

  633.         name->len = last - 1;
  634.         name->data = ngx_pnalloc(ha->temp_pool, name->len);
  635.         if (name->data == NULL) {
  636.             return NGX_ERROR;
  637.         }

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


  640.     if (skip) {

  641.         /*
  642.          * convert "*.example.com" to "com.example.\0"
  643.          *      and ".example.com" to "com.example\0"
  644.          */

  645.         p = ngx_pnalloc(ha->temp_pool, last);
  646.         if (p == NULL) {
  647.             return NGX_ERROR;
  648.         }

  649.         len = 0;
  650.         n = 0;

  651.         for (i = last - 1; i; i--) {
  652.             if (key->data[i] == '.') {
  653.                 ngx_memcpy(&p[n], &key->data[i + 1], len);
  654.                 n += len;
  655.                 p[n++] = '.';
  656.                 len = 0;
  657.                 continue;
  658.             }

  659.             len++;
  660.         }

  661.         if (len) {
  662.             ngx_memcpy(&p[n], &key->data[1], len);
  663.             n += len;
  664.         }

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

  666.         hwc = &ha->dns_wc_head;
  667.         keys = &ha->dns_wc_head_hash[k];

  668.     } else {

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

  670.         last++;

  671.         p = ngx_pnalloc(ha->temp_pool, last);
  672.         if (p == NULL) {
  673.             return NGX_ERROR;
  674.         }

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

  676.         hwc = &ha->dns_wc_tail;
  677.         keys = &ha->dns_wc_tail_hash[k];
  678.     }


  679.     /* check conflicts in wildcard hash */

  680.     name = keys->elts;

  681.     if (name) {
  682.         len = last - skip;

  683.         for (i = 0; i < keys->nelts; i++) {
  684.             if (len != name[i].len) {
  685.                 continue;
  686.             }

  687.             if (ngx_strncmp(key->data + skip, name[i].data, len) == 0) {
  688.                 return NGX_BUSY;
  689.             }
  690.         }

  691.     } else {
  692.         if (ngx_array_init(keys, ha->temp_pool, 4, sizeof(ngx_str_t)) != NGX_OK)
  693.         {
  694.             return NGX_ERROR;
  695.         }
  696.     }

  697.     name = ngx_array_push(keys);
  698.     if (name == NULL) {
  699.         return NGX_ERROR;
  700.     }

  701.     name->len = last - skip;
  702.     name->data = ngx_pnalloc(ha->temp_pool, name->len);
  703.     if (name->data == NULL) {
  704.         return NGX_ERROR;
  705.     }

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


  707.     /* add to wildcard hash */

  708.     hk = ngx_array_push(hwc);
  709.     if (hk == NULL) {
  710.         return NGX_ERROR;
  711.     }

  712.     hk->key.len = last - 1;
  713.     hk->key.data = p;
  714.     hk->key_hash = 0;
  715.     hk->value = value;

  716.     return NGX_OK;
  717. }