1e18a033bSKonstantin Ananyev
2e18a033bSKonstantin Ananyev/*
3e18a033bSKonstantin Ananyev * Copyright (C) Igor Sysoev
4e18a033bSKonstantin Ananyev * Copyright (C) Nginx, Inc.
5e18a033bSKonstantin Ananyev */
6e18a033bSKonstantin Ananyev
7e18a033bSKonstantin Ananyev
8e18a033bSKonstantin Ananyev#include <ngx_config.h>
9e18a033bSKonstantin Ananyev#include <ngx_core.h>
10e18a033bSKonstantin Ananyev#include <ngx_stream.h>
11e18a033bSKonstantin Ananyev
12e18a033bSKonstantin Ananyev
13e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_script_init_arrays(
14e18a033bSKonstantin Ananyev    ngx_stream_script_compile_t *sc);
15e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_script_done(ngx_stream_script_compile_t *sc);
16e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_script_add_copy_code(
17e18a033bSKonstantin Ananyev    ngx_stream_script_compile_t *sc, ngx_str_t *value, ngx_uint_t last);
18e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_script_add_var_code(
19e18a033bSKonstantin Ananyev    ngx_stream_script_compile_t *sc, ngx_str_t *name);
20e18a033bSKonstantin Ananyev#if (NGX_PCRE)
21e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_script_add_capture_code(
22e18a033bSKonstantin Ananyev    ngx_stream_script_compile_t *sc, ngx_uint_t n);
23e18a033bSKonstantin Ananyev#endif
24e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_script_add_full_name_code(
25e18a033bSKonstantin Ananyev    ngx_stream_script_compile_t *sc);
26e18a033bSKonstantin Ananyevstatic size_t ngx_stream_script_full_name_len_code(
27e18a033bSKonstantin Ananyev    ngx_stream_script_engine_t *e);
28e18a033bSKonstantin Ananyevstatic void ngx_stream_script_full_name_code(ngx_stream_script_engine_t *e);
29e18a033bSKonstantin Ananyev
30e18a033bSKonstantin Ananyev
31e18a033bSKonstantin Ananyev#define ngx_stream_script_exit  (u_char *) &ngx_stream_script_exit_code
32e18a033bSKonstantin Ananyev
33e18a033bSKonstantin Ananyevstatic uintptr_t ngx_stream_script_exit_code = (uintptr_t) NULL;
34e18a033bSKonstantin Ananyev
35e18a033bSKonstantin Ananyev
36e18a033bSKonstantin Ananyevvoid
37e18a033bSKonstantin Ananyevngx_stream_script_flush_complex_value(ngx_stream_session_t *s,
38e18a033bSKonstantin Ananyev    ngx_stream_complex_value_t *val)
39e18a033bSKonstantin Ananyev{
40e18a033bSKonstantin Ananyev    ngx_uint_t *index;
41e18a033bSKonstantin Ananyev
42e18a033bSKonstantin Ananyev    index = val->flushes;
43e18a033bSKonstantin Ananyev
44e18a033bSKonstantin Ananyev    if (index) {
45e18a033bSKonstantin Ananyev        while (*index != (ngx_uint_t) -1) {
46e18a033bSKonstantin Ananyev
47e18a033bSKonstantin Ananyev            if (s->variables[*index].no_cacheable) {
48e18a033bSKonstantin Ananyev                s->variables[*index].valid = 0;
49e18a033bSKonstantin Ananyev                s->variables[*index].not_found = 0;
50e18a033bSKonstantin Ananyev            }
51e18a033bSKonstantin Ananyev
52e18a033bSKonstantin Ananyev            index++;
53e18a033bSKonstantin Ananyev        }
54e18a033bSKonstantin Ananyev    }
55e18a033bSKonstantin Ananyev}
56e18a033bSKonstantin Ananyev
57e18a033bSKonstantin Ananyev
58e18a033bSKonstantin Ananyevngx_int_t
59e18a033bSKonstantin Ananyevngx_stream_complex_value(ngx_stream_session_t *s,
60e18a033bSKonstantin Ananyev    ngx_stream_complex_value_t *val, ngx_str_t *value)
61e18a033bSKonstantin Ananyev{
62e18a033bSKonstantin Ananyev    size_t                         len;
63e18a033bSKonstantin Ananyev    ngx_stream_script_code_pt      code;
64e18a033bSKonstantin Ananyev    ngx_stream_script_engine_t     e;
65e18a033bSKonstantin Ananyev    ngx_stream_script_len_code_pt  lcode;
66e18a033bSKonstantin Ananyev
67e18a033bSKonstantin Ananyev    if (val->lengths == NULL) {
68e18a033bSKonstantin Ananyev        *value = val->value;
69e18a033bSKonstantin Ananyev        return NGX_OK;
70e18a033bSKonstantin Ananyev    }
71e18a033bSKonstantin Ananyev
72e18a033bSKonstantin Ananyev    ngx_stream_script_flush_complex_value(s, val);
73e18a033bSKonstantin Ananyev
74e18a033bSKonstantin Ananyev    ngx_memzero(&e, sizeof(ngx_stream_script_engine_t));
75e18a033bSKonstantin Ananyev
76e18a033bSKonstantin Ananyev    e.ip = val->lengths;
77e18a033bSKonstantin Ananyev    e.session = s;
78e18a033bSKonstantin Ananyev    e.flushed = 1;
79e18a033bSKonstantin Ananyev
80e18a033bSKonstantin Ananyev    len = 0;
81e18a033bSKonstantin Ananyev
82e18a033bSKonstantin Ananyev    while (*(uintptr_t *) e.ip) {
83e18a033bSKonstantin Ananyev        lcode = *(ngx_stream_script_len_code_pt *) e.ip;
84e18a033bSKonstantin Ananyev        len += lcode(&e);
85e18a033bSKonstantin Ananyev    }
86e18a033bSKonstantin Ananyev
87e18a033bSKonstantin Ananyev    value->len = len;
88e18a033bSKonstantin Ananyev    value->data = ngx_pnalloc(s->connection->pool, len);
89e18a033bSKonstantin Ananyev    if (value->data == NULL) {
90e18a033bSKonstantin Ananyev        return NGX_ERROR;
91e18a033bSKonstantin Ananyev    }
92e18a033bSKonstantin Ananyev
93e18a033bSKonstantin Ananyev    e.ip = val->values;
94e18a033bSKonstantin Ananyev    e.pos = value->data;
95e18a033bSKonstantin Ananyev    e.buf = *value;
96e18a033bSKonstantin Ananyev
97e18a033bSKonstantin Ananyev    while (*(uintptr_t *) e.ip) {
98e18a033bSKonstantin Ananyev        code = *(ngx_stream_script_code_pt *) e.ip;
99e18a033bSKonstantin Ananyev        code((ngx_stream_script_engine_t *) &e);
100e18a033bSKonstantin Ananyev    }
101e18a033bSKonstantin Ananyev
102e18a033bSKonstantin Ananyev    *value = e.buf;
103e18a033bSKonstantin Ananyev
104e18a033bSKonstantin Ananyev    return NGX_OK;
105e18a033bSKonstantin Ananyev}
106e18a033bSKonstantin Ananyev
107e18a033bSKonstantin Ananyev
108e18a033bSKonstantin Ananyevngx_int_t
109e18a033bSKonstantin Ananyevngx_stream_compile_complex_value(ngx_stream_compile_complex_value_t *ccv)
110e18a033bSKonstantin Ananyev{
111e18a033bSKonstantin Ananyev    ngx_str_t                    *v;
112e18a033bSKonstantin Ananyev    ngx_uint_t                    i, n, nv, nc;
113e18a033bSKonstantin Ananyev    ngx_array_t                   flushes, lengths, values, *pf, *pl, *pv;
114e18a033bSKonstantin Ananyev    ngx_stream_script_compile_t   sc;
115e18a033bSKonstantin Ananyev
116e18a033bSKonstantin Ananyev    v = ccv->value;
117e18a033bSKonstantin Ananyev
118e18a033bSKonstantin Ananyev    nv = 0;
119e18a033bSKonstantin Ananyev    nc = 0;
120e18a033bSKonstantin Ananyev
121e18a033bSKonstantin Ananyev    for (i = 0; i < v->len; i++) {
122e18a033bSKonstantin Ananyev        if (v->data[i] == '$') {
123e18a033bSKonstantin Ananyev            if (v->data[i + 1] >= '1' && v->data[i + 1] <= '9') {
124e18a033bSKonstantin Ananyev                nc++;
125e18a033bSKonstantin Ananyev
126e18a033bSKonstantin Ananyev            } else {
127e18a033bSKonstantin Ananyev                nv++;
128e18a033bSKonstantin Ananyev            }
129e18a033bSKonstantin Ananyev        }
130e18a033bSKonstantin Ananyev    }
131e18a033bSKonstantin Ananyev
132e18a033bSKonstantin Ananyev    if ((v->len == 0 || v->data[0] != '$')
133e18a033bSKonstantin Ananyev        && (ccv->conf_prefix || ccv->root_prefix))
134e18a033bSKonstantin Ananyev    {
135e18a033bSKonstantin Ananyev        if (ngx_conf_full_name(ccv->cf->cycle, v, ccv->conf_prefix) != NGX_OK) {
136e18a033bSKonstantin Ananyev            return NGX_ERROR;
137e18a033bSKonstantin Ananyev        }
138e18a033bSKonstantin Ananyev
139e18a033bSKonstantin Ananyev        ccv->conf_prefix = 0;
140e18a033bSKonstantin Ananyev        ccv->root_prefix = 0;
141e18a033bSKonstantin Ananyev    }
142e18a033bSKonstantin Ananyev
143e18a033bSKonstantin Ananyev    ccv->complex_value->value = *v;
144e18a033bSKonstantin Ananyev    ccv->complex_value->flushes = NULL;
145e18a033bSKonstantin Ananyev    ccv->complex_value->lengths = NULL;
146e18a033bSKonstantin Ananyev    ccv->complex_value->values = NULL;
147e18a033bSKonstantin Ananyev
148e18a033bSKonstantin Ananyev    if (nv == 0 && nc == 0) {
149e18a033bSKonstantin Ananyev        return NGX_OK;
150e18a033bSKonstantin Ananyev    }
151e18a033bSKonstantin Ananyev
152e18a033bSKonstantin Ananyev    n = nv + 1;
153e18a033bSKonstantin Ananyev
154e18a033bSKonstantin Ananyev    if (ngx_array_init(&flushes, ccv->cf->pool, n, sizeof(ngx_uint_t))
155e18a033bSKonstantin Ananyev        != NGX_OK)
156e18a033bSKonstantin Ananyev    {
157e18a033bSKonstantin Ananyev        return NGX_ERROR;
158e18a033bSKonstantin Ananyev    }
159e18a033bSKonstantin Ananyev
160e18a033bSKonstantin Ananyev    n = nv * (2 * sizeof(ngx_stream_script_copy_code_t)
161e18a033bSKonstantin Ananyev                  + sizeof(ngx_stream_script_var_code_t))
162e18a033bSKonstantin Ananyev        + sizeof(uintptr_t);
163e18a033bSKonstantin Ananyev
164e18a033bSKonstantin Ananyev    if (ngx_array_init(&lengths, ccv->cf->pool, n, 1) != NGX_OK) {
165e18a033bSKonstantin Ananyev        return NGX_ERROR;
166e18a033bSKonstantin Ananyev    }
167e18a033bSKonstantin Ananyev
168e18a033bSKonstantin Ananyev    n = (nv * (2 * sizeof(ngx_stream_script_copy_code_t)
169e18a033bSKonstantin Ananyev                   + sizeof(ngx_stream_script_var_code_t))
170e18a033bSKonstantin Ananyev                + sizeof(uintptr_t)
171e18a033bSKonstantin Ananyev                + v->len
172e18a033bSKonstantin Ananyev                + sizeof(uintptr_t) - 1)
173e18a033bSKonstantin Ananyev            & ~(sizeof(uintptr_t) - 1);
174e18a033bSKonstantin Ananyev
175e18a033bSKonstantin Ananyev    if (ngx_array_init(&values, ccv->cf->pool, n, 1) != NGX_OK) {
176e18a033bSKonstantin Ananyev        return NGX_ERROR;
177e18a033bSKonstantin Ananyev    }
178e18a033bSKonstantin Ananyev
179e18a033bSKonstantin Ananyev    pf = &flushes;
180e18a033bSKonstantin Ananyev    pl = &lengths;
181e18a033bSKonstantin Ananyev    pv = &values;
182e18a033bSKonstantin Ananyev
183e18a033bSKonstantin Ananyev    ngx_memzero(&sc, sizeof(ngx_stream_script_compile_t));
184e18a033bSKonstantin Ananyev
185e18a033bSKonstantin Ananyev    sc.cf = ccv->cf;
186e18a033bSKonstantin Ananyev    sc.source = v;
187e18a033bSKonstantin Ananyev    sc.flushes = &pf;
188e18a033bSKonstantin Ananyev    sc.lengths = &pl;
189e18a033bSKonstantin Ananyev    sc.values = &pv;
190e18a033bSKonstantin Ananyev    sc.complete_lengths = 1;
191e18a033bSKonstantin Ananyev    sc.complete_values = 1;
192e18a033bSKonstantin Ananyev    sc.zero = ccv->zero;
193e18a033bSKonstantin Ananyev    sc.conf_prefix = ccv->conf_prefix;
194e18a033bSKonstantin Ananyev    sc.root_prefix = ccv->root_prefix;
195e18a033bSKonstantin Ananyev
196e18a033bSKonstantin Ananyev    if (ngx_stream_script_compile(&sc) != NGX_OK) {
197e18a033bSKonstantin Ananyev        return NGX_ERROR;
198e18a033bSKonstantin Ananyev    }
199e18a033bSKonstantin Ananyev
200e18a033bSKonstantin Ananyev    if (flushes.nelts) {
201e18a033bSKonstantin Ananyev        ccv->complex_value->flushes = flushes.elts;
202e18a033bSKonstantin Ananyev        ccv->complex_value->flushes[flushes.nelts] = (ngx_uint_t) -1;
203e18a033bSKonstantin Ananyev    }
204e18a033bSKonstantin Ananyev
205e18a033bSKonstantin Ananyev    ccv->complex_value->lengths = lengths.elts;
206e18a033bSKonstantin Ananyev    ccv->complex_value->values = values.elts;
207e18a033bSKonstantin Ananyev
208e18a033bSKonstantin Ananyev    return NGX_OK;
209e18a033bSKonstantin Ananyev}
210e18a033bSKonstantin Ananyev
211e18a033bSKonstantin Ananyev
212e18a033bSKonstantin Ananyevchar *
213e18a033bSKonstantin Ananyevngx_stream_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd,
214e18a033bSKonstantin Ananyev    void *conf)
215e18a033bSKonstantin Ananyev{
216e18a033bSKonstantin Ananyev    char  *p = conf;
217e18a033bSKonstantin Ananyev
218e18a033bSKonstantin Ananyev    ngx_str_t                            *value;
219e18a033bSKonstantin Ananyev    ngx_stream_complex_value_t          **cv;
220e18a033bSKonstantin Ananyev    ngx_stream_compile_complex_value_t    ccv;
221e18a033bSKonstantin Ananyev
222e18a033bSKonstantin Ananyev    cv = (ngx_stream_complex_value_t **) (p + cmd->offset);
223e18a033bSKonstantin Ananyev
224e18a033bSKonstantin Ananyev    if (*cv != NULL) {
225e18a033bSKonstantin Ananyev        return "is duplicate";
226e18a033bSKonstantin Ananyev    }
227e18a033bSKonstantin Ananyev
228e18a033bSKonstantin Ananyev    *cv = ngx_palloc(cf->pool, sizeof(ngx_stream_complex_value_t));
229e18a033bSKonstantin Ananyev    if (*cv == NULL) {
230e18a033bSKonstantin Ananyev        return NGX_CONF_ERROR;
231e18a033bSKonstantin Ananyev    }
232e18a033bSKonstantin Ananyev
233e18a033bSKonstantin Ananyev    value = cf->args->elts;
234e18a033bSKonstantin Ananyev
235e18a033bSKonstantin Ananyev    ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t));
236e18a033bSKonstantin Ananyev
237e18a033bSKonstantin Ananyev    ccv.cf = cf;
238e18a033bSKonstantin Ananyev    ccv.value = &value[1];
239e18a033bSKonstantin Ananyev    ccv.complex_value = *cv;
240e18a033bSKonstantin Ananyev
241e18a033bSKonstantin Ananyev    if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) {
242e18a033bSKonstantin Ananyev        return NGX_CONF_ERROR;
243e18a033bSKonstantin Ananyev    }
244e18a033bSKonstantin Ananyev
245e18a033bSKonstantin Ananyev    return NGX_CONF_OK;
246e18a033bSKonstantin Ananyev}
247e18a033bSKonstantin Ananyev
248e18a033bSKonstantin Ananyev
249e18a033bSKonstantin Ananyevngx_uint_t
250e18a033bSKonstantin Ananyevngx_stream_script_variables_count(ngx_str_t *value)
251e18a033bSKonstantin Ananyev{
252e18a033bSKonstantin Ananyev    ngx_uint_t  i, n;
253e18a033bSKonstantin Ananyev
254e18a033bSKonstantin Ananyev    for (n = 0, i = 0; i < value->len; i++) {
255e18a033bSKonstantin Ananyev        if (value->data[i] == '$') {
256e18a033bSKonstantin Ananyev            n++;
257e18a033bSKonstantin Ananyev        }
258e18a033bSKonstantin Ananyev    }
259e18a033bSKonstantin Ananyev
260e18a033bSKonstantin Ananyev    return n;
261e18a033bSKonstantin Ananyev}
262e18a033bSKonstantin Ananyev
263e18a033bSKonstantin Ananyev
264e18a033bSKonstantin Ananyevngx_int_t
265e18a033bSKonstantin Ananyevngx_stream_script_compile(ngx_stream_script_compile_t *sc)
266e18a033bSKonstantin Ananyev{
267e18a033bSKonstantin Ananyev    u_char       ch;
268e18a033bSKonstantin Ananyev    ngx_str_t    name;
269e18a033bSKonstantin Ananyev    ngx_uint_t   i, bracket;
270e18a033bSKonstantin Ananyev
271e18a033bSKonstantin Ananyev    if (ngx_stream_script_init_arrays(sc) != NGX_OK) {
272e18a033bSKonstantin Ananyev        return NGX_ERROR;
273e18a033bSKonstantin Ananyev    }
274e18a033bSKonstantin Ananyev
275e18a033bSKonstantin Ananyev    for (i = 0; i < sc->source->len; /* void */ ) {
276e18a033bSKonstantin Ananyev
277e18a033bSKonstantin Ananyev        name.len = 0;
278e18a033bSKonstantin Ananyev
279e18a033bSKonstantin Ananyev        if (sc->source->data[i] == '$') {
280e18a033bSKonstantin Ananyev
281e18a033bSKonstantin Ananyev            if (++i == sc->source->len) {
282e18a033bSKonstantin Ananyev                goto invalid_variable;
283e18a033bSKonstantin Ananyev            }
284e18a033bSKonstantin Ananyev
285e18a033bSKonstantin Ananyev            if (sc->source->data[i] >= '1' && sc->source->data[i] <= '9') {
286e18a033bSKonstantin Ananyev#if (NGX_PCRE)
287e18a033bSKonstantin Ananyev                ngx_uint_t  n;
288e18a033bSKonstantin Ananyev
289e18a033bSKonstantin Ananyev                n = sc->source->data[i] - '0';
290e18a033bSKonstantin Ananyev
291e18a033bSKonstantin Ananyev                if (ngx_stream_script_add_capture_code(sc, n) != NGX_OK) {
292e18a033bSKonstantin Ananyev                    return NGX_ERROR;
293e18a033bSKonstantin Ananyev                }
294e18a033bSKonstantin Ananyev
295e18a033bSKonstantin Ananyev                i++;
296e18a033bSKonstantin Ananyev
297e18a033bSKonstantin Ananyev                continue;
298e18a033bSKonstantin Ananyev#else
299e18a033bSKonstantin Ananyev                ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0,
300e18a033bSKonstantin Ananyev                                   "using variable \"$%c\" requires "
301e18a033bSKonstantin Ananyev                                   "PCRE library", sc->source->data[i]);
302e18a033bSKonstantin Ananyev                return NGX_ERROR;
303e18a033bSKonstantin Ananyev#endif
304e18a033bSKonstantin Ananyev            }
305e18a033bSKonstantin Ananyev
306e18a033bSKonstantin Ananyev            if (sc->source->data[i] == '{') {
307e18a033bSKonstantin Ananyev                bracket = 1;
308e18a033bSKonstantin Ananyev
309e18a033bSKonstantin Ananyev                if (++i == sc->source->len) {
310e18a033bSKonstantin Ananyev                    goto invalid_variable;
311e18a033bSKonstantin Ananyev                }
312e18a033bSKonstantin Ananyev
313e18a033bSKonstantin Ananyev                name.data = &sc->source->data[i];
314e18a033bSKonstantin Ananyev
315e18a033bSKonstantin Ananyev            } else {
316e18a033bSKonstantin Ananyev                bracket = 0;
317e18a033bSKonstantin Ananyev                name.data = &sc->source->data[i];
318e18a033bSKonstantin Ananyev            }
319e18a033bSKonstantin Ananyev
320e18a033bSKonstantin Ananyev            for ( /* void */ ; i < sc->source->len; i++, name.len++) {
321e18a033bSKonstantin Ananyev                ch = sc->source->data[i];
322e18a033bSKonstantin Ananyev
323e18a033bSKonstantin Ananyev                if (ch == '}' && bracket) {
324e18a033bSKonstantin Ananyev                    i++;
325e18a033bSKonstantin Ananyev                    bracket = 0;
326e18a033bSKonstantin Ananyev                    break;
327e18a033bSKonstantin Ananyev                }
328e18a033bSKonstantin Ananyev
329e18a033bSKonstantin Ananyev                if ((ch >= 'A' && ch <= 'Z')
330e18a033bSKonstantin Ananyev                    || (ch >= 'a' && ch <= 'z')
331e18a033bSKonstantin Ananyev                    || (ch >= '0' && ch <= '9')
332e18a033bSKonstantin Ananyev                    || ch == '_')
333e18a033bSKonstantin Ananyev                {
334e18a033bSKonstantin Ananyev                    continue;
335e18a033bSKonstantin Ananyev                }
336e18a033bSKonstantin Ananyev
337e18a033bSKonstantin Ananyev                break;
338e18a033bSKonstantin Ananyev            }
339e18a033bSKonstantin Ananyev
340e18a033bSKonstantin Ananyev            if (bracket) {
341e18a033bSKonstantin Ananyev                ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0,
342e18a033bSKonstantin Ananyev                                   "the closing bracket in \"%V\" "
343e18a033bSKonstantin Ananyev                                   "variable is missing", &name);
344e18a033bSKonstantin Ananyev                return NGX_ERROR;
345e18a033bSKonstantin Ananyev            }
346e18a033bSKonstantin Ananyev
347e18a033bSKonstantin Ananyev            if (name.len == 0) {
348e18a033bSKonstantin Ananyev                goto invalid_variable;
349e18a033bSKonstantin Ananyev            }
350e18a033bSKonstantin Ananyev
351e18a033bSKonstantin Ananyev            sc->variables++;
352e18a033bSKonstantin Ananyev
353e18a033bSKonstantin Ananyev            if (ngx_stream_script_add_var_code(sc, &name) != NGX_OK) {
354e18a033bSKonstantin Ananyev                return NGX_ERROR;
355e18a033bSKonstantin Ananyev            }
356e18a033bSKonstantin Ananyev
357e18a033bSKonstantin Ananyev            continue;
358e18a033bSKonstantin Ananyev        }
359e18a033bSKonstantin Ananyev
360e18a033bSKonstantin Ananyev        name.data = &sc->source->data[i];
361e18a033bSKonstantin Ananyev
362e18a033bSKonstantin Ananyev        while (i < sc->source->len) {
363e18a033bSKonstantin Ananyev
364e18a033bSKonstantin Ananyev            if (sc->source->data[i] == '$') {
365e18a033bSKonstantin Ananyev                break;
366e18a033bSKonstantin Ananyev            }
367e18a033bSKonstantin Ananyev
368e18a033bSKonstantin Ananyev            i++;
369e18a033bSKonstantin Ananyev            name.len++;
370e18a033bSKonstantin Ananyev        }
371e18a033bSKonstantin Ananyev
372e18a033bSKonstantin Ananyev        sc->size += name.len;
373e18a033bSKonstantin Ananyev
374e18a033bSKonstantin Ananyev        if (ngx_stream_script_add_copy_code(sc, &name, (i == sc->source->len))
375e18a033bSKonstantin Ananyev            != NGX_OK)
376e18a033bSKonstantin Ananyev        {
377e18a033bSKonstantin Ananyev            return NGX_ERROR;
378e18a033bSKonstantin Ananyev        }
379e18a033bSKonstantin Ananyev    }
380e18a033bSKonstantin Ananyev
381e18a033bSKonstantin Ananyev    return ngx_stream_script_done(sc);
382e18a033bSKonstantin Ananyev
383e18a033bSKonstantin Ananyevinvalid_variable:
384e18a033bSKonstantin Ananyev
385e18a033bSKonstantin Ananyev    ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0, "invalid variable name");
386e18a033bSKonstantin Ananyev
387e18a033bSKonstantin Ananyev    return NGX_ERROR;
388e18a033bSKonstantin Ananyev}
389e18a033bSKonstantin Ananyev
390e18a033bSKonstantin Ananyev
391e18a033bSKonstantin Ananyevu_char *
392e18a033bSKonstantin Ananyevngx_stream_script_run(ngx_stream_session_t *s, ngx_str_t *value,
393e18a033bSKonstantin Ananyev    void *code_lengths, size_t len, void *code_values)
394e18a033bSKonstantin Ananyev{
395e18a033bSKonstantin Ananyev    ngx_uint_t                      i;
396e18a033bSKonstantin Ananyev    ngx_stream_script_code_pt       code;
397e18a033bSKonstantin Ananyev    ngx_stream_script_engine_t      e;
398e18a033bSKonstantin Ananyev    ngx_stream_core_main_conf_t    *cmcf;
399e18a033bSKonstantin Ananyev    ngx_stream_script_len_code_pt   lcode;
400e18a033bSKonstantin Ananyev
401e18a033bSKonstantin Ananyev    cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);
402e18a033bSKonstantin Ananyev
403e18a033bSKonstantin Ananyev    for (i = 0; i < cmcf->variables.nelts; i++) {
404e18a033bSKonstantin Ananyev        if (s->variables[i].no_cacheable) {
405e18a033bSKonstantin Ananyev            s->variables[i].valid = 0;
406e18a033bSKonstantin Ananyev            s->variables[i].not_found = 0;
407e18a033bSKonstantin Ananyev        }
408e18a033bSKonstantin Ananyev    }
409e18a033bSKonstantin Ananyev
410e18a033bSKonstantin Ananyev    ngx_memzero(&e, sizeof(ngx_stream_script_engine_t));
411e18a033bSKonstantin Ananyev
412e18a033bSKonstantin Ananyev    e.ip = code_lengths;
413e18a033bSKonstantin Ananyev    e.session = s;
414e18a033bSKonstantin Ananyev    e.flushed = 1;
415e18a033bSKonstantin Ananyev
416e18a033bSKonstantin Ananyev    while (*(uintptr_t *) e.ip) {
417e18a033bSKonstantin Ananyev        lcode = *(ngx_stream_script_len_code_pt *) e.ip;
418e18a033bSKonstantin Ananyev        len += lcode(&e);
419