xref: /unit/src/nxt_var.c (revision 2166:64a3527f65ad)
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;
12*2166Sz.hong@f5.com     nxt_var_flags_t     flags;
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 
291563Svbart@nginx.com struct nxt_var_query_s {
302146Sz.hong@f5.com     nxt_mp_t            *pool;
311563Svbart@nginx.com 
321563Svbart@nginx.com     nxt_lvlhsh_t        cache;
332146Sz.hong@f5.com     nxt_str_t           *spare;
341563Svbart@nginx.com 
351563Svbart@nginx.com     nxt_uint_t          waiting;
361563Svbart@nginx.com     nxt_uint_t          failed;   /* 1 bit */
371563Svbart@nginx.com 
381563Svbart@nginx.com     void                *ctx;
391563Svbart@nginx.com     void                *data;
401563Svbart@nginx.com 
411563Svbart@nginx.com     nxt_work_handler_t  ready;
421563Svbart@nginx.com     nxt_work_handler_t  error;
431563Svbart@nginx.com };
441563Svbart@nginx.com 
451563Svbart@nginx.com 
461953Sz.hong@f5.com #define nxt_var_subs(var)  ((nxt_var_sub_t *) (var)->data)
471563Svbart@nginx.com 
481953Sz.hong@f5.com #define nxt_var_raw_start(var)                                                \
491953Sz.hong@f5.com     ((var)->data + (var)->vars * sizeof(nxt_var_sub_t))
501563Svbart@nginx.com 
511563Svbart@nginx.com 
521563Svbart@nginx.com static nxt_int_t nxt_var_hash_test(nxt_lvlhsh_query_t *lhq, void *data);
531563Svbart@nginx.com static nxt_var_decl_t *nxt_var_hash_find(nxt_str_t *name);
541563Svbart@nginx.com 
552147Sz.hong@f5.com static nxt_var_decl_t *nxt_var_decl_get(nxt_str_t *name, nxt_array_t *fields,
562147Sz.hong@f5.com     uint32_t *index);
572147Sz.hong@f5.com static nxt_var_field_t *nxt_var_field_add(nxt_array_t *fields, nxt_str_t *name,
582147Sz.hong@f5.com     uint32_t hash);
592147Sz.hong@f5.com 
601563Svbart@nginx.com static nxt_int_t nxt_var_cache_test(nxt_lvlhsh_query_t *lhq, void *data);
612146Sz.hong@f5.com static nxt_str_t *nxt_var_cache_value(nxt_task_t *task, nxt_var_query_t *query,
622146Sz.hong@f5.com     uint32_t index);
631563Svbart@nginx.com 
641563Svbart@nginx.com static u_char *nxt_var_next_part(u_char *start, size_t length, nxt_str_t *part,
651563Svbart@nginx.com     nxt_bool_t *is_var);
661563Svbart@nginx.com 
671563Svbart@nginx.com 
681563Svbart@nginx.com static const nxt_lvlhsh_proto_t  nxt_var_hash_proto  nxt_aligned(64) = {
691563Svbart@nginx.com     NXT_LVLHSH_DEFAULT,
701563Svbart@nginx.com     nxt_var_hash_test,
711563Svbart@nginx.com     nxt_lvlhsh_alloc,
721563Svbart@nginx.com     nxt_lvlhsh_free,
731563Svbart@nginx.com };
741563Svbart@nginx.com 
751563Svbart@nginx.com static const nxt_lvlhsh_proto_t  nxt_var_cache_proto  nxt_aligned(64) = {
761563Svbart@nginx.com     NXT_LVLHSH_DEFAULT,
771563Svbart@nginx.com     nxt_var_cache_test,
781563Svbart@nginx.com     nxt_mp_lvlhsh_alloc,
791563Svbart@nginx.com     nxt_mp_lvlhsh_free,
801563Svbart@nginx.com };
811563Svbart@nginx.com 
821563Svbart@nginx.com 
831563Svbart@nginx.com static nxt_lvlhsh_t       nxt_var_hash;
841563Svbart@nginx.com static uint32_t           nxt_var_count;
851563Svbart@nginx.com 
861563Svbart@nginx.com static nxt_var_handler_t  *nxt_var_index;
871563Svbart@nginx.com 
881563Svbart@nginx.com 
891563Svbart@nginx.com static nxt_int_t
nxt_var_hash_test(nxt_lvlhsh_query_t * lhq,void * data)901563Svbart@nginx.com nxt_var_hash_test(nxt_lvlhsh_query_t *lhq, void *data)
911563Svbart@nginx.com {
921563Svbart@nginx.com     nxt_var_decl_t  *decl;
931563Svbart@nginx.com 
941563Svbart@nginx.com     decl = data;
951563Svbart@nginx.com 
961563Svbart@nginx.com     return nxt_strstr_eq(&lhq->key, &decl->name) ? NXT_OK : NXT_DECLINED;
971563Svbart@nginx.com }
981563Svbart@nginx.com 
991563Svbart@nginx.com 
1001563Svbart@nginx.com static nxt_var_decl_t *
nxt_var_hash_find(nxt_str_t * name)1011563Svbart@nginx.com nxt_var_hash_find(nxt_str_t *name)
1021563Svbart@nginx.com {
1031563Svbart@nginx.com     nxt_lvlhsh_query_t  lhq;
1041563Svbart@nginx.com 
1051563Svbart@nginx.com     lhq.key_hash = nxt_djb_hash(name->start, name->length);
1061563Svbart@nginx.com     lhq.key = *name;
1071563Svbart@nginx.com     lhq.proto = &nxt_var_hash_proto;
1081563Svbart@nginx.com 
1091563Svbart@nginx.com     if (nxt_lvlhsh_find(&nxt_var_hash, &lhq) != NXT_OK) {
1101563Svbart@nginx.com         return NULL;
1111563Svbart@nginx.com     }
1121563Svbart@nginx.com 
1131563Svbart@nginx.com     return lhq.value;
1141563Svbart@nginx.com }
1151563Svbart@nginx.com 
1161563Svbart@nginx.com 
1172147Sz.hong@f5.com static nxt_var_decl_t *
nxt_var_decl_get(nxt_str_t * name,nxt_array_t * fields,uint32_t * index)1182147Sz.hong@f5.com nxt_var_decl_get(nxt_str_t *name, nxt_array_t *fields, uint32_t *index)
1192147Sz.hong@f5.com {
1202147Sz.hong@f5.com     u_char           *p, *end;
1212147Sz.hong@f5.com     int64_t          hash;
1222147Sz.hong@f5.com     uint16_t         field;
1232147Sz.hong@f5.com     nxt_str_t        str;
1242147Sz.hong@f5.com     nxt_var_decl_t   *decl;
1252147Sz.hong@f5.com     nxt_var_field_t  *f;
1262147Sz.hong@f5.com 
1272147Sz.hong@f5.com     f = NULL;
1282147Sz.hong@f5.com     field = 0;
1292147Sz.hong@f5.com     decl = nxt_var_hash_find(name);
1302147Sz.hong@f5.com 
1312147Sz.hong@f5.com     if (decl == NULL) {
1322147Sz.hong@f5.com         p = name->start;
1332147Sz.hong@f5.com         end = p + name->length;
1342147Sz.hong@f5.com 
1352147Sz.hong@f5.com         while (p < end) {
1362147Sz.hong@f5.com             if (*p++ == '_') {
1372147Sz.hong@f5.com                 break;
1382147Sz.hong@f5.com             }
1392147Sz.hong@f5.com         }
1402147Sz.hong@f5.com 
1412147Sz.hong@f5.com         if (p == end) {
1422147Sz.hong@f5.com             return NULL;
1432147Sz.hong@f5.com         }
1442147Sz.hong@f5.com 
1452147Sz.hong@f5.com         str.start = name->start;
1462147Sz.hong@f5.com         str.length = p - 1 - name->start;
1472147Sz.hong@f5.com 
1482147Sz.hong@f5.com         decl = nxt_var_hash_find(&str);
1492147Sz.hong@f5.com 
1502147Sz.hong@f5.com         if (decl != NULL) {
1512147Sz.hong@f5.com             str.start = p;
1522147Sz.hong@f5.com             str.length = end - p;
1532147Sz.hong@f5.com 
1542147Sz.hong@f5.com             hash = decl->field_hash(fields->mem_pool, &str);
1552147Sz.hong@f5.com             if (nxt_slow_path(hash == -1)) {
1562147Sz.hong@f5.com                 return NULL;
1572147Sz.hong@f5.com             }
1582147Sz.hong@f5.com 
1592147Sz.hong@f5.com             f = nxt_var_field_add(fields, &str, (uint32_t) hash);
1602147Sz.hong@f5.com             if (nxt_slow_path(f == NULL)) {
1612147Sz.hong@f5.com                 return NULL;
1622147Sz.hong@f5.com             }
1632147Sz.hong@f5.com 
1642147Sz.hong@f5.com             field = f->index;
1652147Sz.hong@f5.com         }
1662147Sz.hong@f5.com     }
1672147Sz.hong@f5.com 
1682147Sz.hong@f5.com     if (decl != NULL) {
1692147Sz.hong@f5.com         if (decl->field_hash != NULL && f == NULL) {
1702147Sz.hong@f5.com             return NULL;
1712147Sz.hong@f5.com         }
1722147Sz.hong@f5.com 
1732147Sz.hong@f5.com         if (index != NULL) {
1742147Sz.hong@f5.com             *index = (decl->index << 16) | field;
1752147Sz.hong@f5.com         }
1762147Sz.hong@f5.com     }
1772147Sz.hong@f5.com 
1782147Sz.hong@f5.com     return decl;
1792147Sz.hong@f5.com }
1802147Sz.hong@f5.com 
1812147Sz.hong@f5.com 
1822147Sz.hong@f5.com static nxt_var_field_t *
nxt_var_field_add(nxt_array_t * fields,nxt_str_t * name,uint32_t hash)1832147Sz.hong@f5.com nxt_var_field_add(nxt_array_t *fields, nxt_str_t *name, uint32_t hash)
1842147Sz.hong@f5.com {
1852147Sz.hong@f5.com     nxt_uint_t       i;
1862147Sz.hong@f5.com     nxt_var_field_t  *field;
1872147Sz.hong@f5.com 
1882147Sz.hong@f5.com     field = fields->elts;
1892147Sz.hong@f5.com 
1902147Sz.hong@f5.com     for (i = 0; i < fields->nelts; i++) {
1912147Sz.hong@f5.com         if (field[i].hash == hash
1922147Sz.hong@f5.com             && nxt_strstr_eq(&field[i].name, name))
1932147Sz.hong@f5.com         {
1942147Sz.hong@f5.com             return field;
1952147Sz.hong@f5.com         }
1962147Sz.hong@f5.com     }
1972147Sz.hong@f5.com 
1982147Sz.hong@f5.com     field = nxt_array_add(fields);
1992147Sz.hong@f5.com     if (nxt_slow_path(field == NULL)) {
2002147Sz.hong@f5.com         return NULL;
2012147Sz.hong@f5.com     }
2022147Sz.hong@f5.com 
2032147Sz.hong@f5.com     field->name = *name;
2042147Sz.hong@f5.com     field->hash = hash;
2052147Sz.hong@f5.com     field->index = fields->nelts - 1;
2062147Sz.hong@f5.com 
2072147Sz.hong@f5.com     return field;
2082147Sz.hong@f5.com }
2092147Sz.hong@f5.com 
2102147Sz.hong@f5.com 
2112147Sz.hong@f5.com nxt_var_field_t *
nxt_var_field_get(nxt_array_t * fields,uint16_t index)2122147Sz.hong@f5.com nxt_var_field_get(nxt_array_t *fields, uint16_t index)
2132147Sz.hong@f5.com {
2142147Sz.hong@f5.com     nxt_uint_t       nfields;
2152147Sz.hong@f5.com     nxt_var_field_t  *field;
2162147Sz.hong@f5.com 
2172147Sz.hong@f5.com     field = fields->elts;
2182147Sz.hong@f5.com     nfields = fields->nelts;
2192147Sz.hong@f5.com 
2202147Sz.hong@f5.com     if (nfields > 0 && index <= nfields) {
2212147Sz.hong@f5.com         return &field[index];
2222147Sz.hong@f5.com     }
2232147Sz.hong@f5.com 
2242147Sz.hong@f5.com     return NULL;
2252147Sz.hong@f5.com }
2262147Sz.hong@f5.com 
2272147Sz.hong@f5.com 
2281563Svbart@nginx.com static nxt_int_t
nxt_var_cache_test(nxt_lvlhsh_query_t * lhq,void * data)2291563Svbart@nginx.com nxt_var_cache_test(nxt_lvlhsh_query_t *lhq, void *data)
2301563Svbart@nginx.com {
2311563Svbart@nginx.com     return NXT_OK;
2321563Svbart@nginx.com }
2331563Svbart@nginx.com 
2341563Svbart@nginx.com 
2351563Svbart@nginx.com static nxt_str_t *
nxt_var_cache_value(nxt_task_t * task,nxt_var_query_t * query,uint32_t index)2362146Sz.hong@f5.com nxt_var_cache_value(nxt_task_t *task, nxt_var_query_t *query, uint32_t index)
2371563Svbart@nginx.com {
2382146Sz.hong@f5.com     nxt_int_t           ret;
2392146Sz.hong@f5.com     nxt_str_t           *value;
2401563Svbart@nginx.com     nxt_lvlhsh_query_t  lhq;
2411563Svbart@nginx.com 
2422146Sz.hong@f5.com     value = query->spare;
2431563Svbart@nginx.com 
2442146Sz.hong@f5.com     if (value == NULL) {
2452146Sz.hong@f5.com         value = nxt_mp_zget(query->pool, sizeof(nxt_str_t));
2462146Sz.hong@f5.com         if (nxt_slow_path(value == NULL)) {
2472146Sz.hong@f5.com             return NULL;
2482146Sz.hong@f5.com         }
2491563Svbart@nginx.com 
2502146Sz.hong@f5.com         query->spare = value;
2512146Sz.hong@f5.com     }
2521563Svbart@nginx.com 
2531563Svbart@nginx.com     lhq.key_hash = nxt_murmur_hash2_uint32(&index);
2541563Svbart@nginx.com     lhq.replace = 0;
2551563Svbart@nginx.com     lhq.key.length = sizeof(uint32_t);
2561563Svbart@nginx.com     lhq.key.start = (u_char *) &index;
2571563Svbart@nginx.com     lhq.value = value;
2581563Svbart@nginx.com     lhq.proto = &nxt_var_cache_proto;
2592146Sz.hong@f5.com     lhq.pool = query->pool;
2602146Sz.hong@f5.com 
2612146Sz.hong@f5.com     ret = nxt_lvlhsh_insert(&query->cache, &lhq);
2622146Sz.hong@f5.com     if (nxt_slow_path(ret == NXT_ERROR)) {
2632146Sz.hong@f5.com         return NULL;
2642146Sz.hong@f5.com     }
2651563Svbart@nginx.com 
2662146Sz.hong@f5.com     if (ret == NXT_OK) {
2672147Sz.hong@f5.com         ret = nxt_var_index[index >> 16](task, value, query->ctx,
2682147Sz.hong@f5.com                                          index & 0xffff);
2692146Sz.hong@f5.com         if (nxt_slow_path(ret != NXT_OK)) {
2702146Sz.hong@f5.com             return NULL;
2712146Sz.hong@f5.com         }
2722146Sz.hong@f5.com 
2732146Sz.hong@f5.com         query->spare = NULL;
2742146Sz.hong@f5.com     }
2752146Sz.hong@f5.com 
2762146Sz.hong@f5.com     return lhq.value;
2771563Svbart@nginx.com }
2781563Svbart@nginx.com 
2791563Svbart@nginx.com 
2801563Svbart@nginx.com nxt_int_t
nxt_var_register(nxt_var_decl_t * decl,size_t n)2811563Svbart@nginx.com nxt_var_register(nxt_var_decl_t *decl, size_t n)
2821563Svbart@nginx.com {
2831563Svbart@nginx.com     nxt_uint_t          i;
2841563Svbart@nginx.com     nxt_lvlhsh_query_t  lhq;
2851563Svbart@nginx.com 
2861563Svbart@nginx.com     lhq.replace = 0;
2871563Svbart@nginx.com     lhq.proto = &nxt_var_hash_proto;
2881563Svbart@nginx.com 
2891563Svbart@nginx.com     for (i = 0; i < n; i++) {
2901563Svbart@nginx.com         lhq.key = decl[i].name;
2911563Svbart@nginx.com         lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length);
2921563Svbart@nginx.com         lhq.value = &decl[i];
2931563Svbart@nginx.com 
2941563Svbart@nginx.com         if (nxt_slow_path(nxt_lvlhsh_insert(&nxt_var_hash, &lhq) != NXT_OK)) {
2951563Svbart@nginx.com             return NXT_ERROR;
2961563Svbart@nginx.com         }
2971563Svbart@nginx.com     }
2981563Svbart@nginx.com 
2991563Svbart@nginx.com     nxt_var_count += n;
3001563Svbart@nginx.com 
3011563Svbart@nginx.com     return NXT_OK;
3021563Svbart@nginx.com }
3031563Svbart@nginx.com 
3041563Svbart@nginx.com 
3051563Svbart@nginx.com nxt_int_t
nxt_var_index_init(void)3061563Svbart@nginx.com nxt_var_index_init(void)
3071563Svbart@nginx.com {
3081563Svbart@nginx.com     nxt_uint_t         i;
3091563Svbart@nginx.com     nxt_var_decl_t     *decl;
3101563Svbart@nginx.com     nxt_var_handler_t  *index;
3111563Svbart@nginx.com     nxt_lvlhsh_each_t  lhe;
3121563Svbart@nginx.com 
3131563Svbart@nginx.com     index = nxt_memalign(64, nxt_var_count * sizeof(nxt_var_handler_t));
3141563Svbart@nginx.com     if (index == NULL) {
3151563Svbart@nginx.com         return NXT_ERROR;
3161563Svbart@nginx.com     }
3171563Svbart@nginx.com 
3181563Svbart@nginx.com     nxt_lvlhsh_each_init(&lhe, &nxt_var_hash_proto);
3191563Svbart@nginx.com 
3201563Svbart@nginx.com     for (i = 0; i < nxt_var_count; i++) {
3211563Svbart@nginx.com         decl = nxt_lvlhsh_each(&nxt_var_hash, &lhe);
3221563Svbart@nginx.com         decl->index = i;
3231563Svbart@nginx.com         index[i] = decl->handler;
3241563Svbart@nginx.com     }
3251563Svbart@nginx.com 
3261563Svbart@nginx.com     nxt_var_index = index;
3271563Svbart@nginx.com 
3281563Svbart@nginx.com     return NXT_OK;
3291563Svbart@nginx.com }
3301563Svbart@nginx.com 
3311563Svbart@nginx.com 
3321563Svbart@nginx.com nxt_var_t *
nxt_var_compile(nxt_str_t * str,nxt_mp_t * mp,nxt_array_t * fields,nxt_var_flags_t flags)3332147Sz.hong@f5.com nxt_var_compile(nxt_str_t *str, nxt_mp_t *mp, nxt_array_t *fields,
334*2166Sz.hong@f5.com     nxt_var_flags_t flags)
3351563Svbart@nginx.com {
3361953Sz.hong@f5.com     u_char          *p, *end, *next, *src;
3371953Sz.hong@f5.com     size_t          size;
3382147Sz.hong@f5.com     uint32_t        index;
339*2166Sz.hong@f5.com     nxt_bool_t      strz;
3401953Sz.hong@f5.com     nxt_var_t       *var;
3411953Sz.hong@f5.com     nxt_str_t       part;
3421953Sz.hong@f5.com     nxt_uint_t      n;
3431953Sz.hong@f5.com     nxt_bool_t      is_var;
3441953Sz.hong@f5.com     nxt_var_sub_t   *subs;
3451953Sz.hong@f5.com     nxt_var_decl_t  *decl;
3461563Svbart@nginx.com 
347*2166Sz.hong@f5.com     strz = (flags & NXT_VAR_STRZ) != 0;
348*2166Sz.hong@f5.com 
3491563Svbart@nginx.com     n = 0;
3501563Svbart@nginx.com 
3511563Svbart@nginx.com     p = str->start;
3521563Svbart@nginx.com     end = p + str->length;
3531563Svbart@nginx.com 
3541563Svbart@nginx.com     while (p < end) {
3551563Svbart@nginx.com         p = nxt_var_next_part(p, end - p, &part, &is_var);
3561563Svbart@nginx.com         if (nxt_slow_path(p == NULL)) {
3571563Svbart@nginx.com             return NULL;
3581563Svbart@nginx.com         }
3591563Svbart@nginx.com 
3601563Svbart@nginx.com         if (is_var) {
3611563Svbart@nginx.com             n++;
3621563Svbart@nginx.com         }
3631563Svbart@nginx.com     }
3641563Svbart@nginx.com 
3651953Sz.hong@f5.com     size = sizeof(nxt_var_t) + n * sizeof(nxt_var_sub_t) + str->length;
3661563Svbart@nginx.com 
3671959Sz.hong@f5.com     var = nxt_mp_get(mp, size + strz);
3681563Svbart@nginx.com     if (nxt_slow_path(var == NULL)) {
3691563Svbart@nginx.com         return NULL;
3701563Svbart@nginx.com     }
3711563Svbart@nginx.com 
3721953Sz.hong@f5.com     var->length = str->length;
3731563Svbart@nginx.com     var->vars = n;
374*2166Sz.hong@f5.com     var->flags = flags;
3751563Svbart@nginx.com 
3761953Sz.hong@f5.com     subs = nxt_var_subs(var);
3771953Sz.hong@f5.com     src = nxt_var_raw_start(var);
3781563Svbart@nginx.com 
3791953Sz.hong@f5.com     nxt_memcpy(src, str->start, str->length);
3801953Sz.hong@f5.com 
3811959Sz.hong@f5.com     if (strz) {
3821959Sz.hong@f5.com         src[str->length] = '\0';
3831959Sz.hong@f5.com     }
3841959Sz.hong@f5.com 
3851563Svbart@nginx.com     n = 0;
3861563Svbart@nginx.com     p = str->start;
3871563Svbart@nginx.com 
3881563Svbart@nginx.com     while (p < end) {
3891953Sz.hong@f5.com         next = nxt_var_next_part(p, end - p, &part, &is_var);
3901563Svbart@nginx.com 
3911563Svbart@nginx.com         if (is_var) {
3922147Sz.hong@f5.com             decl = nxt_var_decl_get(&part, fields, &index);
3931563Svbart@nginx.com             if (nxt_slow_path(decl == NULL)) {
3941563Svbart@nginx.com                 return NULL;
3951563Svbart@nginx.com             }
3961563Svbart@nginx.com 
3972147Sz.hong@f5.com             subs[n].index = index;
3981953Sz.hong@f5.com             subs[n].length = next - p;
3991953Sz.hong@f5.com             subs[n].position = p - str->start;
4001563Svbart@nginx.com 
4011563Svbart@nginx.com             n++;
4021953Sz.hong@f5.com         }
4031563Svbart@nginx.com 
4041953Sz.hong@f5.com         p = next;
4051563Svbart@nginx.com     }
4061563Svbart@nginx.com 
4071563Svbart@nginx.com     return var;
4081563Svbart@nginx.com }
4091563Svbart@nginx.com 
4101563Svbart@nginx.com 
4111563Svbart@nginx.com nxt_int_t
nxt_var_test(nxt_str_t * str,nxt_array_t * fields,u_char * error)4122147Sz.hong@f5.com nxt_var_test(nxt_str_t *str, nxt_array_t *fields, u_char *error)
4131563Svbart@nginx.com {
4141563Svbart@nginx.com     u_char          *p, *end, *next;
4151563Svbart@nginx.com     nxt_str_t       part;
4161563Svbart@nginx.com     nxt_bool_t      is_var;
4171563Svbart@nginx.com     nxt_var_decl_t  *decl;
4181563Svbart@nginx.com 
4191563Svbart@nginx.com     p = str->start;
4201563Svbart@nginx.com     end = p + str->length;
4211563Svbart@nginx.com 
4221563Svbart@nginx.com     while (p < end) {
4231563Svbart@nginx.com         next = nxt_var_next_part(p, end - p, &part, &is_var);
4241563Svbart@nginx.com 
4251563Svbart@nginx.com         if (next == NULL) {
4261563Svbart@nginx.com             nxt_sprintf(error, error + NXT_MAX_ERROR_STR,
4271563Svbart@nginx.com                         "Invalid variable at position %uz%Z", p - str->start);
4281563Svbart@nginx.com 
4291563Svbart@nginx.com             return NXT_ERROR;
4301563Svbart@nginx.com         }
4311563Svbart@nginx.com 
4321563Svbart@nginx.com         if (is_var) {
4332147Sz.hong@f5.com             decl = nxt_var_decl_get(&part, fields, NULL);
4341563Svbart@nginx.com 
4351563Svbart@nginx.com             if (decl == NULL) {
4361563Svbart@nginx.com                 nxt_sprintf(error, error + NXT_MAX_ERROR_STR,
4371563Svbart@nginx.com                             "Unknown variable \"%V\"%Z", &part);
4381563Svbart@nginx.com 
4391563Svbart@nginx.com                 return NXT_ERROR;
4401563Svbart@nginx.com             }
4411563Svbart@nginx.com         }
4421563Svbart@nginx.com 
4431563Svbart@nginx.com         p = next;
4441563Svbart@nginx.com     }
4451563Svbart@nginx.com 
4461563Svbart@nginx.com     return NXT_OK;
4471563Svbart@nginx.com }
4481563Svbart@nginx.com 
4491563Svbart@nginx.com 
4501563Svbart@nginx.com static u_char *
nxt_var_next_part(u_char * start,size_t length,nxt_str_t * part,nxt_bool_t * is_var)4511563Svbart@nginx.com nxt_var_next_part(u_char *start, size_t length, nxt_str_t *part,
4521563Svbart@nginx.com     nxt_bool_t *is_var)
4531563Svbart@nginx.com {
4541563Svbart@nginx.com     u_char      *p, *end, ch, c;
4551563Svbart@nginx.com     nxt_bool_t  bracket;
4561563Svbart@nginx.com 
4571563Svbart@nginx.com     end = start + length;
4581563Svbart@nginx.com 
4591563Svbart@nginx.com     p = nxt_memchr(start, '$', length);
4601563Svbart@nginx.com 
4611563Svbart@nginx.com     if (p == start) {
4621563Svbart@nginx.com         *is_var = 1;
4631563Svbart@nginx.com 
4641563Svbart@nginx.com         p++;
4651563Svbart@nginx.com 
4661563Svbart@nginx.com         if (p == end) {
4671563Svbart@nginx.com             return NULL;
4681563Svbart@nginx.com         }
4691563Svbart@nginx.com 
4701563Svbart@nginx.com         if (*p == '{') {
4711563Svbart@nginx.com             bracket = 1;
4721563Svbart@nginx.com 
4731563Svbart@nginx.com             if (end - p < 2) {
4741563Svbart@nginx.com                 return NULL;
4751563Svbart@nginx.com             }
4761563Svbart@nginx.com 
4771563Svbart@nginx.com             p++;
4781563Svbart@nginx.com 
4791563Svbart@nginx.com         } else {
4801563Svbart@nginx.com             bracket = 0;
4811563Svbart@nginx.com         }
4821563Svbart@nginx.com 
4831563Svbart@nginx.com         start = p;
4841563Svbart@nginx.com 
4851563Svbart@nginx.com         for ( ;; ) {
4861563Svbart@nginx.com             ch = *p;
4871563Svbart@nginx.com 
4881563Svbart@nginx.com             c = (u_char) (ch | 0x20);
4891563Svbart@nginx.com             if ((c < 'a' || c > 'z') && ch != '_') {
4901563Svbart@nginx.com 
4911563Svbart@nginx.com                 if (bracket && ch != '}') {
4921563Svbart@nginx.com                     return NULL;
4931563Svbart@nginx.com                 }
4941563Svbart@nginx.com 
4951563Svbart@nginx.com                 break;
4961563Svbart@nginx.com             }
4971563Svbart@nginx.com 
4981563Svbart@nginx.com             p++;
4991563Svbart@nginx.com 
5001563Svbart@nginx.com             if (p == end) {
5011563Svbart@nginx.com                 if (bracket) {
5021563Svbart@nginx.com                     return NULL;
5031563Svbart@nginx.com                 }
5041563Svbart@nginx.com 
5051563Svbart@nginx.com                 break;
5061563Svbart@nginx.com             }
5071563Svbart@nginx.com         }
5081563Svbart@nginx.com 
5091563Svbart@nginx.com         length = p - start;
5101563Svbart@nginx.com         end = p + bracket;
5111563Svbart@nginx.com 
5121563Svbart@nginx.com     } else {
5131563Svbart@nginx.com         *is_var = 0;
5141563Svbart@nginx.com 
5151563Svbart@nginx.com         if (p != NULL) {
5161563Svbart@nginx.com             length = p - start;
5171563Svbart@nginx.com             end = p;
5181563Svbart@nginx.com         }
5191563Svbart@nginx.com     }
5201563Svbart@nginx.com 
5211563Svbart@nginx.com     part->length = length;
5221563Svbart@nginx.com     part->start = start;
5231563Svbart@nginx.com 
5241563Svbart@nginx.com     return end;
5251563Svbart@nginx.com }
5261563Svbart@nginx.com 
5271563Svbart@nginx.com 
5282128Sz.hong@f5.com inline void
nxt_var_raw(nxt_var_t * var,nxt_str_t * str)5292128Sz.hong@f5.com nxt_var_raw(nxt_var_t *var, nxt_str_t *str)
5302128Sz.hong@f5.com {
5312128Sz.hong@f5.com     str->length = var->length;
5322128Sz.hong@f5.com     str->start = nxt_var_raw_start(var);
5332128Sz.hong@f5.com }
5342128Sz.hong@f5.com 
5352128Sz.hong@f5.com 
5362128Sz.hong@f5.com inline nxt_bool_t
nxt_var_is_const(nxt_var_t * var)5372128Sz.hong@f5.com nxt_var_is_const(nxt_var_t *var)
5382128Sz.hong@f5.com {
5392128Sz.hong@f5.com     return (var->vars == 0);
5402128Sz.hong@f5.com }
5412128Sz.hong@f5.com 
5422128Sz.hong@f5.com 
5431563Svbart@nginx.com nxt_int_t
nxt_var_query_init(nxt_var_query_t ** query_p,void * ctx,nxt_mp_t * mp)5441563Svbart@nginx.com nxt_var_query_init(nxt_var_query_t **query_p, void *ctx, nxt_mp_t *mp)
5451563Svbart@nginx.com {
5461563Svbart@nginx.com     nxt_var_query_t  *query;
5471563Svbart@nginx.com 
5481563Svbart@nginx.com     query = *query_p;
5491563Svbart@nginx.com 
5501563Svbart@nginx.com     if (*query_p == NULL) {
5511563Svbart@nginx.com         query = nxt_mp_zget(mp, sizeof(nxt_var_query_t));
5521563Svbart@nginx.com         if (nxt_slow_path(query == NULL)) {
5531563Svbart@nginx.com             return NXT_ERROR;
5541563Svbart@nginx.com         }
5551563Svbart@nginx.com     }
5561563Svbart@nginx.com 
5572146Sz.hong@f5.com     query->pool = mp;
5581563Svbart@nginx.com     query->ctx = ctx;
5591563Svbart@nginx.com 
5601563Svbart@nginx.com     *query_p = query;
5611563Svbart@nginx.com 
5621563Svbart@nginx.com     return NXT_OK;
5631563Svbart@nginx.com }
5641563Svbart@nginx.com 
5651563Svbart@nginx.com 
5661563Svbart@nginx.com void
nxt_var_query(nxt_task_t * task,nxt_var_query_t * query,nxt_var_t * var,nxt_str_t * str)5671563Svbart@nginx.com nxt_var_query(nxt_task_t *task, nxt_var_query_t *query, nxt_var_t *var,
5681563Svbart@nginx.com     nxt_str_t *str)
5691563Svbart@nginx.com {
5702146Sz.hong@f5.com     u_char         *p, *src;
5712146Sz.hong@f5.com     size_t         length, last, next;
5722146Sz.hong@f5.com     nxt_str_t      *value, **part;
5732146Sz.hong@f5.com     nxt_uint_t     i;
574*2166Sz.hong@f5.com     nxt_bool_t     strz, logging;
5752146Sz.hong@f5.com     nxt_array_t    parts;
5762146Sz.hong@f5.com     nxt_var_sub_t  *subs;
5771563Svbart@nginx.com 
5781954Sz.hong@f5.com     if (nxt_var_is_const(var)) {
5791954Sz.hong@f5.com         nxt_var_raw(var, str);
5801563Svbart@nginx.com         return;
5811563Svbart@nginx.com     }
5821563Svbart@nginx.com 
5831563Svbart@nginx.com     if (nxt_slow_path(query->failed)) {
5841563Svbart@nginx.com         return;
5851563Svbart@nginx.com     }
5861563Svbart@nginx.com 
5872146Sz.hong@f5.com     nxt_memzero(&parts, sizeof(nxt_array_t));
5882146Sz.hong@f5.com     nxt_array_init(&parts, query->pool, sizeof(nxt_str_t *));
5892146Sz.hong@f5.com 
590*2166Sz.hong@f5.com     strz = (var->flags & NXT_VAR_STRZ) != 0;
591*2166Sz.hong@f5.com     logging = (var->flags & NXT_VAR_LOGGING) != 0;
592*2166Sz.hong@f5.com 
5931953Sz.hong@f5.com     subs = nxt_var_subs(var);
5942146Sz.hong@f5.com 
5952146Sz.hong@f5.com     length = var->length;
5961563Svbart@nginx.com 
5971563Svbart@nginx.com     for (i = 0; i < var->vars; i++) {
5982146Sz.hong@f5.com         value = nxt_var_cache_value(task, query, subs[i].index);
5992146Sz.hong@f5.com         if (nxt_slow_path(value == NULL)) {
6002146Sz.hong@f5.com             goto fail;
6011563Svbart@nginx.com         }
6021563Svbart@nginx.com 
6032146Sz.hong@f5.com         part = nxt_array_add(&parts);
6042146Sz.hong@f5.com         if (nxt_slow_path(part == NULL)) {
6052124Sz.hong@f5.com             goto fail;
6062124Sz.hong@f5.com         }
6071563Svbart@nginx.com 
6082146Sz.hong@f5.com         *part = value;
6092146Sz.hong@f5.com 
6102146Sz.hong@f5.com         length += value->length - subs[i].length;
611*2166Sz.hong@f5.com 
612*2166Sz.hong@f5.com         if (logging && value->start == NULL) {
613*2166Sz.hong@f5.com             length += 1;
614*2166Sz.hong@f5.com         }
6151563Svbart@nginx.com     }
6161563Svbart@nginx.com 
617*2166Sz.hong@f5.com     p = nxt_mp_nget(query->pool, length + strz);
6182146Sz.hong@f5.com     if (nxt_slow_path(p == NULL)) {
6191563Svbart@nginx.com         goto fail;
6201563Svbart@nginx.com     }
6211563Svbart@nginx.com 
6222146Sz.hong@f5.com     str->length = length;
6232146Sz.hong@f5.com     str->start = p;
6242146Sz.hong@f5.com 
6252146Sz.hong@f5.com     part = parts.elts;
6262146Sz.hong@f5.com     src = nxt_var_raw_start(var);
6272146Sz.hong@f5.com 
6282146Sz.hong@f5.com     last = 0;
6292146Sz.hong@f5.com 
6302146Sz.hong@f5.com     for (i = 0; i < var->vars; i++) {
6312146Sz.hong@f5.com         next = subs[i].position;
6322146Sz.hong@f5.com 
6332146Sz.hong@f5.com         if (next != last) {
6342146Sz.hong@f5.com             p = nxt_cpymem(p, &src[last], next - last);
6352146Sz.hong@f5.com         }
6362146Sz.hong@f5.com 
6372146Sz.hong@f5.com         p = nxt_cpymem(p, part[i]->start, part[i]->length);
6382146Sz.hong@f5.com 
639*2166Sz.hong@f5.com         if (logging && part[i]->start == NULL) {
640*2166Sz.hong@f5.com             *p++ = '-';
641*2166Sz.hong@f5.com         }
642*2166Sz.hong@f5.com 
6432146Sz.hong@f5.com         last = next + subs[i].length;
6442146Sz.hong@f5.com     }
6452146Sz.hong@f5.com 
6462146Sz.hong@f5.com     if (last != var->length) {
6472146Sz.hong@f5.com         p = nxt_cpymem(p, &src[last], var->length - last);
6482146Sz.hong@f5.com     }
6492146Sz.hong@f5.com 
650*2166Sz.hong@f5.com     if (strz) {
6512146Sz.hong@f5.com         *p = '\0';
6522146Sz.hong@f5.com     }
6532146Sz.hong@f5.com 
6542146Sz.hong@f5.com     nxt_debug(task, "var: \"%*s\" -> \"%V\"", length, src, str);
6551563Svbart@nginx.com 
6561563Svbart@nginx.com     return;
6571563Svbart@nginx.com 
6581563Svbart@nginx.com fail:
6591563Svbart@nginx.com 
6601563Svbart@nginx.com     query->failed = 1;
6611563Svbart@nginx.com }
6621563Svbart@nginx.com 
6631563Svbart@nginx.com 
6641563Svbart@nginx.com void
nxt_var_query_resolve(nxt_task_t * task,nxt_var_query_t * query,void * data,nxt_work_handler_t ready,nxt_work_handler_t error)6651563Svbart@nginx.com nxt_var_query_resolve(nxt_task_t *task, nxt_var_query_t *query, void *data,
6661563Svbart@nginx.com     nxt_work_handler_t ready, nxt_work_handler_t error)
6671563Svbart@nginx.com {
6681563Svbart@nginx.com     query->data = data;
6691563Svbart@nginx.com     query->ready = ready;
6701563Svbart@nginx.com     query->error = error;
6711563Svbart@nginx.com 
6721563Svbart@nginx.com     if (query->waiting == 0) {
6732146Sz.hong@f5.com         nxt_work_queue_add(&task->thread->engine->fast_work_queue,
6742146Sz.hong@f5.com                            query->failed ? query->error : query->ready,
6752146Sz.hong@f5.com                            task, query->ctx, query->data);
6761563Svbart@nginx.com     }
6771563Svbart@nginx.com }
6781563Svbart@nginx.com 
6791563Svbart@nginx.com 
6801563Svbart@nginx.com void
nxt_var_query_handle(nxt_task_t * task,nxt_var_query_t * query,nxt_bool_t failed)6811563Svbart@nginx.com nxt_var_query_handle(nxt_task_t *task, nxt_var_query_t *query,
6821563Svbart@nginx.com     nxt_bool_t failed)
6831563Svbart@nginx.com {
6841563Svbart@nginx.com     query->failed |= failed;
6851563Svbart@nginx.com 
6861563Svbart@nginx.com     if (--query->waiting == 0) {
6872146Sz.hong@f5.com         nxt_work_queue_add(&task->thread->engine->fast_work_queue,
6882146Sz.hong@f5.com                            query->failed ? query->error : query->ready,
6892146Sz.hong@f5.com                            task, query->ctx, query->data);
6901563Svbart@nginx.com     }
6911563Svbart@nginx.com }
692