1
2 /*
3 * Copyright (C) NGINX, Inc.
4 */
5
6 #include <nxt_main.h>
7
8
9 typedef enum {
10 NXT_TSTR_CONST = 0,
11 NXT_TSTR_VAR,
12 #if (NXT_HAVE_NJS)
13 NXT_TSTR_JS,
14 #endif
15 } nxt_tstr_type_t;
16
17
18 struct nxt_tstr_s {
19 nxt_str_t str;
20
21 union {
22 nxt_var_t *var;
23 #if (NXT_HAVE_NJS)
24 nxt_js_t *js;
25 #endif
26 } u;
27
28 nxt_tstr_flags_t flags;
29 nxt_tstr_type_t type;
30 };
31
32
33 struct nxt_tstr_query_s {
34 nxt_mp_t *pool;
35
36 nxt_tstr_state_t *state;
37 nxt_tstr_cache_t *cache;
38
39 nxt_uint_t waiting;
40 nxt_uint_t failed; /* 1 bit */
41
42 void *ctx;
43 void *data;
44
45 nxt_work_handler_t ready;
46 nxt_work_handler_t error;
47 };
48
49
50 #define nxt_tstr_is_js(str) \
51 nxt_strchr_start(str, '`')
52
53
54 nxt_tstr_state_t *
nxt_tstr_state_new(nxt_mp_t * mp,nxt_bool_t test)55 nxt_tstr_state_new(nxt_mp_t *mp, nxt_bool_t test)
56 {
57 nxt_tstr_state_t *state;
58
59 state = nxt_mp_get(mp, sizeof(nxt_tstr_state_t));
60 if (nxt_slow_path(state == NULL)) {
61 return NULL;
62 }
63
64 state->pool = mp;
65 state->test = test;
66
67 state->var_refs = nxt_array_create(mp, 4, sizeof(nxt_var_ref_t));
68 if (nxt_slow_path(state->var_refs == NULL)) {
69 return NULL;
70 }
71
72 #if (NXT_HAVE_NJS)
73 state->jcf = nxt_js_conf_new(mp, test);
74 if (nxt_slow_path(state->jcf == NULL)) {
75 return NULL;
76 }
77 #endif
78
79 return state;
80 }
81
82
83 nxt_tstr_t *
nxt_tstr_compile(nxt_tstr_state_t * state,nxt_str_t * str,nxt_tstr_flags_t flags)84 nxt_tstr_compile(nxt_tstr_state_t *state, nxt_str_t *str,
85 nxt_tstr_flags_t flags)
86 {
87 u_char *p;
88 nxt_tstr_t *tstr;
89 nxt_bool_t strz;
90
91 strz = (flags & NXT_TSTR_STRZ) != 0;
92
93 tstr = nxt_mp_get(state->pool, sizeof(nxt_tstr_t));
94 if (nxt_slow_path(tstr == NULL)) {
95 return NULL;
96 }
97
98 tstr->str.length = str->length + strz;
99
100 tstr->str.start = nxt_mp_nget(state->pool, tstr->str.length);
101 if (nxt_slow_path(tstr->str.start == NULL)) {
102 return NULL;
103 }
104
105 p = nxt_cpymem(tstr->str.start, str->start, str->length);
106
107 if (strz) {
108 *p = '\0';
109 }
110
111 tstr->flags = flags;
112
113 if (nxt_tstr_is_js(str)) {
114
115 #if (NXT_HAVE_NJS)
116
117 nxt_str_t tpl;
118
119 tstr->type = NXT_TSTR_JS;
120
121 nxt_tstr_str(tstr, &tpl);
122
123 tstr->u.js = nxt_js_add_tpl(state->jcf, &tpl, strz);
124 if (nxt_slow_path(tstr->u.js == NULL)) {
125 return NULL;
126 }
127
128 #endif
129
130 } else {
131 p = memchr(str->start, '$', str->length);
132
133 if (p != NULL) {
134 tstr->type = NXT_TSTR_VAR;
135
136 tstr->u.var = nxt_var_compile(state, &tstr->str);
137 if (nxt_slow_path(tstr->u.var == NULL)) {
138 return NULL;
139 }
140
141 } else {
142 tstr->type = NXT_TSTR_CONST;
143 }
144 }
145
146 return tstr;
147 }
148
149
150 nxt_int_t
nxt_tstr_test(nxt_tstr_state_t * state,nxt_str_t * str,u_char * error)151 nxt_tstr_test(nxt_tstr_state_t *state, nxt_str_t *str, u_char *error)
152 {
153 u_char *p;
154
155 if (nxt_tstr_is_js(str)) {
156 #if (NXT_HAVE_NJS)
157 return nxt_js_test(state->jcf, str, error);
158
159 #else
160 nxt_sprintf(error, error + NXT_MAX_ERROR_STR,
161 "Unit is built without support of njs: "
162 "\"--njs\" ./configure option is missing.");
163 return NXT_ERROR;
164 #endif
165
166 } else {
167 p = memchr(str->start, '$', str->length);
168
169 if (p != NULL) {
170 return nxt_var_test(state, str, error);
171 }
172 }
173
174 return NXT_OK;
175 }
176
177
178 nxt_int_t
nxt_tstr_state_done(nxt_tstr_state_t * state,u_char * error)179 nxt_tstr_state_done(nxt_tstr_state_t *state, u_char *error)
180 {
181 #if (NXT_HAVE_NJS)
182 if (!state->test) {
183 nxt_int_t ret;
184
185 ret = nxt_js_compile(state->jcf);
186 if (nxt_slow_path(ret != NXT_OK)) {
187 return NXT_ERROR;
188 }
189 }
190 #endif
191
192 return NXT_OK;
193 }
194
195
196 void
nxt_tstr_state_release(nxt_tstr_state_t * state)197 nxt_tstr_state_release(nxt_tstr_state_t *state)
198 {
199 #if (NXT_HAVE_NJS)
200 nxt_js_conf_release(state->jcf);
201 #endif
202 }
203
204
205 nxt_bool_t
nxt_tstr_is_const(nxt_tstr_t * tstr)206 nxt_tstr_is_const(nxt_tstr_t *tstr)
207 {
208 return (tstr->type == NXT_TSTR_CONST);
209 }
210
211
212 void
nxt_tstr_str(nxt_tstr_t * tstr,nxt_str_t * str)213 nxt_tstr_str(nxt_tstr_t *tstr, nxt_str_t *str)
214 {
215 *str = tstr->str;
216
217 if (tstr->flags & NXT_TSTR_STRZ) {
218 str->length--;
219 }
220 }
221
222
223 nxt_int_t
nxt_tstr_query_init(nxt_tstr_query_t ** query_p,nxt_tstr_state_t * state,nxt_tstr_cache_t * cache,void * ctx,nxt_mp_t * mp)224 nxt_tstr_query_init(nxt_tstr_query_t **query_p, nxt_tstr_state_t *state,
225 nxt_tstr_cache_t *cache, void *ctx, nxt_mp_t *mp)
226 {
227 nxt_tstr_query_t *query;
228
229 query = *query_p;
230
231 if (*query_p == NULL) {
232 query = nxt_mp_zget(mp, sizeof(nxt_tstr_query_t));
233 if (nxt_slow_path(query == NULL)) {
234 return NXT_ERROR;
235 }
236 }
237
238 query->pool = mp;
239 query->state = state;
240 query->cache = cache;
241 query->ctx = ctx;
242
243 *query_p = query;
244
245 return NXT_OK;
246 }
247
248
249 void
nxt_tstr_query(nxt_task_t * task,nxt_tstr_query_t * query,nxt_tstr_t * tstr,nxt_str_t * val)250 nxt_tstr_query(nxt_task_t *task, nxt_tstr_query_t *query, nxt_tstr_t *tstr,
251 nxt_str_t *val)
252 {
253 nxt_int_t ret;
254
255 if (nxt_tstr_is_const(tstr)) {
256 nxt_tstr_str(tstr, val);
257 return;
258 }
259
260 if (nxt_slow_path(query->failed)) {
261 return;
262 }
263
264 if (tstr->type == NXT_TSTR_VAR) {
265 ret = nxt_var_interpreter(task, query->state, &query->cache->var,
266 tstr->u.var, val, query->ctx,
267 tstr->flags & NXT_TSTR_LOGGING);
268
269 if (nxt_slow_path(ret != NXT_OK)) {
270 query->failed = 1;
271 return;
272 }
273
274 } else {
275 #if (NXT_HAVE_NJS)
276 ret = nxt_js_call(task, query->state->jcf, &query->cache->js,
277 tstr->u.js, val, query->ctx);
278
279 if (nxt_slow_path(ret != NXT_OK)) {
280 query->failed = 1;
281 return;
282 }
283 #endif
284 }
285
286 if (tstr->flags & NXT_TSTR_STRZ) {
287 val->length--;
288 }
289
290 #if (NXT_DEBUG)
291 nxt_str_t str;
292
293 nxt_tstr_str(tstr, &str);
294
295 nxt_debug(task, "tstr query: \"%V\", result: \"%V\"", &str, val);
296 #endif
297 }
298
299
300 nxt_bool_t
nxt_tstr_query_failed(nxt_tstr_query_t * query)301 nxt_tstr_query_failed(nxt_tstr_query_t *query)
302 {
303 return query->failed;
304 }
305
306
307 void
nxt_tstr_query_resolve(nxt_task_t * task,nxt_tstr_query_t * query,void * data,nxt_work_handler_t ready,nxt_work_handler_t error)308 nxt_tstr_query_resolve(nxt_task_t *task, nxt_tstr_query_t *query, void *data,
309 nxt_work_handler_t ready, nxt_work_handler_t error)
310 {
311 query->data = data;
312 query->ready = ready;
313 query->error = error;
314
315 if (query->waiting == 0) {
316 nxt_work_queue_add(&task->thread->engine->fast_work_queue,
317 query->failed ? query->error : query->ready,
318 task, query->ctx, query->data);
319 }
320 }
321
322
323 void
nxt_tstr_query_handle(nxt_task_t * task,nxt_tstr_query_t * query,nxt_bool_t failed)324 nxt_tstr_query_handle(nxt_task_t *task, nxt_tstr_query_t *query,
325 nxt_bool_t failed)
326 {
327 query->failed |= failed;
328
329 if (--query->waiting == 0) {
330 nxt_work_queue_add(&task->thread->engine->fast_work_queue,
331 query->failed ? query->error : query->ready,
332 task, query->ctx, query->data);
333 }
334 }
335
336
337 void
nxt_tstr_query_release(nxt_tstr_query_t * query)338 nxt_tstr_query_release(nxt_tstr_query_t *query)
339 {
340 #if (NXT_HAVE_NJS)
341 nxt_js_release(&query->cache->js);
342 #endif
343 }
344