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#include <nginx.h>
12e18a033bSKonstantin Ananyev
13e18a033bSKonstantin Ananyevstatic ngx_stream_variable_t *ngx_stream_add_prefix_variable(ngx_conf_t *cf,
14e18a033bSKonstantin Ananyev    ngx_str_t *name, ngx_uint_t flags);
15e18a033bSKonstantin Ananyev
16e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_variable_binary_remote_addr(
17e18a033bSKonstantin Ananyev    ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
18e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_variable_remote_addr(ngx_stream_session_t *s,
19e18a033bSKonstantin Ananyev    ngx_stream_variable_value_t *v, uintptr_t data);
20e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_variable_remote_port(ngx_stream_session_t *s,
21e18a033bSKonstantin Ananyev    ngx_stream_variable_value_t *v, uintptr_t data);
22e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_variable_proxy_protocol_addr(
23e18a033bSKonstantin Ananyev    ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
24e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_variable_proxy_protocol_port(
25e18a033bSKonstantin Ananyev    ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
26e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_variable_server_addr(ngx_stream_session_t *s,
27e18a033bSKonstantin Ananyev    ngx_stream_variable_value_t *v, uintptr_t data);
28e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_variable_server_port(ngx_stream_session_t *s,
29e18a033bSKonstantin Ananyev    ngx_stream_variable_value_t *v, uintptr_t data);
30e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_variable_bytes(ngx_stream_session_t *s,
31e18a033bSKonstantin Ananyev    ngx_stream_variable_value_t *v, uintptr_t data);
32e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_variable_session_time(ngx_stream_session_t *s,
33e18a033bSKonstantin Ananyev    ngx_stream_variable_value_t *v, uintptr_t data);
34e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_variable_status(ngx_stream_session_t *s,
35e18a033bSKonstantin Ananyev    ngx_stream_variable_value_t *v, uintptr_t data);
36e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_variable_connection(ngx_stream_session_t *s,
37e18a033bSKonstantin Ananyev    ngx_stream_variable_value_t *v, uintptr_t data);
38e18a033bSKonstantin Ananyev
39e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_variable_nginx_version(ngx_stream_session_t *s,
40e18a033bSKonstantin Ananyev    ngx_stream_variable_value_t *v, uintptr_t data);
41e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_variable_hostname(ngx_stream_session_t *s,
42e18a033bSKonstantin Ananyev    ngx_stream_variable_value_t *v, uintptr_t data);
43e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_variable_pid(ngx_stream_session_t *s,
44e18a033bSKonstantin Ananyev    ngx_stream_variable_value_t *v, uintptr_t data);
45e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_variable_msec(ngx_stream_session_t *s,
46e18a033bSKonstantin Ananyev    ngx_stream_variable_value_t *v, uintptr_t data);
47e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_variable_time_iso8601(ngx_stream_session_t *s,
48e18a033bSKonstantin Ananyev    ngx_stream_variable_value_t *v, uintptr_t data);
49e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_variable_time_local(ngx_stream_session_t *s,
50e18a033bSKonstantin Ananyev    ngx_stream_variable_value_t *v, uintptr_t data);
51e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_stream_variable_protocol(ngx_stream_session_t *s,
52e18a033bSKonstantin Ananyev    ngx_stream_variable_value_t *v, uintptr_t data);
53e18a033bSKonstantin Ananyev
54e18a033bSKonstantin Ananyev
55e18a033bSKonstantin Ananyevstatic ngx_stream_variable_t  ngx_stream_core_variables[] = {
56e18a033bSKonstantin Ananyev
57e18a033bSKonstantin Ananyev    { ngx_string("binary_remote_addr"), NULL,
58e18a033bSKonstantin Ananyev      ngx_stream_variable_binary_remote_addr, 0, 0, 0 },
59e18a033bSKonstantin Ananyev
60e18a033bSKonstantin Ananyev    { ngx_string("remote_addr"), NULL,
61e18a033bSKonstantin Ananyev      ngx_stream_variable_remote_addr, 0, 0, 0 },
62e18a033bSKonstantin Ananyev
63e18a033bSKonstantin Ananyev    { ngx_string("remote_port"), NULL,
64e18a033bSKonstantin Ananyev      ngx_stream_variable_remote_port, 0, 0, 0 },
65e18a033bSKonstantin Ananyev
66e18a033bSKonstantin Ananyev    { ngx_string("proxy_protocol_addr"), NULL,
67e18a033bSKonstantin Ananyev      ngx_stream_variable_proxy_protocol_addr, 0, 0, 0 },
68e18a033bSKonstantin Ananyev
69e18a033bSKonstantin Ananyev    { ngx_string("proxy_protocol_port"), NULL,
70e18a033bSKonstantin Ananyev      ngx_stream_variable_proxy_protocol_port, 0, 0, 0 },
71e18a033bSKonstantin Ananyev
72e18a033bSKonstantin Ananyev    { ngx_string("server_addr"), NULL,
73e18a033bSKonstantin Ananyev      ngx_stream_variable_server_addr, 0, 0, 0 },
74e18a033bSKonstantin Ananyev
75e18a033bSKonstantin Ananyev    { ngx_string("server_port"), NULL,
76e18a033bSKonstantin Ananyev      ngx_stream_variable_server_port, 0, 0, 0 },
77e18a033bSKonstantin Ananyev
78e18a033bSKonstantin Ananyev    { ngx_string("bytes_sent"), NULL, ngx_stream_variable_bytes,
79e18a033bSKonstantin Ananyev      0, 0, 0 },
80e18a033bSKonstantin Ananyev
81e18a033bSKonstantin Ananyev    { ngx_string("bytes_received"), NULL, ngx_stream_variable_bytes,
82e18a033bSKonstantin Ananyev      1, 0, 0 },
83e18a033bSKonstantin Ananyev
84e18a033bSKonstantin Ananyev    { ngx_string("session_time"), NULL, ngx_stream_variable_session_time,
85e18a033bSKonstantin Ananyev      0, NGX_STREAM_VAR_NOCACHEABLE, 0 },
86e18a033bSKonstantin Ananyev
87e18a033bSKonstantin Ananyev    { ngx_string("status"), NULL, ngx_stream_variable_status,
88e18a033bSKonstantin Ananyev      0, NGX_STREAM_VAR_NOCACHEABLE, 0 },
89e18a033bSKonstantin Ananyev
90e18a033bSKonstantin Ananyev    { ngx_string("connection"), NULL,
91e18a033bSKonstantin Ananyev      ngx_stream_variable_connection, 0, 0, 0 },
92e18a033bSKonstantin Ananyev
93e18a033bSKonstantin Ananyev    { ngx_string("nginx_version"), NULL, ngx_stream_variable_nginx_version,
94e18a033bSKonstantin Ananyev      0, 0, 0 },
95e18a033bSKonstantin Ananyev
96e18a033bSKonstantin Ananyev    { ngx_string("hostname"), NULL, ngx_stream_variable_hostname,
97e18a033bSKonstantin Ananyev      0, 0, 0 },
98e18a033bSKonstantin Ananyev
99e18a033bSKonstantin Ananyev    { ngx_string("pid"), NULL, ngx_stream_variable_pid,
100e18a033bSKonstantin Ananyev      0, 0, 0 },
101e18a033bSKonstantin Ananyev
102e18a033bSKonstantin Ananyev    { ngx_string("msec"), NULL, ngx_stream_variable_msec,
103e18a033bSKonstantin Ananyev      0, NGX_STREAM_VAR_NOCACHEABLE, 0 },
104e18a033bSKonstantin Ananyev
105e18a033bSKonstantin Ananyev    { ngx_string("time_iso8601"), NULL, ngx_stream_variable_time_iso8601,
106e18a033bSKonstantin Ananyev      0, NGX_STREAM_VAR_NOCACHEABLE, 0 },
107e18a033bSKonstantin Ananyev
108e18a033bSKonstantin Ananyev    { ngx_string("time_local"), NULL, ngx_stream_variable_time_local,
109e18a033bSKonstantin Ananyev      0, NGX_STREAM_VAR_NOCACHEABLE, 0 },
110e18a033bSKonstantin Ananyev
111e18a033bSKonstantin Ananyev    { ngx_string("protocol"), NULL,
112e18a033bSKonstantin Ananyev      ngx_stream_variable_protocol, 0, 0, 0 },
113e18a033bSKonstantin Ananyev
114e18a033bSKonstantin Ananyev    { ngx_null_string, NULL, NULL, 0, 0, 0 }
115e18a033bSKonstantin Ananyev};
116e18a033bSKonstantin Ananyev
117e18a033bSKonstantin Ananyev
118e18a033bSKonstantin Ananyevngx_stream_variable_value_t  ngx_stream_variable_null_value =
119e18a033bSKonstantin Ananyev    ngx_stream_variable("");
120e18a033bSKonstantin Ananyevngx_stream_variable_value_t  ngx_stream_variable_true_value =
121e18a033bSKonstantin Ananyev    ngx_stream_variable("1");
122e18a033bSKonstantin Ananyev
123e18a033bSKonstantin Ananyev
124e18a033bSKonstantin Ananyevstatic ngx_uint_t  ngx_stream_variable_depth = 100;
125e18a033bSKonstantin Ananyev
126e18a033bSKonstantin Ananyev
127e18a033bSKonstantin Ananyevngx_stream_variable_t *
128e18a033bSKonstantin Ananyevngx_stream_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags)
129e18a033bSKonstantin Ananyev{
130e18a033bSKonstantin Ananyev    ngx_int_t                     rc;
131e18a033bSKonstantin Ananyev    ngx_uint_t                    i;
132e18a033bSKonstantin Ananyev    ngx_hash_key_t               *key;
133e18a033bSKonstantin Ananyev    ngx_stream_variable_t        *v;
134e18a033bSKonstantin Ananyev    ngx_stream_core_main_conf_t  *cmcf;
135e18a033bSKonstantin Ananyev
136e18a033bSKonstantin Ananyev    if (name->len == 0) {
137e18a033bSKonstantin Ananyev        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
138e18a033bSKonstantin Ananyev                           "invalid variable name \"$\"");
139e18a033bSKonstantin Ananyev        return NULL;
140e18a033bSKonstantin Ananyev    }
141e18a033bSKonstantin Ananyev
142e18a033bSKonstantin Ananyev    if (flags & NGX_STREAM_VAR_PREFIX) {
143e18a033bSKonstantin Ananyev        return ngx_stream_add_prefix_variable(cf, name, flags);
144e18a033bSKonstantin Ananyev    }
145e18a033bSKonstantin Ananyev
146e18a033bSKonstantin Ananyev    cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
147e18a033bSKonstantin Ananyev
148e18a033bSKonstantin Ananyev    key = cmcf->variables_keys->keys.elts;
149e18a033bSKonstantin Ananyev    for (i = 0; i < cmcf->variables_keys->keys.nelts; i++) {
150e18a033bSKonstantin Ananyev        if (name->len != key[i].key.len
151e18a033bSKonstantin Ananyev            || ngx_strncasecmp(name->data, key[i].key.data, name->len) != 0)
152e18a033bSKonstantin Ananyev        {
153e18a033bSKonstantin Ananyev            continue;
154e18a033bSKonstantin Ananyev        }
155e18a033bSKonstantin Ananyev
156e18a033bSKonstantin Ananyev        v = key[i].value;
157e18a033bSKonstantin Ananyev
158e18a033bSKonstantin Ananyev        if (!(v->flags & NGX_STREAM_VAR_CHANGEABLE)) {
159e18a033bSKonstantin Ananyev            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
160e18a033bSKonstantin Ananyev                               "the duplicate \"%V\" variable", name);
161e18a033bSKonstantin Ananyev            return NULL;
162e18a033bSKonstantin Ananyev        }
163e18a033bSKonstantin Ananyev
164e18a033bSKonstantin Ananyev        v->flags &= flags | ~NGX_STREAM_VAR_WEAK;
165e18a033bSKonstantin Ananyev
166e18a033bSKonstantin Ananyev        return v;
167e18a033bSKonstantin Ananyev    }
168e18a033bSKonstantin Ananyev
169e18a033bSKonstantin Ananyev    v = ngx_palloc(cf->pool, sizeof(ngx_stream_variable_t));
170e18a033bSKonstantin Ananyev    if (v == NULL) {
171e18a033bSKonstantin Ananyev        return NULL;
172e18a033bSKonstantin Ananyev    }
173e18a033bSKonstantin Ananyev
174e18a033bSKonstantin Ananyev    v->name.len = name->len;
175e18a033bSKonstantin Ananyev    v->name.data = ngx_pnalloc(cf->pool, name->len);
176e18a033bSKonstantin Ananyev    if (v->name.data == NULL) {
177e18a033bSKonstantin Ananyev        return NULL;
178e18a033bSKonstantin Ananyev    }
179e18a033bSKonstantin Ananyev
180e18a033bSKonstantin Ananyev    ngx_strlow(v->name.data, name->data, name->len);
181e18a033bSKonstantin Ananyev
182e18a033bSKonstantin Ananyev    v->set_handler = NULL;
183e18a033bSKonstantin Ananyev    v->get_handler = NULL;
184e18a033bSKonstantin Ananyev    v->data = 0;
185e18a033bSKonstantin Ananyev    v->flags = flags;
186e18a033bSKonstantin Ananyev    v->index = 0;
187e18a033bSKonstantin Ananyev
188e18a033bSKonstantin Ananyev    rc = ngx_hash_add_key(cmcf->variables_keys, &v->name, v, 0);
189e18a033bSKonstantin Ananyev
190e18a033bSKonstantin Ananyev    if (rc == NGX_ERROR) {
191e18a033bSKonstantin Ananyev        return NULL;
192e18a033bSKonstantin Ananyev    }
193e18a033bSKonstantin Ananyev
194e18a033bSKonstantin Ananyev    if (rc == NGX_BUSY) {
195e18a033bSKonstantin Ananyev        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
196e18a033bSKonstantin Ananyev                           "conflicting variable name \"%V\"", name);
197e18a033bSKonstantin Ananyev        return NULL;
198e18a033bSKonstantin Ananyev    }
199e18a033bSKonstantin Ananyev
200e18a033bSKonstantin Ananyev    return v;
201e18a033bSKonstantin Ananyev}
202e18a033bSKonstantin Ananyev
203e18a033bSKonstantin Ananyev
204e18a033bSKonstantin Ananyevstatic ngx_stream_variable_t *
205e18a033bSKonstantin Ananyevngx_stream_add_prefix_variable(ngx_conf_t *cf, ngx_str_t *name,
206e18a033bSKonstantin Ananyev    ngx_uint_t flags)
207e18a033bSKonstantin Ananyev{
208e18a033bSKonstantin Ananyev    ngx_uint_t                    i;
209e18a033bSKonstantin Ananyev    ngx_stream_variable_t        *v;
210e18a033bSKonstantin Ananyev    ngx_stream_core_main_conf_t  *cmcf;
211e18a033bSKonstantin Ananyev
212e18a033bSKonstantin Ananyev    cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
213e18a033bSKonstantin Ananyev
214e18a033bSKonstantin Ananyev    v = cmcf->prefix_variables.elts;
215e18a033bSKonstantin Ananyev    for (i = 0; i < cmcf->prefix_variables.nelts; i++) {
216e18a033bSKonstantin Ananyev        if (name->len != v[i].name.len
217e18a033bSKonstantin Ananyev            || ngx_strncasecmp(name->data, v[i].name.data, name->len) != 0)
218e18a033bSKonstantin Ananyev        {
219e18a033bSKonstantin Ananyev            continue;
220e18a033bSKonstantin Ananyev        }
221e18a033bSKonstantin Ananyev
222e18a033bSKonstantin Ananyev        v = &v[i];
223e18a033bSKonstantin Ananyev
224e18a033bSKonstantin Ananyev        if (!(v->flags & NGX_STREAM_VAR_CHANGEABLE)) {
225e18a033bSKonstantin Ananyev            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
226e18a033bSKonstantin Ananyev                               "the duplicate \"%V\" variable", name);
227e18a033bSKonstantin Ananyev            return NULL;
228e18a033bSKonstantin Ananyev        }
229e18a033bSKonstantin Ananyev
230e18a033bSKonstantin Ananyev        v->flags &= flags | ~NGX_STREAM_VAR_WEAK;
231e18a033bSKonstantin Ananyev
232e18a033bSKonstantin Ananyev        return v;
233e18a033bSKonstantin Ananyev    }
234e18a033bSKonstantin Ananyev
235e18a033bSKonstantin Ananyev    v = ngx_array_push(&cmcf->prefix_variables);
236e18a033bSKonstantin Ananyev    if (v == NULL) {
237e18a033bSKonstantin Ananyev        return NULL;
238e18a033bSKonstantin Ananyev    }
239e18a033bSKonstantin Ananyev
240e18a033bSKonstantin Ananyev    v->name.len = name->len;
241e18a033bSKonstantin Ananyev    v->name.data = ngx_pnalloc(cf->pool, name->len);
242e18a033bSKonstantin Ananyev    if (v->name.data == NULL) {
243e18a033bSKonstantin Ananyev        return NULL;
244e18a033bSKonstantin Ananyev    }
245e18a033bSKonstantin Ananyev
246e18a033bSKonstantin Ananyev    ngx_strlow(v->name.data, name->data, name->len);
247e18a033bSKonstantin Ananyev
248e18a033bSKonstantin Ananyev    v->set_handler = NULL;
249e18a033bSKonstantin Ananyev    v->get_handler = NULL;
250e18a033bSKonstantin Ananyev    v->data = 0;
251e18a033bSKonstantin Ananyev    v->flags = flags;
252e18a033bSKonstantin Ananyev    v->index = 0;
253e18a033bSKonstantin Ananyev
254e18a033bSKonstantin Ananyev    return v;
255e18a033bSKonstantin Ananyev}
256e18a033bSKonstantin Ananyev
257e18a033bSKonstantin Ananyev
258e18a033bSKonstantin Ananyevngx_int_t
259e18a033bSKonstantin Ananyevngx_stream_get_variable_index(ngx_conf_t *cf, ngx_str_t *name)
260e18a033bSKonstantin Ananyev{
261e18a033bSKonstantin Ananyev    ngx_uint_t                    i;
262e18a033bSKonstantin Ananyev    ngx_stream_variable_t        *v;
263e18a033bSKonstantin Ananyev    ngx_stream_core_main_conf_t  *cmcf;
264e18a033bSKonstantin Ananyev
265e18a033bSKonstantin Ananyev    if (name->len == 0) {
266e18a033bSKonstantin Ananyev        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
267e18a033bSKonstantin Ananyev                           "invalid variable name \"$\"");
268e18a033bSKonstantin Ananyev        return NGX_ERROR;
269e18a033bSKonstantin Ananyev    }
270e18a033bSKonstantin Ananyev
271e18a033bSKonstantin Ananyev    cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
272e18a033bSKonstantin Ananyev
273e18a033bSKonstantin Ananyev    v = cmcf->variables.elts;
274e18a033bSKonstantin Ananyev
275e18a033bSKonstantin Ananyev    if (v == NULL) {
276e18a033bSKonstantin Ananyev        if (ngx_array_init(&cmcf->variables, cf->pool, 4,
277e18a033bSKonstantin Ananyev                           sizeof(ngx_stream_variable_t))
278e18a033bSKonstantin Ananyev            != NGX_OK)
279e18a033bSKonstantin Ananyev        {
280e18a033bSKonstantin Ananyev            return NGX_ERROR;
281e18a033bSKonstantin Ananyev        }
282e18a033bSKonstantin Ananyev
283e18a033bSKonstantin Ananyev    } else {
284e18a033bSKonstantin Ananyev        for (i = 0; i < cmcf->variables.nelts; i++) {
285e18a033bSKonstantin Ananyev            if (name->len != v[i].name.len
286e18a033bSKonstantin Ananyev                || ngx_strncasecmp(name->data, v[i].name.data, name->len) != 0)
287e18a033bSKonstantin Ananyev            {
288e18a033bSKonstantin Ananyev                continue;
289e18a033bSKonstantin Ananyev            }
290e18a033bSKonstantin Ananyev
291e18a033bSKonstantin Ananyev            return i;
292e18a033bSKonstantin Ananyev        }
293e18a033bSKonstantin Ananyev    }
294e18a033bSKonstantin Ananyev
295e18a033bSKonstantin Ananyev    v = ngx_array_push(&cmcf->variables);
296e18a033bSKonstantin Ananyev    if (v == NULL) {
297e18a033bSKonstantin Ananyev        return NGX_ERROR;
298e18a033bSKonstantin Ananyev    }
299e18a033bSKonstantin Ananyev
300e18a033bSKonstantin Ananyev    v->name.len = name->len;
301e18a033bSKonstantin Ananyev    v->name.data = ngx_pnalloc(cf->pool, name->len);
302e18a033bSKonstantin Ananyev    if (v->name.data == NULL) {
303e18a033bSKonstantin Ananyev        return NGX_ERROR;
304e18a033bSKonstantin Ananyev    }
305e18a033bSKonstantin Ananyev
306e18a033bSKonstantin Ananyev    ngx_strlow(v->name.data, name->data, name->len);
307e18a033bSKonstantin Ananyev
308e18a033bSKonstantin Ananyev    v->set_handler = NULL;
309e18a033bSKonstantin Ananyev    v->get_handler = NULL;
310e18a033bSKonstantin Ananyev    v->data = 0;
311e18a033bSKonstantin Ananyev    v->flags = 0;
312e18a033bSKonstantin Ananyev    v->index = cmcf->variables.nelts - 1;
313e18a033bSKonstantin Ananyev
314e18a033bSKonstantin Ananyev    return v->index;
315e18a033bSKonstantin Ananyev}
316e18a033bSKonstantin Ananyev
317e18a033bSKonstantin Ananyev
318e18a033bSKonstantin Ananyevngx_stream_variable_value_t *
319e18a033bSKonstantin Ananyevngx_stream_get_indexed_variable(ngx_stream_session_t *s, ngx_uint_t index)
320e18a033bSKonstantin Ananyev{
321e18a033bSKonstantin Ananyev    ngx_stream_variable_t        *v;
322e18a033bSKonstantin Ananyev    ngx_stream_core_main_conf_t  *cmcf;
323e18a033bSKonstantin Ananyev
324e18a033bSKonstantin Ananyev    cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);
325e18a033bSKonstantin Ananyev
326e18a033bSKonstantin Ananyev    if (cmcf->variables.nelts <= index) {
327e18a033bSKonstantin Ananyev        ngx_log_error(NGX_LOG_ALERT, s->connection->log, 0,
328e18a033bSKonstantin Ananyev                      "unknown variable index: %ui", index);
329e18a033bSKonstantin Ananyev        return NULL;
330e18a033bSKonstantin Ananyev    }
331e18a033bSKonstantin Ananyev
332e18a033bSKonstantin Ananyev    if (s->variables[index].not_found || s->variables[index].valid) {
333e18a033bSKonstantin Ananyev        return &s->variables[index];
334e18a033bSKonstantin Ananyev    }
335e18a033bSKonstantin Ananyev
336e18a033bSKonstantin Ananyev    v = cmcf->variables.elts;
337e18a033bSKonstantin Ananyev
338e18a033bSKonstantin Ananyev    if (ngx_stream_variable_depth == 0) {
339e18a033bSKonstantin Ananyev        ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
340e18a033bSKonstantin Ananyev                      "cycle while evaluating variable \"%V\"",
341e18a033bSKonstantin Ananyev                      &v[index].name);
342e18a033bSKonstantin Ananyev        return NULL;
343e18a033bSKonstantin Ananyev    }
344e18a033bSKonstantin Ananyev
345e18a033bSKonstantin Ananyev    ngx_stream_variable_depth--;
346e18a033bSKonstantin Ananyev
347e18a033bSKonstantin Ananyev    if (v[index].get_handler(s, &s->variables[index], v[index].data)
348e18a033bSKonstantin Ananyev        == NGX_OK)
349e18a033bSKonstantin Ananyev    {
350e18a033bSKonstantin Ananyev        ngx_stream_variable_depth++;
351e18a033bSKonstantin Ananyev
352e18a033bSKonstantin Ananyev        if (v[index].flags & NGX_STREAM_VAR_NOCACHEABLE) {
353e18a033bSKonstantin Ananyev            s->variables[index].no_cacheable = 1;
354e18a033bSKonstantin Ananyev        }
355e18a033bSKonstantin Ananyev
356e18a033bSKonstantin Ananyev        return &s->variables[index];
357e18a033bSKonstantin Ananyev    }
358e18a033bSKonstantin Ananyev
359e18a033bSKonstantin Ananyev    ngx_stream_variable_depth++;
360e18a033bSKonstantin Ananyev
361e18a033bSKonstantin Ananyev    s->variables[index].valid = 0;
362e18a033bSKonstantin Ananyev    s->variables[index].not_found = 1;
363e18a033bSKonstantin Ananyev
364e18a033bSKonstantin Ananyev    return NULL;
365e18a033bSKonstantin Ananyev}
366e18a033bSKonstantin Ananyev
367e18a033bSKonstantin Ananyev
368e18a033bSKonstantin Ananyevngx_stream_variable_value_t *
369e18a033bSKonstantin Ananyevngx_stream_get_flushed_variable(ngx_stream_session_t *s, ngx_uint_t index)
370e18a033bSKonstantin Ananyev{
371e18a033bSKonstantin Ananyev    ngx_stream_variable_value_t  *v;
372e18a033bSKonstantin Ananyev
373e18a033bSKonstantin Ananyev    v = &s->variables[index];
374e18a033bSKonstantin Ananyev
375e18a033bSKonstantin Ananyev    if (v->valid || v->not_found) {
376e18a033bSKonstantin Ananyev        if (!v->no_cacheable) {
377e18a033bSKonstantin Ananyev            return v;
378e18a033bSKonstantin Ananyev        }
379e18a033bSKonstantin Ananyev
380e18a033bSKonstantin Ananyev        v->valid = 0;
381e18a033bSKonstantin Ananyev        v->not_found = 0;
382e18a033bSKonstantin Ananyev    }
383e18a033bSKonstantin Ananyev
384e18a033bSKonstantin Ananyev    return ngx_stream_get_indexed_variable(s, index);
385e18a033bSKonstantin Ananyev}
386e18a033bSKonstantin Ananyev
387e18a033bSKonstantin Ananyev
388e18a033bSKonstantin Ananyevngx_stream_variable_value_t *
389e18a033bSKonstantin Ananyevngx_stream_get_variable(ngx_stream_session_t *s, ngx_str_t *name,
390e18a033bSKonstantin Ananyev    ngx_uint_t key)
391e18a033bSKonstantin Ananyev{
392e18a033bSKonstantin Ananyev    size_t                        len;
393e18a033bSKonstantin Ananyev    ngx_uint_t                    i, n;
394e18a033bSKonstantin Ananyev    ngx_stream_variable_t        *v;
395e18a033bSKonstantin Ananyev    ngx_stream_variable_value_t  *vv;
396e18a033bSKonstantin Ananyev    ngx_stream_core_main_conf_t  *cmcf;
397e18a033bSKonstantin Ananyev
398e18a033bSKonstantin Ananyev    cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);
399e18a033bSKonstantin Ananyev
400e18a033bSKonstantin Ananyev    v = ngx_hash_find(&cmcf->variables_hash, key, name->data, name->len);
401e18a033bSKonstantin Ananyev
402e18a033bSKonstantin Ananyev    if (v) {
403e18a033bSKonstantin Ananyev        if (v->flags & NGX_STREAM_VAR_INDEXED) {
404e18a033bSKonstantin Ananyev            return ngx_stream_get_flushed_variable(s, v->index);
405e18a033bSKonstantin Ananyev        }
406e18a033bSKonstantin Ananyev
407e18a033bSKonstantin Ananyev        if (ngx_stream_variable_depth == 0) {
408e18a033bSKonstantin Ananyev            ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
409e18a033bSKonstantin Ananyev                          "cycle while evaluating variable \"%V\"", name);
410e18a033bSKonstantin Ananyev            return NULL;
411e18a033bSKonstantin Ananyev        }
412e18a033bSKonstantin Ananyev
413e18a033bSKonstantin Ananyev        ngx_stream_variable_depth--;
414e18a033bSKonstantin Ananyev
415e18a033bSKonstantin Ananyev        vv = ngx_palloc(s->connection->pool,