xref: /unit/src/nxt_var.c (revision 2124)
11563Svbart@nginx.com 
21563Svbart@nginx.com /*
31563Svbart@nginx.com  * Copyright (C) NGINX, Inc.
41563Svbart@nginx.com  */
51563Svbart@nginx.com 
61563Svbart@nginx.com #include <nxt_main.h>
71563Svbart@nginx.com 
81563Svbart@nginx.com 
91563Svbart@nginx.com struct nxt_var_s {
101953Sz.hong@f5.com     size_t              length;
111953Sz.hong@f5.com     nxt_uint_t          vars;
121959Sz.hong@f5.com     uint8_t             strz;  /* 1 bit */
131953Sz.hong@f5.com     u_char              data[];
141563Svbart@nginx.com 
151563Svbart@nginx.com /*
161953Sz.hong@f5.com     nxt_var_sub_t       subs[vars];
171953Sz.hong@f5.com     u_char              raw[length];
181563Svbart@nginx.com */
191563Svbart@nginx.com };
201563Svbart@nginx.com 
211563Svbart@nginx.com 
221563Svbart@nginx.com typedef struct {
231953Sz.hong@f5.com     uint32_t            index;
241953Sz.hong@f5.com     uint32_t            length;
251953Sz.hong@f5.com     uint32_t            position;
261953Sz.hong@f5.com } nxt_var_sub_t;
271953Sz.hong@f5.com 
281953Sz.hong@f5.com 
291953Sz.hong@f5.com typedef struct {
301953Sz.hong@f5.com     nxt_var_t           *var;
311953Sz.hong@f5.com     nxt_str_t           *value;
321563Svbart@nginx.com } nxt_var_value_t;
331563Svbart@nginx.com 
341563Svbart@nginx.com 
351563Svbart@nginx.com struct nxt_var_query_s {
361563Svbart@nginx.com     nxt_array_t         values;   /* of nxt_var_value_t */
371563Svbart@nginx.com     nxt_array_t         parts;    /* of nxt_str_t * */
381563Svbart@nginx.com 
391563Svbart@nginx.com     nxt_lvlhsh_t        cache;
401563Svbart@nginx.com 
411563Svbart@nginx.com     nxt_str_t           *spare;
421563Svbart@nginx.com     nxt_uint_t          waiting;
431563Svbart@nginx.com     nxt_uint_t          failed;   /* 1 bit */
441563Svbart@nginx.com 
451563Svbart@nginx.com     void                *ctx;
461563Svbart@nginx.com     void                *data;
471563Svbart@nginx.com 
481563Svbart@nginx.com     nxt_work_handler_t  ready;
491563Svbart@nginx.com     nxt_work_handler_t  error;
501563Svbart@nginx.com };
511563Svbart@nginx.com 
521563Svbart@nginx.com 
531953Sz.hong@f5.com #define nxt_var_subs(var)  ((nxt_var_sub_t *) (var)->data)
541563Svbart@nginx.com 
551953Sz.hong@f5.com #define nxt_var_raw_start(var)                                                \
561953Sz.hong@f5.com     ((var)->data + (var)->vars * sizeof(nxt_var_sub_t))
571563Svbart@nginx.com 
581563Svbart@nginx.com 
591563Svbart@nginx.com static nxt_int_t nxt_var_hash_test(nxt_lvlhsh_query_t *lhq, void *data);
601563Svbart@nginx.com static nxt_var_decl_t *nxt_var_hash_find(nxt_str_t *name);
611563Svbart@nginx.com 
621563Svbart@nginx.com static nxt_int_t nxt_var_cache_test(nxt_lvlhsh_query_t *lhq, void *data);
631563Svbart@nginx.com static nxt_str_t *nxt_var_cache_find(nxt_lvlhsh_t *lh, uint32_t index);
641563Svbart@nginx.com static nxt_int_t nxt_var_cache_add(nxt_lvlhsh_t *lh, uint32_t index,
651563Svbart@nginx.com     nxt_str_t *value, nxt_mp_t *mp);
661563Svbart@nginx.com 
671563Svbart@nginx.com static u_char *nxt_var_next_part(u_char *start, size_t length, nxt_str_t *part,
681563Svbart@nginx.com     nxt_bool_t *is_var);
691563Svbart@nginx.com 
701563Svbart@nginx.com static void nxt_var_query_finish(nxt_task_t *task, nxt_var_query_t *query);
711563Svbart@nginx.com 
721563Svbart@nginx.com 
731563Svbart@nginx.com static const nxt_lvlhsh_proto_t  nxt_var_hash_proto  nxt_aligned(64) = {
741563Svbart@nginx.com     NXT_LVLHSH_DEFAULT,
751563Svbart@nginx.com     nxt_var_hash_test,
761563Svbart@nginx.com     nxt_lvlhsh_alloc,
771563Svbart@nginx.com     nxt_lvlhsh_free,
781563Svbart@nginx.com };
791563Svbart@nginx.com 
801563Svbart@nginx.com static const nxt_lvlhsh_proto_t  nxt_var_cache_proto  nxt_aligned(64) = {
811563Svbart@nginx.com     NXT_LVLHSH_DEFAULT,
821563Svbart@nginx.com     nxt_var_cache_test,
831563Svbart@nginx.com     nxt_mp_lvlhsh_alloc,
841563Svbart@nginx.com     nxt_mp_lvlhsh_free,
851563Svbart@nginx.com };
861563Svbart@nginx.com 
871563Svbart@nginx.com 
881563Svbart@nginx.com static nxt_lvlhsh_t       nxt_var_hash;
891563Svbart@nginx.com static uint32_t           nxt_var_count;
901563Svbart@nginx.com 
911563Svbart@nginx.com static nxt_var_handler_t  *nxt_var_index;
921563Svbart@nginx.com 
931563Svbart@nginx.com 
941954Sz.hong@f5.com void
951954Sz.hong@f5.com nxt_var_raw(nxt_var_t *var, nxt_str_t *str)
961954Sz.hong@f5.com {
971954Sz.hong@f5.com     str->length = var->length;
981954Sz.hong@f5.com     str->start = nxt_var_raw_start(var);
991954Sz.hong@f5.com }
1001954Sz.hong@f5.com 
1011954Sz.hong@f5.com 
1021954Sz.hong@f5.com nxt_bool_t
1031954Sz.hong@f5.com nxt_var_is_const(nxt_var_t *var)
1041954Sz.hong@f5.com {
1051954Sz.hong@f5.com     return (var->vars == 0);
1061954Sz.hong@f5.com }
1071954Sz.hong@f5.com 
1081954Sz.hong@f5.com 
1091563Svbart@nginx.com static nxt_int_t
1101563Svbart@nginx.com nxt_var_hash_test(nxt_lvlhsh_query_t *lhq, void *data)
1111563Svbart@nginx.com {
1121563Svbart@nginx.com     nxt_var_decl_t  *decl;
1131563Svbart@nginx.com 
1141563Svbart@nginx.com     decl = data;
1151563Svbart@nginx.com 
1161563Svbart@nginx.com     return nxt_strstr_eq(&lhq->key, &decl->name) ? NXT_OK : NXT_DECLINED;
1171563Svbart@nginx.com }
1181563Svbart@nginx.com 
1191563Svbart@nginx.com 
1201563Svbart@nginx.com static nxt_var_decl_t *
1211563Svbart@nginx.com nxt_var_hash_find(nxt_str_t *name)
1221563Svbart@nginx.com {
1231563Svbart@nginx.com     nxt_lvlhsh_query_t  lhq;
1241563Svbart@nginx.com 
1251563Svbart@nginx.com     lhq.key_hash = nxt_djb_hash(name->start, name->length);
1261563Svbart@nginx.com     lhq.key = *name;
1271563Svbart@nginx.com     lhq.proto = &nxt_var_hash_proto;
1281563Svbart@nginx.com 
1291563Svbart@nginx.com     if (nxt_lvlhsh_find(&nxt_var_hash, &lhq) != NXT_OK) {
1301563Svbart@nginx.com         return NULL;
1311563Svbart@nginx.com     }
1321563Svbart@nginx.com 
1331563Svbart@nginx.com     return lhq.value;
1341563Svbart@nginx.com }
1351563Svbart@nginx.com 
1361563Svbart@nginx.com 
1371563Svbart@nginx.com static nxt_int_t
1381563Svbart@nginx.com nxt_var_cache_test(nxt_lvlhsh_query_t *lhq, void *data)
1391563Svbart@nginx.com {
1401563Svbart@nginx.com     return NXT_OK;
1411563Svbart@nginx.com }
1421563Svbart@nginx.com 
1431563Svbart@nginx.com 
1441563Svbart@nginx.com static nxt_str_t *
1451563Svbart@nginx.com nxt_var_cache_find(nxt_lvlhsh_t *lh, uint32_t index)
1461563Svbart@nginx.com {
1471563Svbart@nginx.com     nxt_lvlhsh_query_t  lhq;
1481563Svbart@nginx.com 
1491563Svbart@nginx.com     lhq.key_hash = nxt_murmur_hash2_uint32(&index);
1501563Svbart@nginx.com     lhq.key.length = sizeof(uint32_t);
1511563Svbart@nginx.com     lhq.key.start = (u_char *) &index;
1521563Svbart@nginx.com     lhq.proto = &nxt_var_cache_proto;
1531563Svbart@nginx.com 
1541563Svbart@nginx.com     if (nxt_lvlhsh_find(lh, &lhq) != NXT_OK) {
1551563Svbart@nginx.com         return NULL;
1561563Svbart@nginx.com     }
1571563Svbart@nginx.com 
1581563Svbart@nginx.com     return lhq.value;
1591563Svbart@nginx.com }
1601563Svbart@nginx.com 
1611563Svbart@nginx.com 
1621563Svbart@nginx.com static nxt_int_t
1631563Svbart@nginx.com nxt_var_cache_add(nxt_lvlhsh_t *lh, uint32_t index, nxt_str_t *value,
1641563Svbart@nginx.com     nxt_mp_t *mp)
1651563Svbart@nginx.com {
1661563Svbart@nginx.com     nxt_lvlhsh_query_t  lhq;
1671563Svbart@nginx.com 
1681563Svbart@nginx.com     lhq.key_hash = nxt_murmur_hash2_uint32(&index);
1691563Svbart@nginx.com     lhq.replace = 0;
1701563Svbart@nginx.com     lhq.key.length = sizeof(uint32_t);
1711563Svbart@nginx.com     lhq.key.start = (u_char *) &index;
1721563Svbart@nginx.com     lhq.value = value;
1731563Svbart@nginx.com     lhq.proto = &nxt_var_cache_proto;
1741563Svbart@nginx.com     lhq.pool = mp;
1751563Svbart@nginx.com 
1761563Svbart@nginx.com     return nxt_lvlhsh_insert(lh, &lhq);
1771563Svbart@nginx.com }
1781563Svbart@nginx.com 
1791563Svbart@nginx.com 
1801563Svbart@nginx.com nxt_int_t
1811563Svbart@nginx.com nxt_var_register(nxt_var_decl_t *decl, size_t n)
1821563Svbart@nginx.com {
1831563Svbart@nginx.com     nxt_uint_t          i;
1841563Svbart@nginx.com     nxt_lvlhsh_query_t  lhq;
1851563Svbart@nginx.com 
1861563Svbart@nginx.com     lhq.replace = 0;
1871563Svbart@nginx.com     lhq.proto = &nxt_var_hash_proto;
1881563Svbart@nginx.com 
1891563Svbart@nginx.com     for (i = 0; i < n; i++) {
1901563Svbart@nginx.com         lhq.key = decl[i].name;
1911563Svbart@nginx.com         lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length);
1921563Svbart@nginx.com         lhq.value = &decl[i];
1931563Svbart@nginx.com 
1941563Svbart@nginx.com         if (nxt_slow_path(nxt_lvlhsh_insert(&nxt_var_hash, &lhq) != NXT_OK)) {
1951563Svbart@nginx.com             return NXT_ERROR;
1961563Svbart@nginx.com         }
1971563Svbart@nginx.com     }
1981563Svbart@nginx.com 
1991563Svbart@nginx.com     nxt_var_count += n;
2001563Svbart@nginx.com 
2011563Svbart@nginx.com     return NXT_OK;
2021563Svbart@nginx.com }
2031563Svbart@nginx.com 
2041563Svbart@nginx.com 
2051563Svbart@nginx.com nxt_int_t
2061563Svbart@nginx.com nxt_var_index_init(void)
2071563Svbart@nginx.com {
2081563Svbart@nginx.com     nxt_uint_t         i;
2091563Svbart@nginx.com     nxt_var_decl_t     *decl;
2101563Svbart@nginx.com     nxt_var_handler_t  *index;
2111563Svbart@nginx.com     nxt_lvlhsh_each_t  lhe;
2121563Svbart@nginx.com 
2131563Svbart@nginx.com     index = nxt_memalign(64, nxt_var_count * sizeof(nxt_var_handler_t));
2141563Svbart@nginx.com     if (index == NULL) {
2151563Svbart@nginx.com         return NXT_ERROR;
2161563Svbart@nginx.com     }
2171563Svbart@nginx.com 
2181563Svbart@nginx.com     nxt_lvlhsh_each_init(&lhe, &nxt_var_hash_proto);
2191563Svbart@nginx.com 
2201563Svbart@nginx.com     for (i = 0; i < nxt_var_count; i++) {
2211563Svbart@nginx.com         decl = nxt_lvlhsh_each(&nxt_var_hash, &lhe);
2221563Svbart@nginx.com         decl->index = i;
2231563Svbart@nginx.com         index[i] = decl->handler;
2241563Svbart@nginx.com     }
2251563Svbart@nginx.com 
2261563Svbart@nginx.com     nxt_var_index = index;
2271563Svbart@nginx.com 
2281563Svbart@nginx.com     return NXT_OK;
2291563Svbart@nginx.com }
2301563Svbart@nginx.com 
2311563Svbart@nginx.com 
2321563Svbart@nginx.com nxt_var_t *
2331959Sz.hong@f5.com nxt_var_compile(nxt_str_t *str, nxt_mp_t *mp, nxt_bool_t strz)
2341563Svbart@nginx.com {
2351953Sz.hong@f5.com     u_char          *p, *end, *next, *src;
2361953Sz.hong@f5.com     size_t          size;
2371953Sz.hong@f5.com     nxt_var_t       *var;
2381953Sz.hong@f5.com     nxt_str_t       part;
2391953Sz.hong@f5.com     nxt_uint_t      n;
2401953Sz.hong@f5.com     nxt_bool_t      is_var;
2411953Sz.hong@f5.com     nxt_var_sub_t   *subs;
2421953Sz.hong@f5.com     nxt_var_decl_t  *decl;
2431563Svbart@nginx.com 
2441563Svbart@nginx.com     n = 0;
2451563Svbart@nginx.com 
2461563Svbart@nginx.com     p = str->start;
2471563Svbart@nginx.com     end = p + str->length;
2481563Svbart@nginx.com 
2491563Svbart@nginx.com     while (p < end) {
2501563Svbart@nginx.com         p = nxt_var_next_part(p, end - p, &part, &is_var);
2511563Svbart@nginx.com         if (nxt_slow_path(p == NULL)) {
2521563Svbart@nginx.com             return NULL;
2531563Svbart@nginx.com         }
2541563Svbart@nginx.com 
2551563Svbart@nginx.com         if (is_var) {
2561563Svbart@nginx.com             n++;
2571563Svbart@nginx.com         }
2581563Svbart@nginx.com     }
2591563Svbart@nginx.com 
2601953Sz.hong@f5.com     size = sizeof(nxt_var_t) + n * sizeof(nxt_var_sub_t) + str->length;
2611563Svbart@nginx.com 
2621959Sz.hong@f5.com     var = nxt_mp_get(mp, size + strz);
2631563Svbart@nginx.com     if (nxt_slow_path(var == NULL)) {
2641563Svbart@nginx.com         return NULL;
2651563Svbart@nginx.com     }
2661563Svbart@nginx.com 
2671953Sz.hong@f5.com     var->length = str->length;
2681563Svbart@nginx.com     var->vars = n;
2691959Sz.hong@f5.com     var->strz = strz;
2701563Svbart@nginx.com 
2711953Sz.hong@f5.com     subs = nxt_var_subs(var);
2721953Sz.hong@f5.com     src = nxt_var_raw_start(var);
2731563Svbart@nginx.com 
2741953Sz.hong@f5.com     nxt_memcpy(src, str->start, str->length);
2751953Sz.hong@f5.com 
2761959Sz.hong@f5.com     if (strz) {
2771959Sz.hong@f5.com         src[str->length] = '\0';
2781959Sz.hong@f5.com     }
2791959Sz.hong@f5.com 
2801563Svbart@nginx.com     n = 0;
2811563Svbart@nginx.com     p = str->start;
2821563Svbart@nginx.com 
2831563Svbart@nginx.com     while (p < end) {
2841953Sz.hong@f5.com         next = nxt_var_next_part(p, end - p, &part, &is_var);
2851563Svbart@nginx.com 
2861563Svbart@nginx.com         if (is_var) {
2871563Svbart@nginx.com             decl = nxt_var_hash_find(&part);
2881563Svbart@nginx.com             if (nxt_slow_path(decl == NULL)) {
2891563Svbart@nginx.com                 return NULL;
2901563Svbart@nginx.com             }
2911563Svbart@nginx.com 
2921953Sz.hong@f5.com             subs[n].index = decl->index;
2931953Sz.hong@f5.com             subs[n].length = next - p;
2941953Sz.hong@f5.com             subs[n].position = p - str->start;
2951563Svbart@nginx.com 
2961563Svbart@nginx.com             n++;
2971953Sz.hong@f5.com         }
2981563Svbart@nginx.com 
2991953Sz.hong@f5.com         p = next;
3001563Svbart@nginx.com     }
3011563Svbart@nginx.com 
3021563Svbart@nginx.com     return var;
3031563Svbart@nginx.com }
3041563Svbart@nginx.com 
3051563Svbart@nginx.com 
3061563Svbart@nginx.com nxt_int_t
3071563Svbart@nginx.com nxt_var_test(nxt_str_t *str, u_char *error)
3081563Svbart@nginx.com {
3091563Svbart@nginx.com     u_char          *p, *end, *next;
3101563Svbart@nginx.com     nxt_str_t       part;
3111563Svbart@nginx.com     nxt_bool_t      is_var;
3121563Svbart@nginx.com     nxt_var_decl_t  *decl;
3131563Svbart@nginx.com 
3141563Svbart@nginx.com     p = str->start;
3151563Svbart@nginx.com     end = p + str->length;
3161563Svbart@nginx.com 
3171563Svbart@nginx.com     while (p < end) {
3181563Svbart@nginx.com         next = nxt_var_next_part(p, end - p, &part, &is_var);
3191563Svbart@nginx.com 
3201563Svbart@nginx.com         if (next == NULL) {
3211563Svbart@nginx.com             nxt_sprintf(error, error + NXT_MAX_ERROR_STR,
3221563Svbart@nginx.com                         "Invalid variable at position %uz%Z", p - str->start);
3231563Svbart@nginx.com 
3241563Svbart@nginx.com             return NXT_ERROR;
3251563Svbart@nginx.com         }
3261563Svbart@nginx.com 
3271563Svbart@nginx.com         if (is_var) {
3281563Svbart@nginx.com             decl = nxt_var_hash_find(&part);
3291563Svbart@nginx.com 
3301563Svbart@nginx.com             if (decl == NULL) {
3311563Svbart@nginx.com                 nxt_sprintf(error, error + NXT_MAX_ERROR_STR,
3321563Svbart@nginx.com                             "Unknown variable \"%V\"%Z", &part);
3331563Svbart@nginx.com 
3341563Svbart@nginx.com                 return NXT_ERROR;
3351563Svbart@nginx.com             }
3361563Svbart@nginx.com         }
3371563Svbart@nginx.com 
3381563Svbart@nginx.com         p = next;
3391563Svbart@nginx.com     }
3401563Svbart@nginx.com 
3411563Svbart@nginx.com     return NXT_OK;
3421563Svbart@nginx.com }
3431563Svbart@nginx.com 
3441563Svbart@nginx.com 
3451563Svbart@nginx.com static u_char *
3461563Svbart@nginx.com nxt_var_next_part(u_char *start, size_t length, nxt_str_t *part,
3471563Svbart@nginx.com     nxt_bool_t *is_var)
3481563Svbart@nginx.com {
3491563Svbart@nginx.com     u_char      *p, *end, ch, c;
3501563Svbart@nginx.com     nxt_bool_t  bracket;
3511563Svbart@nginx.com 
3521563Svbart@nginx.com     end = start + length;
3531563Svbart@nginx.com 
3541563Svbart@nginx.com     p = nxt_memchr(start, '$', length);
3551563Svbart@nginx.com 
3561563Svbart@nginx.com     if (p == start) {
3571563Svbart@nginx.com         *is_var = 1;
3581563Svbart@nginx.com 
3591563Svbart@nginx.com         p++;
3601563Svbart@nginx.com 
3611563Svbart@nginx.com         if (p == end) {
3621563Svbart@nginx.com             return NULL;
3631563Svbart@nginx.com         }
3641563Svbart@nginx.com 
3651563Svbart@nginx.com         if (*p == '{') {
3661563Svbart@nginx.com             bracket = 1;
3671563Svbart@nginx.com 
3681563Svbart@nginx.com             if (end - p < 2) {
3691563Svbart@nginx.com                 return NULL;
3701563Svbart@nginx.com             }
3711563Svbart@nginx.com 
3721563Svbart@nginx.com             p++;
3731563Svbart@nginx.com 
3741563Svbart@nginx.com         } else {
3751563Svbart@nginx.com             bracket = 0;
3761563Svbart@nginx.com         }
3771563Svbart@nginx.com 
3781563Svbart@nginx.com         start = p;
3791563Svbart@nginx.com 
3801563Svbart@nginx.com         for ( ;; ) {
3811563Svbart@nginx.com             ch = *p;
3821563Svbart@nginx.com 
3831563Svbart@nginx.com             c = (u_char) (ch | 0x20);
3841563Svbart@nginx.com             if ((c < 'a' || c > 'z') && ch != '_') {
3851563Svbart@nginx.com 
3861563Svbart@nginx.com                 if (bracket && ch != '}') {
3871563Svbart@nginx.com                     return NULL;
3881563Svbart@nginx.com                 }
3891563Svbart@nginx.com 
3901563Svbart@nginx.com                 break;
3911563Svbart@nginx.com             }
3921563Svbart@nginx.com 
3931563Svbart@nginx.com             p++;
3941563Svbart@nginx.com 
3951563Svbart@nginx.com             if (p == end) {
3961563Svbart@nginx.com                 if (bracket) {
3971563Svbart@nginx.com                     return NULL;
3981563Svbart@nginx.com                 }
3991563Svbart@nginx.com 
4001563Svbart@nginx.com                 break;
4011563Svbart@nginx.com             }
4021563Svbart@nginx.com         }
4031563Svbart@nginx.com 
4041563Svbart@nginx.com         length = p - start;
4051563Svbart@nginx.com         end = p + bracket;
4061563Svbart@nginx.com 
4071563Svbart@nginx.com     } else {
4081563Svbart@nginx.com         *is_var = 0;
4091563Svbart@nginx.com 
4101563Svbart@nginx.com         if (p != NULL) {
4111563Svbart@nginx.com             length = p - start;
4121563Svbart@nginx.com             end = p;
4131563Svbart@nginx.com         }
4141563Svbart@nginx.com     }
4151563Svbart@nginx.com 
4161563Svbart@nginx.com     part->length = length;
4171563Svbart@nginx.com     part->start = start;
4181563Svbart@nginx.com 
4191563Svbart@nginx.com     return end;
4201563Svbart@nginx.com }
4211563Svbart@nginx.com 
4221563Svbart@nginx.com 
4231563Svbart@nginx.com nxt_int_t
4241563Svbart@nginx.com nxt_var_query_init(nxt_var_query_t **query_p, void *ctx, nxt_mp_t *mp)
4251563Svbart@nginx.com {
4261563Svbart@nginx.com     nxt_var_query_t  *query;
4271563Svbart@nginx.com 
4281563Svbart@nginx.com     query = *query_p;
4291563Svbart@nginx.com 
4301563Svbart@nginx.com     if (*query_p == NULL) {
4311563Svbart@nginx.com         query = nxt_mp_zget(mp, sizeof(nxt_var_query_t));
4321563Svbart@nginx.com         if (nxt_slow_path(query == NULL)) {
4331563Svbart@nginx.com             return NXT_ERROR;
4341563Svbart@nginx.com         }
4351563Svbart@nginx.com 
4361563Svbart@nginx.com         nxt_array_init(&query->values, mp, sizeof(nxt_var_value_t));
4371563Svbart@nginx.com         nxt_array_init(&query->parts, mp, sizeof(nxt_str_t *));
4381563Svbart@nginx.com 
4391563Svbart@nginx.com     } else {
4401563Svbart@nginx.com         nxt_array_reset(&query->values);
4411563Svbart@nginx.com     }
4421563Svbart@nginx.com 
4431563Svbart@nginx.com     query->ctx = ctx;
4441563Svbart@nginx.com 
4451563Svbart@nginx.com     *query_p = query;
4461563Svbart@nginx.com 
4471563Svbart@nginx.com     return NXT_OK;
4481563Svbart@nginx.com }
4491563Svbart@nginx.com 
4501563Svbart@nginx.com 
4511563Svbart@nginx.com void
4521563Svbart@nginx.com nxt_var_query(nxt_task_t *task, nxt_var_query_t *query, nxt_var_t *var,
4531563Svbart@nginx.com     nxt_str_t *str)
4541563Svbart@nginx.com {
4551953Sz.hong@f5.com     uint32_t         index;
4561953Sz.hong@f5.com     nxt_mp_t         *mp;
4571953Sz.hong@f5.com     nxt_str_t        *value;
4581953Sz.hong@f5.com     nxt_int_t        ret;
4591953Sz.hong@f5.com     nxt_uint_t       i;
4601953Sz.hong@f5.com     nxt_var_sub_t    *subs;
4611953Sz.hong@f5.com     nxt_var_value_t  *val;
4621563Svbart@nginx.com 
4631954Sz.hong@f5.com     if (nxt_var_is_const(var)) {
4641954Sz.hong@f5.com         nxt_var_raw(var, str);
4651563Svbart@nginx.com         return;
4661563Svbart@nginx.com     }
4671563Svbart@nginx.com 
4681563Svbart@nginx.com     if (nxt_slow_path(query->failed)) {
4691563Svbart@nginx.com         return;
4701563Svbart@nginx.com     }
4711563Svbart@nginx.com 
4721563Svbart@nginx.com     mp = query->values.mem_pool;
4731953Sz.hong@f5.com     subs = nxt_var_subs(var);
4741563Svbart@nginx.com     value = query->spare;
4751563Svbart@nginx.com 
4761563Svbart@nginx.com     for (i = 0; i < var->vars; i++) {
4771563Svbart@nginx.com 
4781563Svbart@nginx.com         if (value == NULL) {
4791563Svbart@nginx.com             value = nxt_mp_zget(mp, sizeof(nxt_str_t));
4801563Svbart@nginx.com             if (nxt_slow_path(value == NULL)) {
4811563Svbart@nginx.com                 goto fail;
4821563Svbart@nginx.com             }
4831563Svbart@nginx.com         }
4841563Svbart@nginx.com 
4851953Sz.hong@f5.com         index = subs[i].index;
4861953Sz.hong@f5.com 
4871953Sz.hong@f5.com         ret = nxt_var_cache_add(&query->cache, index, value, mp);
4881563Svbart@nginx.com 
4891563Svbart@nginx.com         if (ret != NXT_OK) {
4901563Svbart@nginx.com             if (nxt_slow_path(ret == NXT_ERROR)) {
4911563Svbart@nginx.com                 goto fail;
4921563Svbart@nginx.com             }
4931563Svbart@nginx.com 
4941563Svbart@nginx.com             continue;  /* NXT_DECLINED */
4951563Svbart@nginx.com         }
4961563Svbart@nginx.com 
497*2124Sz.hong@f5.com         ret = nxt_var_index[index](task, value, query->ctx);
498*2124Sz.hong@f5.com         if (nxt_slow_path(ret != NXT_OK)) {
499*2124Sz.hong@f5.com             goto fail;
500*2124Sz.hong@f5.com         }
5011563Svbart@nginx.com 
5021563Svbart@nginx.com         value = NULL;
5031563Svbart@nginx.com     }
5041563Svbart@nginx.com 
5051563Svbart@nginx.com     query->spare = value;
5061563Svbart@nginx.com 
5071563Svbart@nginx.com     val = nxt_array_add(&query->values);
5081563Svbart@nginx.com     if (nxt_slow_path(val == NULL)) {
5091563Svbart@nginx.com         goto fail;
5101563Svbart@nginx.com     }
5111563Svbart@nginx.com 
5121563Svbart@nginx.com     val->var = var;
5131563Svbart@nginx.com     val->value = str;
5141563Svbart@nginx.com 
5151563Svbart@nginx.com     return;
5161563Svbart@nginx.com 
5171563Svbart@nginx.com fail:
5181563Svbart@nginx.com 
5191563Svbart@nginx.com     query->failed = 1;
5201563Svbart@nginx.com }
5211563Svbart@nginx.com 
5221563Svbart@nginx.com 
5231563Svbart@nginx.com void
5241563Svbart@nginx.com nxt_var_query_resolve(nxt_task_t *task, nxt_var_query_t *query, void *data,
5251563Svbart@nginx.com     nxt_work_handler_t ready, nxt_work_handler_t error)
5261563Svbart@nginx.com {
5271563Svbart@nginx.com     query->data = data;
5281563Svbart@nginx.com     query->ready = ready;
5291563Svbart@nginx.com     query->error = error;
5301563Svbart@nginx.com 
5311563Svbart@nginx.com     if (query->waiting == 0) {
5321563Svbart@nginx.com         nxt_var_query_finish(task, query);
5331563Svbart@nginx.com     }
5341563Svbart@nginx.com }
5351563Svbart@nginx.com 
5361563Svbart@nginx.com 
5371563Svbart@nginx.com void
5381563Svbart@nginx.com nxt_var_query_handle(nxt_task_t *task, nxt_var_query_t *query,
5391563Svbart@nginx.com     nxt_bool_t failed)
5401563Svbart@nginx.com {
5411563Svbart@nginx.com     query->failed |= failed;
5421563Svbart@nginx.com 
5431563Svbart@nginx.com     if (--query->waiting == 0) {
5441563Svbart@nginx.com         nxt_var_query_finish(task, query);
5451563Svbart@nginx.com     }
5461563Svbart@nginx.com }
5471563Svbart@nginx.com 
5481563Svbart@nginx.com 
5491563Svbart@nginx.com static void
5501563Svbart@nginx.com nxt_var_query_finish(nxt_task_t *task, nxt_var_query_t *query)
5511563Svbart@nginx.com {
5521953Sz.hong@f5.com     u_char           *p, *src;
5531953Sz.hong@f5.com     size_t           length, last, next;
5541953Sz.hong@f5.com     nxt_str_t        *str, **part;
5551953Sz.hong@f5.com     nxt_var_t        *var;
5561953Sz.hong@f5.com     nxt_uint_t       i, j;
5571953Sz.hong@f5.com     nxt_var_sub_t    *subs;
5581953Sz.hong@f5.com     nxt_var_value_t  *val;
5591563Svbart@nginx.com 
5601563Svbart@nginx.com     if (query->failed) {
5611563Svbart@nginx.com         goto done;
5621563Svbart@nginx.com     }
5631563Svbart@nginx.com 
5641563Svbart@nginx.com     val = query->values.elts;
5651563Svbart@nginx.com 
5661563Svbart@nginx.com     for (i = 0; i < query->values.nelts; i++) {
5671563Svbart@nginx.com         var = val[i].var;
5681563Svbart@nginx.com 
5691953Sz.hong@f5.com         subs = nxt_var_subs(var);
5701953Sz.hong@f5.com         length = var->length;
5711563Svbart@nginx.com 
5721563Svbart@nginx.com         for (j = 0; j < var->vars; j++) {
5731953Sz.hong@f5.com             str = nxt_var_cache_find(&query->cache, subs[j].index);
5741563Svbart@nginx.com 
5751563Svbart@nginx.com             nxt_assert(str != NULL);
5761563Svbart@nginx.com 
5771563Svbart@nginx.com             part = nxt_array_add(&query->parts);
5781563Svbart@nginx.com 
5791563Svbart@nginx.com             if (nxt_slow_path(part == NULL)) {
5801563Svbart@nginx.com                 query->failed = 1;
5811563Svbart@nginx.com                 goto done;
5821563Svbart@nginx.com             }
5831563Svbart@nginx.com 
5841563Svbart@nginx.com             *part = str;
5851563Svbart@nginx.com 
5861953Sz.hong@f5.com             length += str->length - subs[j].length;
5871563Svbart@nginx.com         }
5881563Svbart@nginx.com 
5891959Sz.hong@f5.com         p = nxt_mp_nget(query->values.mem_pool, length + var->strz);
5901563Svbart@nginx.com         if (nxt_slow_path(p == NULL)) {
5911563Svbart@nginx.com             query->failed = 1;
5921563Svbart@nginx.com             goto done;
5931563Svbart@nginx.com         }
5941563Svbart@nginx.com 
5951563Svbart@nginx.com         val[i].value->length = length;
5961563Svbart@nginx.com         val[i].value->start = p;
5971563Svbart@nginx.com 
5981563Svbart@nginx.com         part = query->parts.elts;
5991953Sz.hong@f5.com         src = nxt_var_raw_start(var);
6001563Svbart@nginx.com 
6011953Sz.hong@f5.com         last = 0;
6021563Svbart@nginx.com 
6031563Svbart@nginx.com         for (j = 0; j < var->vars; j++) {
6041953Sz.hong@f5.com             next = subs[j].position;
6051563Svbart@nginx.com 
6061953Sz.hong@f5.com             if (next != last) {
6071953Sz.hong@f5.com                 p = nxt_cpymem(p, &src[last], next - last);
6081563Svbart@nginx.com             }
6091563Svbart@nginx.com 
6101563Svbart@nginx.com             p = nxt_cpymem(p, part[j]->start, part[j]->length);
6111953Sz.hong@f5.com 
6121953Sz.hong@f5.com             last = next + subs[j].length;
6131563Svbart@nginx.com         }
6141563Svbart@nginx.com 
6151953Sz.hong@f5.com         if (last != var->length) {
6161959Sz.hong@f5.com             p = nxt_cpymem(p, &src[last], var->length - last);
6171959Sz.hong@f5.com         }
6181959Sz.hong@f5.com 
6191959Sz.hong@f5.com         if (var->strz) {
6201959Sz.hong@f5.com             *p = '\0';
6211563Svbart@nginx.com         }
6221563Svbart@nginx.com 
6231563Svbart@nginx.com         nxt_array_reset(&query->parts);
6241959Sz.hong@f5.com 
6252052Sz.hong@f5.com         nxt_debug(task, "var: \"%*s\" -> \"%V\"", var->length, src,
6262052Sz.hong@f5.com                   val[i].value);
6271563Svbart@nginx.com     }
6281563Svbart@nginx.com 
6291563Svbart@nginx.com done:
6301563Svbart@nginx.com 
6311563Svbart@nginx.com     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
6321563Svbart@nginx.com                        query->failed ? query->error : query->ready,
6331563Svbart@nginx.com                        task, query->ctx, query->data);
6341563Svbart@nginx.com }
635