xref: /unit/src/nxt_var.c (revision 1563)
1*1563Svbart@nginx.com 
2*1563Svbart@nginx.com /*
3*1563Svbart@nginx.com  * Copyright (C) NGINX, Inc.
4*1563Svbart@nginx.com  */
5*1563Svbart@nginx.com 
6*1563Svbart@nginx.com #include <nxt_main.h>
7*1563Svbart@nginx.com 
8*1563Svbart@nginx.com 
9*1563Svbart@nginx.com struct nxt_var_s {
10*1563Svbart@nginx.com     size_t      plain;
11*1563Svbart@nginx.com     nxt_uint_t  vars;
12*1563Svbart@nginx.com     u_char      data[];
13*1563Svbart@nginx.com 
14*1563Svbart@nginx.com /*
15*1563Svbart@nginx.com    uint32_t     indexes[vars];
16*1563Svbart@nginx.com    size_t       positions[vars];
17*1563Svbart@nginx.com    u_char       chars[plain];
18*1563Svbart@nginx.com */
19*1563Svbart@nginx.com };
20*1563Svbart@nginx.com 
21*1563Svbart@nginx.com 
22*1563Svbart@nginx.com typedef struct {
23*1563Svbart@nginx.com     nxt_var_t  *var;
24*1563Svbart@nginx.com     nxt_str_t  *value;
25*1563Svbart@nginx.com } nxt_var_value_t;
26*1563Svbart@nginx.com 
27*1563Svbart@nginx.com 
28*1563Svbart@nginx.com struct nxt_var_query_s {
29*1563Svbart@nginx.com     nxt_array_t         values;   /* of nxt_var_value_t */
30*1563Svbart@nginx.com     nxt_array_t         parts;    /* of nxt_str_t * */
31*1563Svbart@nginx.com 
32*1563Svbart@nginx.com     nxt_lvlhsh_t        cache;
33*1563Svbart@nginx.com 
34*1563Svbart@nginx.com     nxt_str_t           *spare;
35*1563Svbart@nginx.com     nxt_uint_t          waiting;
36*1563Svbart@nginx.com     nxt_uint_t          failed;   /* 1 bit */
37*1563Svbart@nginx.com 
38*1563Svbart@nginx.com     void                *ctx;
39*1563Svbart@nginx.com     void                *data;
40*1563Svbart@nginx.com 
41*1563Svbart@nginx.com     nxt_work_handler_t  ready;
42*1563Svbart@nginx.com     nxt_work_handler_t  error;
43*1563Svbart@nginx.com };
44*1563Svbart@nginx.com 
45*1563Svbart@nginx.com 
46*1563Svbart@nginx.com #define nxt_var_indexes(var)  ((uint32_t *) (var)->data)
47*1563Svbart@nginx.com 
48*1563Svbart@nginx.com #define nxt_var_positions(var)                                                \
49*1563Svbart@nginx.com     ((size_t *) ((var)->data + (var)->vars * sizeof(uint32_t)))
50*1563Svbart@nginx.com 
51*1563Svbart@nginx.com #define nxt_var_plain_start(var)                                              \
52*1563Svbart@nginx.com     ((var)->data + (var)->vars * (sizeof(uint32_t) + sizeof(size_t)))
53*1563Svbart@nginx.com 
54*1563Svbart@nginx.com 
55*1563Svbart@nginx.com static nxt_int_t nxt_var_hash_test(nxt_lvlhsh_query_t *lhq, void *data);
56*1563Svbart@nginx.com static nxt_var_decl_t *nxt_var_hash_find(nxt_str_t *name);
57*1563Svbart@nginx.com 
58*1563Svbart@nginx.com static nxt_int_t nxt_var_cache_test(nxt_lvlhsh_query_t *lhq, void *data);
59*1563Svbart@nginx.com static nxt_str_t *nxt_var_cache_find(nxt_lvlhsh_t *lh, uint32_t index);
60*1563Svbart@nginx.com static nxt_int_t nxt_var_cache_add(nxt_lvlhsh_t *lh, uint32_t index,
61*1563Svbart@nginx.com     nxt_str_t *value, nxt_mp_t *mp);
62*1563Svbart@nginx.com 
63*1563Svbart@nginx.com static u_char *nxt_var_next_part(u_char *start, size_t length, nxt_str_t *part,
64*1563Svbart@nginx.com     nxt_bool_t *is_var);
65*1563Svbart@nginx.com 
66*1563Svbart@nginx.com static void nxt_var_query_finish(nxt_task_t *task, nxt_var_query_t *query);
67*1563Svbart@nginx.com 
68*1563Svbart@nginx.com 
69*1563Svbart@nginx.com static const nxt_lvlhsh_proto_t  nxt_var_hash_proto  nxt_aligned(64) = {
70*1563Svbart@nginx.com     NXT_LVLHSH_DEFAULT,
71*1563Svbart@nginx.com     nxt_var_hash_test,
72*1563Svbart@nginx.com     nxt_lvlhsh_alloc,
73*1563Svbart@nginx.com     nxt_lvlhsh_free,
74*1563Svbart@nginx.com };
75*1563Svbart@nginx.com 
76*1563Svbart@nginx.com static const nxt_lvlhsh_proto_t  nxt_var_cache_proto  nxt_aligned(64) = {
77*1563Svbart@nginx.com     NXT_LVLHSH_DEFAULT,
78*1563Svbart@nginx.com     nxt_var_cache_test,
79*1563Svbart@nginx.com     nxt_mp_lvlhsh_alloc,
80*1563Svbart@nginx.com     nxt_mp_lvlhsh_free,
81*1563Svbart@nginx.com };
82*1563Svbart@nginx.com 
83*1563Svbart@nginx.com 
84*1563Svbart@nginx.com static nxt_lvlhsh_t       nxt_var_hash;
85*1563Svbart@nginx.com static uint32_t           nxt_var_count;
86*1563Svbart@nginx.com 
87*1563Svbart@nginx.com static nxt_var_handler_t  *nxt_var_index;
88*1563Svbart@nginx.com 
89*1563Svbart@nginx.com 
90*1563Svbart@nginx.com static nxt_int_t
91*1563Svbart@nginx.com nxt_var_hash_test(nxt_lvlhsh_query_t *lhq, void *data)
92*1563Svbart@nginx.com {
93*1563Svbart@nginx.com     nxt_var_decl_t  *decl;
94*1563Svbart@nginx.com 
95*1563Svbart@nginx.com     decl = data;
96*1563Svbart@nginx.com 
97*1563Svbart@nginx.com     return nxt_strstr_eq(&lhq->key, &decl->name) ? NXT_OK : NXT_DECLINED;
98*1563Svbart@nginx.com }
99*1563Svbart@nginx.com 
100*1563Svbart@nginx.com 
101*1563Svbart@nginx.com static nxt_var_decl_t *
102*1563Svbart@nginx.com nxt_var_hash_find(nxt_str_t *name)
103*1563Svbart@nginx.com {
104*1563Svbart@nginx.com     nxt_lvlhsh_query_t  lhq;
105*1563Svbart@nginx.com 
106*1563Svbart@nginx.com     lhq.key_hash = nxt_djb_hash(name->start, name->length);
107*1563Svbart@nginx.com     lhq.key = *name;
108*1563Svbart@nginx.com     lhq.proto = &nxt_var_hash_proto;
109*1563Svbart@nginx.com 
110*1563Svbart@nginx.com     if (nxt_lvlhsh_find(&nxt_var_hash, &lhq) != NXT_OK) {
111*1563Svbart@nginx.com         return NULL;
112*1563Svbart@nginx.com     }
113*1563Svbart@nginx.com 
114*1563Svbart@nginx.com     return lhq.value;
115*1563Svbart@nginx.com }
116*1563Svbart@nginx.com 
117*1563Svbart@nginx.com 
118*1563Svbart@nginx.com static nxt_int_t
119*1563Svbart@nginx.com nxt_var_cache_test(nxt_lvlhsh_query_t *lhq, void *data)
120*1563Svbart@nginx.com {
121*1563Svbart@nginx.com     return NXT_OK;
122*1563Svbart@nginx.com }
123*1563Svbart@nginx.com 
124*1563Svbart@nginx.com 
125*1563Svbart@nginx.com static nxt_str_t *
126*1563Svbart@nginx.com nxt_var_cache_find(nxt_lvlhsh_t *lh, uint32_t index)
127*1563Svbart@nginx.com {
128*1563Svbart@nginx.com     nxt_lvlhsh_query_t  lhq;
129*1563Svbart@nginx.com 
130*1563Svbart@nginx.com     lhq.key_hash = nxt_murmur_hash2_uint32(&index);
131*1563Svbart@nginx.com     lhq.key.length = sizeof(uint32_t);
132*1563Svbart@nginx.com     lhq.key.start = (u_char *) &index;
133*1563Svbart@nginx.com     lhq.proto = &nxt_var_cache_proto;
134*1563Svbart@nginx.com 
135*1563Svbart@nginx.com     if (nxt_lvlhsh_find(lh, &lhq) != NXT_OK) {
136*1563Svbart@nginx.com         return NULL;
137*1563Svbart@nginx.com     }
138*1563Svbart@nginx.com 
139*1563Svbart@nginx.com     return lhq.value;
140*1563Svbart@nginx.com }
141*1563Svbart@nginx.com 
142*1563Svbart@nginx.com 
143*1563Svbart@nginx.com static nxt_int_t
144*1563Svbart@nginx.com nxt_var_cache_add(nxt_lvlhsh_t *lh, uint32_t index, nxt_str_t *value,
145*1563Svbart@nginx.com     nxt_mp_t *mp)
146*1563Svbart@nginx.com {
147*1563Svbart@nginx.com     nxt_lvlhsh_query_t  lhq;
148*1563Svbart@nginx.com 
149*1563Svbart@nginx.com     lhq.key_hash = nxt_murmur_hash2_uint32(&index);
150*1563Svbart@nginx.com     lhq.replace = 0;
151*1563Svbart@nginx.com     lhq.key.length = sizeof(uint32_t);
152*1563Svbart@nginx.com     lhq.key.start = (u_char *) &index;
153*1563Svbart@nginx.com     lhq.value = value;
154*1563Svbart@nginx.com     lhq.proto = &nxt_var_cache_proto;
155*1563Svbart@nginx.com     lhq.pool = mp;
156*1563Svbart@nginx.com 
157*1563Svbart@nginx.com     return nxt_lvlhsh_insert(lh, &lhq);
158*1563Svbart@nginx.com }
159*1563Svbart@nginx.com 
160*1563Svbart@nginx.com 
161*1563Svbart@nginx.com nxt_int_t
162*1563Svbart@nginx.com nxt_var_register(nxt_var_decl_t *decl, size_t n)
163*1563Svbart@nginx.com {
164*1563Svbart@nginx.com     nxt_uint_t          i;
165*1563Svbart@nginx.com     nxt_lvlhsh_query_t  lhq;
166*1563Svbart@nginx.com 
167*1563Svbart@nginx.com     lhq.replace = 0;
168*1563Svbart@nginx.com     lhq.proto = &nxt_var_hash_proto;
169*1563Svbart@nginx.com 
170*1563Svbart@nginx.com     for (i = 0; i < n; i++) {
171*1563Svbart@nginx.com         lhq.key = decl[i].name;
172*1563Svbart@nginx.com         lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length);
173*1563Svbart@nginx.com         lhq.value = &decl[i];
174*1563Svbart@nginx.com 
175*1563Svbart@nginx.com         if (nxt_slow_path(nxt_lvlhsh_insert(&nxt_var_hash, &lhq) != NXT_OK)) {
176*1563Svbart@nginx.com             return NXT_ERROR;
177*1563Svbart@nginx.com         }
178*1563Svbart@nginx.com     }
179*1563Svbart@nginx.com 
180*1563Svbart@nginx.com     nxt_var_count += n;
181*1563Svbart@nginx.com 
182*1563Svbart@nginx.com     return NXT_OK;
183*1563Svbart@nginx.com }
184*1563Svbart@nginx.com 
185*1563Svbart@nginx.com 
186*1563Svbart@nginx.com nxt_int_t
187*1563Svbart@nginx.com nxt_var_index_init(void)
188*1563Svbart@nginx.com {
189*1563Svbart@nginx.com     nxt_uint_t         i;
190*1563Svbart@nginx.com     nxt_var_decl_t     *decl;
191*1563Svbart@nginx.com     nxt_var_handler_t  *index;
192*1563Svbart@nginx.com     nxt_lvlhsh_each_t  lhe;
193*1563Svbart@nginx.com 
194*1563Svbart@nginx.com     index = nxt_memalign(64, nxt_var_count * sizeof(nxt_var_handler_t));
195*1563Svbart@nginx.com     if (index == NULL) {
196*1563Svbart@nginx.com         return NXT_ERROR;
197*1563Svbart@nginx.com     }
198*1563Svbart@nginx.com 
199*1563Svbart@nginx.com     nxt_lvlhsh_each_init(&lhe, &nxt_var_hash_proto);
200*1563Svbart@nginx.com 
201*1563Svbart@nginx.com     for (i = 0; i < nxt_var_count; i++) {
202*1563Svbart@nginx.com         decl = nxt_lvlhsh_each(&nxt_var_hash, &lhe);
203*1563Svbart@nginx.com         decl->index = i;
204*1563Svbart@nginx.com         index[i] = decl->handler;
205*1563Svbart@nginx.com     }
206*1563Svbart@nginx.com 
207*1563Svbart@nginx.com     nxt_var_index = index;
208*1563Svbart@nginx.com 
209*1563Svbart@nginx.com     return NXT_OK;
210*1563Svbart@nginx.com }
211*1563Svbart@nginx.com 
212*1563Svbart@nginx.com 
213*1563Svbart@nginx.com nxt_var_t *
214*1563Svbart@nginx.com nxt_var_compile(nxt_str_t *str, nxt_mp_t *mp)
215*1563Svbart@nginx.com {
216*1563Svbart@nginx.com     u_char             *p, *end, *plain_pos;
217*1563Svbart@nginx.com     size_t             plain, size, *positions;
218*1563Svbart@nginx.com     uint32_t           *indexes;
219*1563Svbart@nginx.com     nxt_var_t          *var;
220*1563Svbart@nginx.com     nxt_str_t          part;
221*1563Svbart@nginx.com     nxt_uint_t         n;
222*1563Svbart@nginx.com     nxt_bool_t         is_var;
223*1563Svbart@nginx.com     nxt_var_decl_t     *decl;
224*1563Svbart@nginx.com 
225*1563Svbart@nginx.com     plain = 0;
226*1563Svbart@nginx.com     n = 0;
227*1563Svbart@nginx.com 
228*1563Svbart@nginx.com     p = str->start;
229*1563Svbart@nginx.com     end = p + str->length;
230*1563Svbart@nginx.com 
231*1563Svbart@nginx.com     while (p < end) {
232*1563Svbart@nginx.com         p = nxt_var_next_part(p, end - p, &part, &is_var);
233*1563Svbart@nginx.com 
234*1563Svbart@nginx.com         if (nxt_slow_path(p == NULL)) {
235*1563Svbart@nginx.com             return NULL;
236*1563Svbart@nginx.com         }
237*1563Svbart@nginx.com 
238*1563Svbart@nginx.com         if (is_var) {
239*1563Svbart@nginx.com             n++;
240*1563Svbart@nginx.com 
241*1563Svbart@nginx.com         } else {
242*1563Svbart@nginx.com             plain += part.length;
243*1563Svbart@nginx.com         }
244*1563Svbart@nginx.com     }
245*1563Svbart@nginx.com 
246*1563Svbart@nginx.com     size = sizeof(nxt_var_t)
247*1563Svbart@nginx.com            + n * (sizeof(nxt_var_handler_t) + sizeof (size_t))
248*1563Svbart@nginx.com            + plain;
249*1563Svbart@nginx.com 
250*1563Svbart@nginx.com     var = nxt_mp_get(mp, size);
251*1563Svbart@nginx.com     if (nxt_slow_path(var == NULL)) {
252*1563Svbart@nginx.com         return NULL;
253*1563Svbart@nginx.com     }
254*1563Svbart@nginx.com 
255*1563Svbart@nginx.com     var->plain = plain;
256*1563Svbart@nginx.com     var->vars = n;
257*1563Svbart@nginx.com 
258*1563Svbart@nginx.com     indexes = nxt_var_indexes(var);
259*1563Svbart@nginx.com     positions = nxt_var_positions(var);
260*1563Svbart@nginx.com     plain_pos = nxt_var_plain_start(var);
261*1563Svbart@nginx.com 
262*1563Svbart@nginx.com     plain = 0;
263*1563Svbart@nginx.com     n = 0;
264*1563Svbart@nginx.com 
265*1563Svbart@nginx.com     p = str->start;
266*1563Svbart@nginx.com 
267*1563Svbart@nginx.com     while (p < end) {
268*1563Svbart@nginx.com         p = nxt_var_next_part(p, end - p, &part, &is_var);
269*1563Svbart@nginx.com 
270*1563Svbart@nginx.com         if (is_var) {
271*1563Svbart@nginx.com             decl = nxt_var_hash_find(&part);
272*1563Svbart@nginx.com 
273*1563Svbart@nginx.com             if (nxt_slow_path(decl == NULL)) {
274*1563Svbart@nginx.com                 return NULL;
275*1563Svbart@nginx.com             }
276*1563Svbart@nginx.com 
277*1563Svbart@nginx.com             indexes[n] = decl->index;
278*1563Svbart@nginx.com             positions[n] = plain;
279*1563Svbart@nginx.com 
280*1563Svbart@nginx.com             n++;
281*1563Svbart@nginx.com 
282*1563Svbart@nginx.com         } else {
283*1563Svbart@nginx.com             plain_pos = nxt_cpymem(plain_pos, part.start, part.length);
284*1563Svbart@nginx.com             plain += part.length;
285*1563Svbart@nginx.com         }
286*1563Svbart@nginx.com     }
287*1563Svbart@nginx.com 
288*1563Svbart@nginx.com     return var;
289*1563Svbart@nginx.com }
290*1563Svbart@nginx.com 
291*1563Svbart@nginx.com 
292*1563Svbart@nginx.com nxt_int_t
293*1563Svbart@nginx.com nxt_var_test(nxt_str_t *str, u_char *error)
294*1563Svbart@nginx.com {
295*1563Svbart@nginx.com     u_char          *p, *end, *next;
296*1563Svbart@nginx.com     nxt_str_t       part;
297*1563Svbart@nginx.com     nxt_bool_t      is_var;
298*1563Svbart@nginx.com     nxt_var_decl_t  *decl;
299*1563Svbart@nginx.com 
300*1563Svbart@nginx.com     p = str->start;
301*1563Svbart@nginx.com     end = p + str->length;
302*1563Svbart@nginx.com 
303*1563Svbart@nginx.com     while (p < end) {
304*1563Svbart@nginx.com         next = nxt_var_next_part(p, end - p, &part, &is_var);
305*1563Svbart@nginx.com 
306*1563Svbart@nginx.com         if (next == NULL) {
307*1563Svbart@nginx.com             nxt_sprintf(error, error + NXT_MAX_ERROR_STR,
308*1563Svbart@nginx.com                         "Invalid variable at position %uz%Z", p - str->start);
309*1563Svbart@nginx.com 
310*1563Svbart@nginx.com             return NXT_ERROR;
311*1563Svbart@nginx.com         }
312*1563Svbart@nginx.com 
313*1563Svbart@nginx.com         if (is_var) {
314*1563Svbart@nginx.com             decl = nxt_var_hash_find(&part);
315*1563Svbart@nginx.com 
316*1563Svbart@nginx.com             if (decl == NULL) {
317*1563Svbart@nginx.com                 nxt_sprintf(error, error + NXT_MAX_ERROR_STR,
318*1563Svbart@nginx.com                             "Unknown variable \"%V\"%Z", &part);
319*1563Svbart@nginx.com 
320*1563Svbart@nginx.com                 return NXT_ERROR;
321*1563Svbart@nginx.com             }
322*1563Svbart@nginx.com         }
323*1563Svbart@nginx.com 
324*1563Svbart@nginx.com         p = next;
325*1563Svbart@nginx.com     }
326*1563Svbart@nginx.com 
327*1563Svbart@nginx.com     return NXT_OK;
328*1563Svbart@nginx.com }
329*1563Svbart@nginx.com 
330*1563Svbart@nginx.com 
331*1563Svbart@nginx.com static u_char *
332*1563Svbart@nginx.com nxt_var_next_part(u_char *start, size_t length, nxt_str_t *part,
333*1563Svbart@nginx.com     nxt_bool_t *is_var)
334*1563Svbart@nginx.com {
335*1563Svbart@nginx.com     u_char      *p, *end, ch, c;
336*1563Svbart@nginx.com     nxt_bool_t  bracket;
337*1563Svbart@nginx.com 
338*1563Svbart@nginx.com     end = start + length;
339*1563Svbart@nginx.com 
340*1563Svbart@nginx.com     p = nxt_memchr(start, '$', length);
341*1563Svbart@nginx.com 
342*1563Svbart@nginx.com     if (p == start) {
343*1563Svbart@nginx.com         *is_var = 1;
344*1563Svbart@nginx.com 
345*1563Svbart@nginx.com         p++;
346*1563Svbart@nginx.com 
347*1563Svbart@nginx.com         if (p == end) {
348*1563Svbart@nginx.com             return NULL;
349*1563Svbart@nginx.com         }
350*1563Svbart@nginx.com 
351*1563Svbart@nginx.com         if (*p == '{') {
352*1563Svbart@nginx.com             bracket = 1;
353*1563Svbart@nginx.com 
354*1563Svbart@nginx.com             if (end - p < 2) {
355*1563Svbart@nginx.com                 return NULL;
356*1563Svbart@nginx.com             }
357*1563Svbart@nginx.com 
358*1563Svbart@nginx.com             p++;
359*1563Svbart@nginx.com 
360*1563Svbart@nginx.com         } else {
361*1563Svbart@nginx.com             bracket = 0;
362*1563Svbart@nginx.com         }
363*1563Svbart@nginx.com 
364*1563Svbart@nginx.com         start = p;
365*1563Svbart@nginx.com 
366*1563Svbart@nginx.com         for ( ;; ) {
367*1563Svbart@nginx.com             ch = *p;
368*1563Svbart@nginx.com 
369*1563Svbart@nginx.com             c = (u_char) (ch | 0x20);
370*1563Svbart@nginx.com             if ((c < 'a' || c > 'z') && ch != '_') {
371*1563Svbart@nginx.com 
372*1563Svbart@nginx.com                 if (bracket && ch != '}') {
373*1563Svbart@nginx.com                     return NULL;
374*1563Svbart@nginx.com                 }
375*1563Svbart@nginx.com 
376*1563Svbart@nginx.com                 break;
377*1563Svbart@nginx.com             }
378*1563Svbart@nginx.com 
379*1563Svbart@nginx.com             p++;
380*1563Svbart@nginx.com 
381*1563Svbart@nginx.com             if (p == end) {
382*1563Svbart@nginx.com                 if (bracket) {
383*1563Svbart@nginx.com                     return NULL;
384*1563Svbart@nginx.com                 }
385*1563Svbart@nginx.com 
386*1563Svbart@nginx.com                 break;
387*1563Svbart@nginx.com             }
388*1563Svbart@nginx.com         }
389*1563Svbart@nginx.com 
390*1563Svbart@nginx.com         length = p - start;
391*1563Svbart@nginx.com         end = p + bracket;
392*1563Svbart@nginx.com 
393*1563Svbart@nginx.com     } else {
394*1563Svbart@nginx.com         *is_var = 0;
395*1563Svbart@nginx.com 
396*1563Svbart@nginx.com         if (p != NULL) {
397*1563Svbart@nginx.com             length = p - start;
398*1563Svbart@nginx.com             end = p;
399*1563Svbart@nginx.com         }
400*1563Svbart@nginx.com     }
401*1563Svbart@nginx.com 
402*1563Svbart@nginx.com     part->length = length;
403*1563Svbart@nginx.com     part->start = start;
404*1563Svbart@nginx.com 
405*1563Svbart@nginx.com     return end;
406*1563Svbart@nginx.com }
407*1563Svbart@nginx.com 
408*1563Svbart@nginx.com 
409*1563Svbart@nginx.com nxt_int_t
410*1563Svbart@nginx.com nxt_var_query_init(nxt_var_query_t **query_p, void *ctx, nxt_mp_t *mp)
411*1563Svbart@nginx.com {
412*1563Svbart@nginx.com     nxt_var_query_t  *query;
413*1563Svbart@nginx.com 
414*1563Svbart@nginx.com     query = *query_p;
415*1563Svbart@nginx.com 
416*1563Svbart@nginx.com     if (*query_p == NULL) {
417*1563Svbart@nginx.com         query = nxt_mp_zget(mp, sizeof(nxt_var_query_t));
418*1563Svbart@nginx.com         if (nxt_slow_path(query == NULL)) {
419*1563Svbart@nginx.com             return NXT_ERROR;
420*1563Svbart@nginx.com         }
421*1563Svbart@nginx.com 
422*1563Svbart@nginx.com         nxt_array_init(&query->values, mp, sizeof(nxt_var_value_t));
423*1563Svbart@nginx.com         nxt_array_init(&query->parts, mp, sizeof(nxt_str_t *));
424*1563Svbart@nginx.com 
425*1563Svbart@nginx.com     } else {
426*1563Svbart@nginx.com         nxt_array_reset(&query->values);
427*1563Svbart@nginx.com     }
428*1563Svbart@nginx.com 
429*1563Svbart@nginx.com     query->ctx = ctx;
430*1563Svbart@nginx.com 
431*1563Svbart@nginx.com     *query_p = query;
432*1563Svbart@nginx.com 
433*1563Svbart@nginx.com     return NXT_OK;
434*1563Svbart@nginx.com }
435*1563Svbart@nginx.com 
436*1563Svbart@nginx.com 
437*1563Svbart@nginx.com void
438*1563Svbart@nginx.com nxt_var_query(nxt_task_t *task, nxt_var_query_t *query, nxt_var_t *var,
439*1563Svbart@nginx.com     nxt_str_t *str)
440*1563Svbart@nginx.com {
441*1563Svbart@nginx.com     uint32_t           *indexes;
442*1563Svbart@nginx.com     nxt_mp_t           *mp;
443*1563Svbart@nginx.com     nxt_str_t          *value;
444*1563Svbart@nginx.com     nxt_int_t          ret;
445*1563Svbart@nginx.com     nxt_uint_t         i;
446*1563Svbart@nginx.com     nxt_var_value_t    *val;
447*1563Svbart@nginx.com 
448*1563Svbart@nginx.com     if (var->vars == 0) {
449*1563Svbart@nginx.com         str->length = var->plain;
450*1563Svbart@nginx.com         str->start = nxt_var_plain_start(var);
451*1563Svbart@nginx.com         return;
452*1563Svbart@nginx.com     }
453*1563Svbart@nginx.com 
454*1563Svbart@nginx.com     if (nxt_slow_path(query->failed)) {
455*1563Svbart@nginx.com         return;
456*1563Svbart@nginx.com     }
457*1563Svbart@nginx.com 
458*1563Svbart@nginx.com     mp = query->values.mem_pool;
459*1563Svbart@nginx.com     indexes = nxt_var_indexes(var);
460*1563Svbart@nginx.com     value = query->spare;
461*1563Svbart@nginx.com 
462*1563Svbart@nginx.com     for (i = 0; i < var->vars; i++) {
463*1563Svbart@nginx.com 
464*1563Svbart@nginx.com         if (value == NULL) {
465*1563Svbart@nginx.com             value = nxt_mp_zget(mp, sizeof(nxt_str_t));
466*1563Svbart@nginx.com             if (nxt_slow_path(value == NULL)) {
467*1563Svbart@nginx.com                 goto fail;
468*1563Svbart@nginx.com             }
469*1563Svbart@nginx.com         }
470*1563Svbart@nginx.com 
471*1563Svbart@nginx.com         ret = nxt_var_cache_add(&query->cache, indexes[i], value, mp);
472*1563Svbart@nginx.com 
473*1563Svbart@nginx.com         if (ret != NXT_OK) {
474*1563Svbart@nginx.com             if (nxt_slow_path(ret == NXT_ERROR)) {
475*1563Svbart@nginx.com                 goto fail;
476*1563Svbart@nginx.com             }
477*1563Svbart@nginx.com 
478*1563Svbart@nginx.com             continue;  /* NXT_DECLINED */
479*1563Svbart@nginx.com         }
480*1563Svbart@nginx.com 
481*1563Svbart@nginx.com         ret = nxt_var_index[indexes[i]](task, query, value, query->ctx);
482*1563Svbart@nginx.com 
483*1563Svbart@nginx.com         value = NULL;
484*1563Svbart@nginx.com 
485*1563Svbart@nginx.com         if (ret != NXT_OK) {
486*1563Svbart@nginx.com             if (nxt_slow_path(ret != NXT_AGAIN)) {
487*1563Svbart@nginx.com                 goto fail;
488*1563Svbart@nginx.com             }
489*1563Svbart@nginx.com 
490*1563Svbart@nginx.com             query->waiting++;
491*1563Svbart@nginx.com         }
492*1563Svbart@nginx.com     }
493*1563Svbart@nginx.com 
494*1563Svbart@nginx.com     query->spare = value;
495*1563Svbart@nginx.com 
496*1563Svbart@nginx.com     val = nxt_array_add(&query->values);
497*1563Svbart@nginx.com     if (nxt_slow_path(val == NULL)) {
498*1563Svbart@nginx.com         goto fail;
499*1563Svbart@nginx.com     }
500*1563Svbart@nginx.com 
501*1563Svbart@nginx.com     val->var = var;
502*1563Svbart@nginx.com     val->value = str;
503*1563Svbart@nginx.com 
504*1563Svbart@nginx.com     return;
505*1563Svbart@nginx.com 
506*1563Svbart@nginx.com fail:
507*1563Svbart@nginx.com 
508*1563Svbart@nginx.com     query->failed = 1;
509*1563Svbart@nginx.com }
510*1563Svbart@nginx.com 
511*1563Svbart@nginx.com 
512*1563Svbart@nginx.com void
513*1563Svbart@nginx.com nxt_var_query_resolve(nxt_task_t *task, nxt_var_query_t *query, void *data,
514*1563Svbart@nginx.com     nxt_work_handler_t ready, nxt_work_handler_t error)
515*1563Svbart@nginx.com {
516*1563Svbart@nginx.com     query->data = data;
517*1563Svbart@nginx.com     query->ready = ready;
518*1563Svbart@nginx.com     query->error = error;
519*1563Svbart@nginx.com 
520*1563Svbart@nginx.com     if (query->waiting == 0) {
521*1563Svbart@nginx.com         nxt_var_query_finish(task, query);
522*1563Svbart@nginx.com     }
523*1563Svbart@nginx.com }
524*1563Svbart@nginx.com 
525*1563Svbart@nginx.com 
526*1563Svbart@nginx.com void
527*1563Svbart@nginx.com nxt_var_query_handle(nxt_task_t *task, nxt_var_query_t *query,
528*1563Svbart@nginx.com     nxt_bool_t failed)
529*1563Svbart@nginx.com {
530*1563Svbart@nginx.com     query->failed |= failed;
531*1563Svbart@nginx.com 
532*1563Svbart@nginx.com     if (--query->waiting == 0) {
533*1563Svbart@nginx.com         nxt_var_query_finish(task, query);
534*1563Svbart@nginx.com     }
535*1563Svbart@nginx.com }
536*1563Svbart@nginx.com 
537*1563Svbart@nginx.com 
538*1563Svbart@nginx.com static void
539*1563Svbart@nginx.com nxt_var_query_finish(nxt_task_t *task, nxt_var_query_t *query)
540*1563Svbart@nginx.com {
541*1563Svbart@nginx.com     u_char             *p, *src;
542*1563Svbart@nginx.com     size_t             length, plain, next, *positions;
543*1563Svbart@nginx.com     uint32_t           *indexes;
544*1563Svbart@nginx.com     nxt_str_t          *str, **part;
545*1563Svbart@nginx.com     nxt_var_t          *var;
546*1563Svbart@nginx.com     nxt_uint_t         i, j;
547*1563Svbart@nginx.com     nxt_var_value_t    *val;
548*1563Svbart@nginx.com 
549*1563Svbart@nginx.com     if (query->failed) {
550*1563Svbart@nginx.com         goto done;
551*1563Svbart@nginx.com     }
552*1563Svbart@nginx.com 
553*1563Svbart@nginx.com     val = query->values.elts;
554*1563Svbart@nginx.com 
555*1563Svbart@nginx.com     for (i = 0; i < query->values.nelts; i++) {
556*1563Svbart@nginx.com         var = val[i].var;
557*1563Svbart@nginx.com 
558*1563Svbart@nginx.com         length = var->plain;
559*1563Svbart@nginx.com         indexes = nxt_var_indexes(var);
560*1563Svbart@nginx.com 
561*1563Svbart@nginx.com         for (j = 0; j < var->vars; j++) {
562*1563Svbart@nginx.com             str = nxt_var_cache_find(&query->cache, indexes[j]);
563*1563Svbart@nginx.com 
564*1563Svbart@nginx.com             nxt_assert(str != NULL);
565*1563Svbart@nginx.com 
566*1563Svbart@nginx.com             part = nxt_array_add(&query->parts);
567*1563Svbart@nginx.com 
568*1563Svbart@nginx.com             if (nxt_slow_path(part == NULL)) {
569*1563Svbart@nginx.com                 query->failed = 1;
570*1563Svbart@nginx.com                 goto done;
571*1563Svbart@nginx.com             }
572*1563Svbart@nginx.com 
573*1563Svbart@nginx.com             *part = str;
574*1563Svbart@nginx.com 
575*1563Svbart@nginx.com             length += str->length;
576*1563Svbart@nginx.com         }
577*1563Svbart@nginx.com 
578*1563Svbart@nginx.com         p = nxt_mp_nget(query->values.mem_pool, length);
579*1563Svbart@nginx.com         if (nxt_slow_path(p == NULL)) {
580*1563Svbart@nginx.com             query->failed = 1;
581*1563Svbart@nginx.com             goto done;
582*1563Svbart@nginx.com         }
583*1563Svbart@nginx.com 
584*1563Svbart@nginx.com         val[i].value->length = length;
585*1563Svbart@nginx.com         val[i].value->start = p;
586*1563Svbart@nginx.com 
587*1563Svbart@nginx.com         part = query->parts.elts;
588*1563Svbart@nginx.com         positions = nxt_var_positions(var);
589*1563Svbart@nginx.com         src = nxt_var_plain_start(var);
590*1563Svbart@nginx.com 
591*1563Svbart@nginx.com         plain = 0;
592*1563Svbart@nginx.com 
593*1563Svbart@nginx.com         for (j = 0; j < var->vars; j++) {
594*1563Svbart@nginx.com             next = positions[j];
595*1563Svbart@nginx.com 
596*1563Svbart@nginx.com             if (next != plain) {
597*1563Svbart@nginx.com                 p = nxt_cpymem(p, &src[plain], next - plain);
598*1563Svbart@nginx.com                 plain = next;
599*1563Svbart@nginx.com             }
600*1563Svbart@nginx.com 
601*1563Svbart@nginx.com             p = nxt_cpymem(p, part[j]->start, part[j]->length);
602*1563Svbart@nginx.com         }
603*1563Svbart@nginx.com 
604*1563Svbart@nginx.com         if (plain != var->plain) {
605*1563Svbart@nginx.com             nxt_memcpy(p, &src[plain], var->plain - plain);
606*1563Svbart@nginx.com         }
607*1563Svbart@nginx.com 
608*1563Svbart@nginx.com         nxt_array_reset(&query->parts);
609*1563Svbart@nginx.com     }
610*1563Svbart@nginx.com 
611*1563Svbart@nginx.com done:
612*1563Svbart@nginx.com 
613*1563Svbart@nginx.com     nxt_work_queue_add(&task->thread->engine->fast_work_queue,
614*1563Svbart@nginx.com                        query->failed ? query->error : query->ready,
615*1563Svbart@nginx.com                        task, query->ctx, query->data);
616*1563Svbart@nginx.com }
617