xref: /unit/src/nxt_tstr.c (revision 2504:c559ee0041ec)
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