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