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