Mercurial > hg > nginx
annotate src/stream/ngx_stream_script.c @ 7665:d127837c714f
Stream: fixed processing of zero length UDP packets (ticket #1982).
author | Vladimir Homutov <vl@nginx.com> |
---|---|
date | Mon, 08 Jun 2020 11:40:34 +0300 |
parents | b82162b8496a |
children | bdd4d89370a7 |
rev | line source |
---|---|
6607 | 1 |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 * Copyright (C) Nginx, Inc. | |
5 */ | |
6 | |
7 | |
8 #include <ngx_config.h> | |
9 #include <ngx_core.h> | |
10 #include <ngx_stream.h> | |
11 | |
12 | |
13 static ngx_int_t ngx_stream_script_init_arrays( | |
14 ngx_stream_script_compile_t *sc); | |
15 static ngx_int_t ngx_stream_script_done(ngx_stream_script_compile_t *sc); | |
16 static ngx_int_t ngx_stream_script_add_copy_code( | |
17 ngx_stream_script_compile_t *sc, ngx_str_t *value, ngx_uint_t last); | |
18 static ngx_int_t ngx_stream_script_add_var_code( | |
19 ngx_stream_script_compile_t *sc, ngx_str_t *name); | |
20 #if (NGX_PCRE) | |
21 static ngx_int_t ngx_stream_script_add_capture_code( | |
22 ngx_stream_script_compile_t *sc, ngx_uint_t n); | |
23 #endif | |
24 static ngx_int_t ngx_stream_script_add_full_name_code( | |
25 ngx_stream_script_compile_t *sc); | |
26 static size_t ngx_stream_script_full_name_len_code( | |
27 ngx_stream_script_engine_t *e); | |
28 static void ngx_stream_script_full_name_code(ngx_stream_script_engine_t *e); | |
29 | |
30 | |
31 #define ngx_stream_script_exit (u_char *) &ngx_stream_script_exit_code | |
32 | |
33 static uintptr_t ngx_stream_script_exit_code = (uintptr_t) NULL; | |
34 | |
35 | |
36 void | |
37 ngx_stream_script_flush_complex_value(ngx_stream_session_t *s, | |
38 ngx_stream_complex_value_t *val) | |
39 { | |
40 ngx_uint_t *index; | |
41 | |
42 index = val->flushes; | |
43 | |
44 if (index) { | |
45 while (*index != (ngx_uint_t) -1) { | |
46 | |
47 if (s->variables[*index].no_cacheable) { | |
48 s->variables[*index].valid = 0; | |
49 s->variables[*index].not_found = 0; | |
50 } | |
51 | |
52 index++; | |
53 } | |
54 } | |
55 } | |
56 | |
57 | |
58 ngx_int_t | |
59 ngx_stream_complex_value(ngx_stream_session_t *s, | |
60 ngx_stream_complex_value_t *val, ngx_str_t *value) | |
61 { | |
62 size_t len; | |
63 ngx_stream_script_code_pt code; | |
64 ngx_stream_script_engine_t e; | |
65 ngx_stream_script_len_code_pt lcode; | |
66 | |
67 if (val->lengths == NULL) { | |
68 *value = val->value; | |
69 return NGX_OK; | |
70 } | |
71 | |
72 ngx_stream_script_flush_complex_value(s, val); | |
73 | |
74 ngx_memzero(&e, sizeof(ngx_stream_script_engine_t)); | |
75 | |
76 e.ip = val->lengths; | |
77 e.session = s; | |
78 e.flushed = 1; | |
79 | |
80 len = 0; | |
81 | |
82 while (*(uintptr_t *) e.ip) { | |
83 lcode = *(ngx_stream_script_len_code_pt *) e.ip; | |
84 len += lcode(&e); | |
85 } | |
86 | |
87 value->len = len; | |
88 value->data = ngx_pnalloc(s->connection->pool, len); | |
89 if (value->data == NULL) { | |
90 return NGX_ERROR; | |
91 } | |
92 | |
93 e.ip = val->values; | |
94 e.pos = value->data; | |
95 e.buf = *value; | |
96 | |
97 while (*(uintptr_t *) e.ip) { | |
98 code = *(ngx_stream_script_code_pt *) e.ip; | |
99 code((ngx_stream_script_engine_t *) &e); | |
100 } | |
101 | |
102 *value = e.buf; | |
103 | |
104 return NGX_OK; | |
105 } | |
106 | |
107 | |
7503
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
108 size_t |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
109 ngx_stream_complex_value_size(ngx_stream_session_t *s, |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
110 ngx_stream_complex_value_t *val, size_t default_value) |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
111 { |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
112 size_t size; |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
113 ngx_str_t value; |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
114 |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
115 if (val == NULL) { |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
116 return default_value; |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
117 } |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
118 |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
119 if (val->lengths == NULL) { |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
120 return val->u.size; |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
121 } |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
122 |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
123 if (ngx_stream_complex_value(s, val, &value) != NGX_OK) { |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
124 return default_value; |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
125 } |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
126 |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
127 size = ngx_parse_size(&value); |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
128 |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
129 if (size == (size_t) NGX_ERROR) { |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
130 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
131 "invalid size \"%V\"", &value); |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
132 return default_value; |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
133 } |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
134 |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
135 return size; |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
136 } |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
137 |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
138 |
6607 | 139 ngx_int_t |
140 ngx_stream_compile_complex_value(ngx_stream_compile_complex_value_t *ccv) | |
141 { | |
142 ngx_str_t *v; | |
143 ngx_uint_t i, n, nv, nc; | |
144 ngx_array_t flushes, lengths, values, *pf, *pl, *pv; | |
145 ngx_stream_script_compile_t sc; | |
146 | |
147 v = ccv->value; | |
148 | |
149 nv = 0; | |
150 nc = 0; | |
151 | |
152 for (i = 0; i < v->len; i++) { | |
153 if (v->data[i] == '$') { | |
154 if (v->data[i + 1] >= '1' && v->data[i + 1] <= '9') { | |
155 nc++; | |
156 | |
157 } else { | |
158 nv++; | |
159 } | |
160 } | |
161 } | |
162 | |
163 if ((v->len == 0 || v->data[0] != '$') | |
164 && (ccv->conf_prefix || ccv->root_prefix)) | |
165 { | |
166 if (ngx_conf_full_name(ccv->cf->cycle, v, ccv->conf_prefix) != NGX_OK) { | |
167 return NGX_ERROR; | |
168 } | |
169 | |
170 ccv->conf_prefix = 0; | |
171 ccv->root_prefix = 0; | |
172 } | |
173 | |
174 ccv->complex_value->value = *v; | |
175 ccv->complex_value->flushes = NULL; | |
176 ccv->complex_value->lengths = NULL; | |
177 ccv->complex_value->values = NULL; | |
178 | |
179 if (nv == 0 && nc == 0) { | |
180 return NGX_OK; | |
181 } | |
182 | |
183 n = nv + 1; | |
184 | |
185 if (ngx_array_init(&flushes, ccv->cf->pool, n, sizeof(ngx_uint_t)) | |
186 != NGX_OK) | |
187 { | |
188 return NGX_ERROR; | |
189 } | |
190 | |
191 n = nv * (2 * sizeof(ngx_stream_script_copy_code_t) | |
192 + sizeof(ngx_stream_script_var_code_t)) | |
193 + sizeof(uintptr_t); | |
194 | |
195 if (ngx_array_init(&lengths, ccv->cf->pool, n, 1) != NGX_OK) { | |
196 return NGX_ERROR; | |
197 } | |
198 | |
199 n = (nv * (2 * sizeof(ngx_stream_script_copy_code_t) | |
200 + sizeof(ngx_stream_script_var_code_t)) | |
201 + sizeof(uintptr_t) | |
202 + v->len | |
203 + sizeof(uintptr_t) - 1) | |
204 & ~(sizeof(uintptr_t) - 1); | |
205 | |
206 if (ngx_array_init(&values, ccv->cf->pool, n, 1) != NGX_OK) { | |
207 return NGX_ERROR; | |
208 } | |
209 | |
210 pf = &flushes; | |
211 pl = &lengths; | |
212 pv = &values; | |
213 | |
214 ngx_memzero(&sc, sizeof(ngx_stream_script_compile_t)); | |
215 | |
216 sc.cf = ccv->cf; | |
217 sc.source = v; | |
218 sc.flushes = &pf; | |
219 sc.lengths = &pl; | |
220 sc.values = &pv; | |
221 sc.complete_lengths = 1; | |
222 sc.complete_values = 1; | |
223 sc.zero = ccv->zero; | |
224 sc.conf_prefix = ccv->conf_prefix; | |
225 sc.root_prefix = ccv->root_prefix; | |
226 | |
227 if (ngx_stream_script_compile(&sc) != NGX_OK) { | |
228 return NGX_ERROR; | |
229 } | |
230 | |
231 if (flushes.nelts) { | |
232 ccv->complex_value->flushes = flushes.elts; | |
233 ccv->complex_value->flushes[flushes.nelts] = (ngx_uint_t) -1; | |
234 } | |
235 | |
236 ccv->complex_value->lengths = lengths.elts; | |
237 ccv->complex_value->values = values.elts; | |
238 | |
239 return NGX_OK; | |
240 } | |
241 | |
242 | |
243 char * | |
244 ngx_stream_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, | |
245 void *conf) | |
246 { | |
247 char *p = conf; | |
248 | |
249 ngx_str_t *value; | |
250 ngx_stream_complex_value_t **cv; | |
251 ngx_stream_compile_complex_value_t ccv; | |
252 | |
253 cv = (ngx_stream_complex_value_t **) (p + cmd->offset); | |
254 | |
255 if (*cv != NULL) { | |
6940
39ff6939266e
Unified error messages about duplicate directives.
Ruslan Ermilov <ru@nginx.com>
parents:
6678
diff
changeset
|
256 return "is duplicate"; |
6607 | 257 } |
258 | |
259 *cv = ngx_palloc(cf->pool, sizeof(ngx_stream_complex_value_t)); | |
260 if (*cv == NULL) { | |
261 return NGX_CONF_ERROR; | |
262 } | |
263 | |
264 value = cf->args->elts; | |
265 | |
266 ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); | |
267 | |
268 ccv.cf = cf; | |
269 ccv.value = &value[1]; | |
270 ccv.complex_value = *cv; | |
271 | |
272 if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { | |
273 return NGX_CONF_ERROR; | |
274 } | |
275 | |
276 return NGX_CONF_OK; | |
277 } | |
278 | |
279 | |
7503
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
280 char * |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
281 ngx_stream_set_complex_value_size_slot(ngx_conf_t *cf, ngx_command_t *cmd, |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
282 void *conf) |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
283 { |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
284 char *p = conf; |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
285 |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
286 char *rv; |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
287 ngx_stream_complex_value_t *cv; |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
288 |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
289 rv = ngx_stream_set_complex_value_slot(cf, cmd, conf); |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
290 |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
291 if (rv != NGX_CONF_OK) { |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
292 return rv; |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
293 } |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
294 |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
295 cv = *(ngx_stream_complex_value_t **) (p + cmd->offset); |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
296 |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
297 if (cv->lengths) { |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
298 return NGX_CONF_OK; |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
299 } |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
300 |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
301 cv->u.size = ngx_parse_size(&cv->value); |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
302 if (cv->u.size == (size_t) NGX_ERROR) { |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
303 return "invalid value"; |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
304 } |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
305 |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
306 return NGX_CONF_OK; |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
307 } |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
308 |
b82162b8496a
Added ngx_http_set_complex_value_size_slot().
Ruslan Ermilov <ru@nginx.com>
parents:
7271
diff
changeset
|
309 |
6607 | 310 ngx_uint_t |
311 ngx_stream_script_variables_count(ngx_str_t *value) | |
312 { | |
313 ngx_uint_t i, n; | |
314 | |
315 for (n = 0, i = 0; i < value->len; i++) { | |
316 if (value->data[i] == '$') { | |
317 n++; | |
318 } | |
319 } | |
320 | |
321 return n; | |
322 } | |
323 | |
324 | |
325 ngx_int_t | |
326 ngx_stream_script_compile(ngx_stream_script_compile_t *sc) | |
327 { | |
328 u_char ch; | |
329 ngx_str_t name; | |
330 ngx_uint_t i, bracket; | |
331 | |
332 if (ngx_stream_script_init_arrays(sc) != NGX_OK) { | |
333 return NGX_ERROR; | |
334 } | |
335 | |
336 for (i = 0; i < sc->source->len; /* void */ ) { | |
337 | |
338 name.len = 0; | |
339 | |
340 if (sc->source->data[i] == '$') { | |
341 | |
342 if (++i == sc->source->len) { | |
343 goto invalid_variable; | |
344 } | |
345 | |
6644
af642539cd53
Fixed regex captures handling without PCRE.
Vladimir Homutov <vl@nginx.com>
parents:
6607
diff
changeset
|
346 if (sc->source->data[i] >= '1' && sc->source->data[i] <= '9') { |
6607 | 347 #if (NGX_PCRE) |
6644
af642539cd53
Fixed regex captures handling without PCRE.
Vladimir Homutov <vl@nginx.com>
parents:
6607
diff
changeset
|
348 ngx_uint_t n; |
6607 | 349 |
350 n = sc->source->data[i] - '0'; | |
351 | |
352 if (ngx_stream_script_add_capture_code(sc, n) != NGX_OK) { | |
353 return NGX_ERROR; | |
354 } | |
355 | |
356 i++; | |
357 | |
358 continue; | |
6644
af642539cd53
Fixed regex captures handling without PCRE.
Vladimir Homutov <vl@nginx.com>
parents:
6607
diff
changeset
|
359 #else |
af642539cd53
Fixed regex captures handling without PCRE.
Vladimir Homutov <vl@nginx.com>
parents:
6607
diff
changeset
|
360 ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0, |
af642539cd53
Fixed regex captures handling without PCRE.
Vladimir Homutov <vl@nginx.com>
parents:
6607
diff
changeset
|
361 "using variable \"$%c\" requires " |
af642539cd53
Fixed regex captures handling without PCRE.
Vladimir Homutov <vl@nginx.com>
parents:
6607
diff
changeset
|
362 "PCRE library", sc->source->data[i]); |
af642539cd53
Fixed regex captures handling without PCRE.
Vladimir Homutov <vl@nginx.com>
parents:
6607
diff
changeset
|
363 return NGX_ERROR; |
af642539cd53
Fixed regex captures handling without PCRE.
Vladimir Homutov <vl@nginx.com>
parents:
6607
diff
changeset
|
364 #endif |
6607 | 365 } |
366 | |
367 if (sc->source->data[i] == '{') { | |
368 bracket = 1; | |
369 | |
370 if (++i == sc->source->len) { | |
371 goto invalid_variable; | |
372 } | |
373 | |
374 name.data = &sc->source->data[i]; | |
375 | |
376 } else { | |
377 bracket = 0; | |
378 name.data = &sc->source->data[i]; | |
379 } | |
380 | |
381 for ( /* void */ ; i < sc->source->len; i++, name.len++) { | |
382 ch = sc->source->data[i]; | |
383 | |
384 if (ch == '}' && bracket) { | |
385 i++; | |
386 bracket = 0; | |
387 break; | |
388 } | |
389 | |
390 if ((ch >= 'A' && ch <= 'Z') | |
391 || (ch >= 'a' && ch <= 'z') | |
392 || (ch >= '0' && ch <= '9') | |
393 || ch == '_') | |
394 { | |
395 continue; | |
396 } | |
397 | |
398 break; | |
399 } | |
400 | |
401 if (bracket) { | |
402 ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0, | |
403 "the closing bracket in \"%V\" " | |
404 "variable is missing", &name); | |
405 return NGX_ERROR; | |
406 } | |
407 | |
408 if (name.len == 0) { | |
409 goto invalid_variable; | |
410 } | |
411 | |
412 sc->variables++; | |
413 | |
414 if (ngx_stream_script_add_var_code(sc, &name) != NGX_OK) { | |
415 return NGX_ERROR; | |
416 } | |
417 | |
418 continue; | |
419 } | |
420 | |
421 name.data = &sc->source->data[i]; | |
422 | |
423 while (i < sc->source->len) { | |
424 | |
425 if (sc->source->data[i] == '$') { | |
426 break; | |
427 } | |
428 | |
429 i++; | |
430 name.len++; | |
431 } | |
432 | |
433 sc->size += name.len; | |
434 | |
435 if (ngx_stream_script_add_copy_code(sc, &name, (i == sc->source->len)) | |
436 != NGX_OK) | |
437 { | |
438 return NGX_ERROR; | |
439 } | |
440 } | |
441 | |
442 return ngx_stream_script_done(sc); | |
443 | |
444 invalid_variable: | |
445 | |
446 ngx_conf_log_error(NGX_LOG_EMERG, sc->cf, 0, "invalid variable name"); | |
447 | |
448 return NGX_ERROR; | |
449 } | |
450 | |
451 | |
6678 | 452 u_char * |
453 ngx_stream_script_run(ngx_stream_session_t *s, ngx_str_t *value, | |
454 void *code_lengths, size_t len, void *code_values) | |
455 { | |
456 ngx_uint_t i; | |
457 ngx_stream_script_code_pt code; | |
458 ngx_stream_script_engine_t e; | |
459 ngx_stream_core_main_conf_t *cmcf; | |
460 ngx_stream_script_len_code_pt lcode; | |
461 | |
462 cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module); | |
463 | |
464 for (i = 0; i < cmcf->variables.nelts; i++) { | |
465 if (s->variables[i].no_cacheable) { | |
466 s->variables[i].valid = 0; | |
467 s->variables[i].not_found = 0; | |
468 } | |
469 } | |
470 | |
471 ngx_memzero(&e, sizeof(ngx_stream_script_engine_t)); | |
472 | |
473 e.ip = code_lengths; | |
474 e.session = s; | |
475 e.flushed = 1; | |
476 | |
477 while (*(uintptr_t *) e.ip) { | |
478 lcode = *(ngx_stream_script_len_code_pt *) e.ip; | |
479 len += lcode(&e); | |
480 } | |
481 | |
482 | |
483 value->len = len; | |
484 value->data = ngx_pnalloc(s->connection->pool, len); | |
485 if (value->data == NULL) { | |
486 return NULL; | |
487 } | |
488 | |
489 e.ip = code_values; | |
490 e.pos = value->data; | |
491 | |
492 while (*(uintptr_t *) e.ip) { | |
493 code = *(ngx_stream_script_code_pt *) e.ip; | |
494 code((ngx_stream_script_engine_t *) &e); | |
495 } | |
496 | |
497 return e.pos; | |
498 } | |
499 | |
500 | |
501 void | |
502 ngx_stream_script_flush_no_cacheable_variables(ngx_stream_session_t *s, | |
503 ngx_array_t *indices) | |
504 { | |
505 ngx_uint_t n, *index; | |
506 | |
507 if (indices) { | |
508 index = indices->elts; | |
509 for (n = 0; n < indices->nelts; n++) { | |
510 if (s->variables[index[n]].no_cacheable) { | |
511 s->variables[index[n]].valid = 0; | |
512 s->variables[index[n]].not_found = 0; | |
513 } | |
514 } | |
515 } | |
516 } | |
517 | |
518 | |
6607 | 519 static ngx_int_t |
520 ngx_stream_script_init_arrays(ngx_stream_script_compile_t *sc) | |
521 { | |
522 ngx_uint_t n; | |
523 | |
524 if (sc->flushes && *sc->flushes == NULL) { | |
525 n = sc->variables ? sc->variables : 1; | |
526 *sc->flushes = ngx_array_create(sc->cf->pool, n, sizeof(ngx_uint_t)); | |
527 if (*sc->flushes == NULL) { | |
528 return NGX_ERROR; | |
529 } | |
530 } | |
531 | |
532 if (*sc->lengths == NULL) { | |
533 n = sc->variables * (2 * sizeof(ngx_stream_script_copy_code_t) | |
534 + sizeof(ngx_stream_script_var_code_t)) | |
535 + sizeof(uintptr_t); | |
536 | |
537 *sc->lengths = ngx_array_create(sc->cf->pool, n, 1); | |
538 if (*sc->lengths == NULL) { | |
539 return NGX_ERROR; | |
540 } | |
541 } | |
542 | |
543 if (*sc->values == NULL) { | |
544 n = (sc->variables * (2 * sizeof(ngx_stream_script_copy_code_t) | |
545 + sizeof(ngx_stream_script_var_code_t)) | |
546 + sizeof(uintptr_t) | |
547 + sc->source->len | |
548 + sizeof(uintptr_t) - 1) | |
549 & ~(sizeof(uintptr_t) - 1); | |
550 | |
551 *sc->values = ngx_array_create(sc->cf->pool, n, 1); | |
552 if (*sc->values == NULL) { | |
553 return NGX_ERROR; | |
554 } | |
555 } | |
556 | |
557 sc->variables = 0; | |
558 | |
559 return NGX_OK; | |
560 } | |
561 | |
562 | |
563 static ngx_int_t | |
564 ngx_stream_script_done(ngx_stream_script_compile_t *sc) | |
565 { | |
566 ngx_str_t zero; | |
567 uintptr_t *code; | |
568 | |
569 if (sc->zero) { | |
570 | |
571 zero.len = 1; | |
572 zero.data = (u_char *) "\0"; | |
573 | |
574 if (ngx_stream_script_add_copy_code(sc, &zero, 0) != NGX_OK) { | |
575 return NGX_ERROR; | |
576 } | |
577 } | |
578 | |
579 if (sc->conf_prefix || sc->root_prefix) { | |
580 if (ngx_stream_script_add_full_name_code(sc) != NGX_OK) { | |
581 return NGX_ERROR; | |
582 } | |
583 } | |
584 | |
585 if (sc->complete_lengths) { | |
586 code = ngx_stream_script_add_code(*sc->lengths, sizeof(uintptr_t), | |
587 NULL); | |
588 if (code == NULL) { | |
589 return NGX_ERROR; | |
590 } | |
591 | |
592 *code = (uintptr_t) NULL; | |
593 } | |
594 | |
595 if (sc->complete_values) { | |
596 code = ngx_stream_script_add_code(*sc->values, sizeof(uintptr_t), | |
597 &sc->main); | |
598 if (code == NULL) { | |
599 return NGX_ERROR; | |
600 } | |
601 | |
602 *code = (uintptr_t) NULL; | |
603 } | |
604 | |
605 return NGX_OK; | |
606 } | |
607 | |
608 | |
609 void * | |
610 ngx_stream_script_add_code(ngx_array_t *codes, size_t size, void *code) | |
611 { | |
612 u_char *elts, **p; | |
613 void *new; | |
614 | |
615 elts = codes->elts; | |
616 | |
617 new = ngx_array_push_n(codes, size); | |
618 if (new == NULL) { | |
619 return NULL; | |
620 } | |
621 | |
622 if (code) { | |
623 if (elts != codes->elts) { | |
624 p = code; | |
625 *p += (u_char *) codes->elts - elts; | |
626 } | |
627 } | |
628 | |
629 return new; | |
630 } | |
631 | |
632 | |
633 static ngx_int_t | |
634 ngx_stream_script_add_copy_code(ngx_stream_script_compile_t *sc, | |
635 ngx_str_t *value, ngx_uint_t last) | |
636 { | |
637 u_char *p; | |
638 size_t size, len, zero; | |
639 ngx_stream_script_copy_code_t *code; | |
640 | |
641 zero = (sc->zero && last); | |
642 len = value->len + zero; | |
643 | |
644 code = ngx_stream_script_add_code(*sc->lengths, | |
645 sizeof(ngx_stream_script_copy_code_t), | |
646 NULL); | |
647 if (code == NULL) { | |
648 return NGX_ERROR; | |
649 } | |
650 | |
7271
9e25a5380a21
Silenced -Wcast-function-type warnings (closes #1546).
Sergey Kandaurov <pluknet@nginx.com>
parents:
6940
diff
changeset
|
651 code->code = (ngx_stream_script_code_pt) (void *) |
9e25a5380a21
Silenced -Wcast-function-type warnings (closes #1546).
Sergey Kandaurov <pluknet@nginx.com>
parents:
6940
diff
changeset
|
652 ngx_stream_script_copy_len_code; |
6607 | 653 code->len = len; |
654 | |
655 size = (sizeof(ngx_stream_script_copy_code_t) + len + sizeof(uintptr_t) - 1) | |
656 & ~(sizeof(uintptr_t) - 1); | |
657 | |
658 code = ngx_stream_script_add_code(*sc->values, size, &sc->main); | |
659 if (code == NULL) { | |
660 return NGX_ERROR; | |
661 } | |
662 | |
663 code->code = ngx_stream_script_copy_code; | |
664 code->len = len; | |
665 | |
666 p = ngx_cpymem((u_char *) code + sizeof(ngx_stream_script_copy_code_t), | |
667 value->data, value->len); | |
668 | |
669 if (zero) { | |
670 *p = '\0'; | |
671 sc->zero = 0; | |
672 } | |
673 | |
674 return NGX_OK; | |
675 } | |
676 | |
677 | |
678 size_t | |
679 ngx_stream_script_copy_len_code(ngx_stream_script_engine_t *e) | |
680 { | |
681 ngx_stream_script_copy_code_t *code; | |
682 | |
683 code = (ngx_stream_script_copy_code_t *) e->ip; | |
684 | |
685 e->ip += sizeof(ngx_stream_script_copy_code_t); | |
686 | |
687 return code->len; | |
688 } | |
689 | |
690 | |
691 void | |
692 ngx_stream_script_copy_code(ngx_stream_script_engine_t *e) | |
693 { | |
694 u_char *p; | |
695 ngx_stream_script_copy_code_t *code; | |
696 | |
697 code = (ngx_stream_script_copy_code_t *) e->ip; | |
698 | |
699 p = e->pos; | |
700 | |
701 if (!e->skip) { | |
702 e->pos = ngx_copy(p, e->ip + sizeof(ngx_stream_script_copy_code_t), | |
703 code->len); | |
704 } | |
705 | |
706 e->ip += sizeof(ngx_stream_script_copy_code_t) | |
707 + ((code->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1)); | |
708 | |
709 ngx_log_debug2(NGX_LOG_DEBUG_STREAM, e->session->connection->log, 0, | |
710 "stream script copy: \"%*s\"", e->pos - p, p); | |
711 } | |
712 | |
713 | |
714 static ngx_int_t | |
715 ngx_stream_script_add_var_code(ngx_stream_script_compile_t *sc, ngx_str_t *name) | |
716 { | |
717 ngx_int_t index, *p; | |
718 ngx_stream_script_var_code_t *code; | |
719 | |
720 index = ngx_stream_get_variable_index(sc->cf, name); | |
721 | |
722 if (index == NGX_ERROR) { | |
723 return NGX_ERROR; | |
724 } | |
725 | |
726 if (sc->flushes) { | |
727 p = ngx_array_push(*sc->flushes); | |
728 if (p == NULL) { | |
729 return NGX_ERROR; | |
730 } | |
731 | |
732 *p = index; | |
733 } | |
734 | |
735 code = ngx_stream_script_add_code(*sc->lengths, | |
736 sizeof(ngx_stream_script_var_code_t), | |
737 NULL); | |
738 if (code == NULL) { | |
739 return NGX_ERROR; | |
740 } | |
741 | |
7271
9e25a5380a21
Silenced -Wcast-function-type warnings (closes #1546).
Sergey Kandaurov <pluknet@nginx.com>
parents:
6940
diff
changeset
|
742 code->code = (ngx_stream_script_code_pt) (void *) |
9e25a5380a21
Silenced -Wcast-function-type warnings (closes #1546).
Sergey Kandaurov <pluknet@nginx.com>
parents:
6940
diff
changeset
|
743 ngx_stream_script_copy_var_len_code; |
6607 | 744 code->index = (uintptr_t) index; |
745 | |
746 code = ngx_stream_script_add_code(*sc->values, | |
747 sizeof(ngx_stream_script_var_code_t), | |
748 &sc->main); | |
749 if (code == NULL) { | |
750 return NGX_ERROR; | |
751 } | |
752 | |
753 code->code = ngx_stream_script_copy_var_code; | |
754 code->index = (uintptr_t) index; | |
755 | |
756 return NGX_OK; | |
757 } | |
758 | |
759 | |
760 size_t | |
761 ngx_stream_script_copy_var_len_code(ngx_stream_script_engine_t *e) | |
762 { | |
763 ngx_stream_variable_value_t *value; | |
764 ngx_stream_script_var_code_t *code; | |
765 | |
766 code = (ngx_stream_script_var_code_t *) e->ip; | |
767 | |
768 e->ip += sizeof(ngx_stream_script_var_code_t); | |
769 | |
770 if (e->flushed) { | |
771 value = ngx_stream_get_indexed_variable(e->session, code->index); | |
772 | |
773 } else { | |
774 value = ngx_stream_get_flushed_variable(e->session, code->index); | |
775 } | |
776 | |
777 if (value && !value->not_found) { | |
778 return value->len; | |
779 } | |
780 | |
781 return 0; | |
782 } | |
783 | |
784 | |
785 void | |
786 ngx_stream_script_copy_var_code(ngx_stream_script_engine_t *e) | |
787 { | |
788 u_char *p; | |
789 ngx_stream_variable_value_t *value; | |
790 ngx_stream_script_var_code_t *code; | |
791 | |
792 code = (ngx_stream_script_var_code_t *) e->ip; | |
793 | |
794 e->ip += sizeof(ngx_stream_script_var_code_t); | |
795 | |
796 if (!e->skip) { | |
797 | |
798 if (e->flushed) { | |
799 value = ngx_stream_get_indexed_variable(e->session, code->index); | |
800 | |
801 } else { | |
802 value = ngx_stream_get_flushed_variable(e->session, code->index); | |
803 } | |
804 | |
805 if (value && !value->not_found) { | |
806 p = e->pos; | |
807 e->pos = ngx_copy(p, value->data, value->len); | |
808 | |
809 ngx_log_debug2(NGX_LOG_DEBUG_STREAM, | |
810 e->session->connection->log, 0, | |
811 "stream script var: \"%*s\"", e->pos - p, p); | |
812 } | |
813 } | |
814 } | |
815 | |
816 | |
817 #if (NGX_PCRE) | |
818 | |
819 static ngx_int_t | |
820 ngx_stream_script_add_capture_code(ngx_stream_script_compile_t *sc, | |
821 ngx_uint_t n) | |
822 { | |
823 ngx_stream_script_copy_capture_code_t *code; | |
824 | |
825 code = ngx_stream_script_add_code(*sc->lengths, | |
826 sizeof(ngx_stream_script_copy_capture_code_t), | |
827 NULL); | |
828 if (code == NULL) { | |
829 return NGX_ERROR; | |
830 } | |
831 | |
7271
9e25a5380a21
Silenced -Wcast-function-type warnings (closes #1546).
Sergey Kandaurov <pluknet@nginx.com>
parents:
6940
diff
changeset
|
832 code->code = (ngx_stream_script_code_pt) (void *) |
9e25a5380a21
Silenced -Wcast-function-type warnings (closes #1546).
Sergey Kandaurov <pluknet@nginx.com>
parents:
6940
diff
changeset
|
833 ngx_stream_script_copy_capture_len_code; |
6607 | 834 code->n = 2 * n; |
835 | |
836 | |
837 code = ngx_stream_script_add_code(*sc->values, | |
838 sizeof(ngx_stream_script_copy_capture_code_t), | |
839 &sc->main); | |
840 if (code == NULL) { | |
841 return NGX_ERROR; | |
842 } | |
843 | |
844 code->code = ngx_stream_script_copy_capture_code; | |
845 code->n = 2 * n; | |
846 | |
847 if (sc->ncaptures < n) { | |
848 sc->ncaptures = n; | |
849 } | |
850 | |
851 return NGX_OK; | |
852 } | |
853 | |
854 | |
855 size_t | |
856 ngx_stream_script_copy_capture_len_code(ngx_stream_script_engine_t *e) | |
857 { | |
858 int *cap; | |
859 ngx_uint_t n; | |
860 ngx_stream_session_t *s; | |
861 ngx_stream_script_copy_capture_code_t *code; | |
862 | |
863 s = e->session; | |
864 | |
865 code = (ngx_stream_script_copy_capture_code_t *) e->ip; | |
866 | |
867 e->ip += sizeof(ngx_stream_script_copy_capture_code_t); | |
868 | |
869 n = code->n; | |
870 | |
871 if (n < s->ncaptures) { | |
872 cap = s->captures; | |
873 return cap[n + 1] - cap[n]; | |
874 } | |
875 | |
876 return 0; | |
877 } | |
878 | |
879 | |
880 void | |
881 ngx_stream_script_copy_capture_code(ngx_stream_script_engine_t *e) | |
882 { | |
883 int *cap; | |
884 u_char *p, *pos; | |
885 ngx_uint_t n; | |
886 ngx_stream_session_t *s; | |
887 ngx_stream_script_copy_capture_code_t *code; | |
888 | |
889 s = e->session; | |
890 | |
891 code = (ngx_stream_script_copy_capture_code_t *) e->ip; | |
892 | |
893 e->ip += sizeof(ngx_stream_script_copy_capture_code_t); | |
894 | |
895 n = code->n; | |
896 | |
897 pos = e->pos; | |
898 | |
899 if (n < s->ncaptures) { | |
900 cap = s->captures; | |
901 p = s->captures_data; | |
902 e->pos = ngx_copy(pos, &p[cap[n]], cap[n + 1] - cap[n]); | |
903 } | |
904 | |
905 ngx_log_debug2(NGX_LOG_DEBUG_STREAM, e->session->connection->log, 0, | |
906 "stream script capture: \"%*s\"", e->pos - pos, pos); | |
907 } | |
908 | |
909 #endif | |
910 | |
911 | |
912 static ngx_int_t | |
913 ngx_stream_script_add_full_name_code(ngx_stream_script_compile_t *sc) | |
914 { | |
915 ngx_stream_script_full_name_code_t *code; | |
916 | |
917 code = ngx_stream_script_add_code(*sc->lengths, | |
918 sizeof(ngx_stream_script_full_name_code_t), | |
919 NULL); | |
920 if (code == NULL) { | |
921 return NGX_ERROR; | |
922 } | |
923 | |
7271
9e25a5380a21
Silenced -Wcast-function-type warnings (closes #1546).
Sergey Kandaurov <pluknet@nginx.com>
parents:
6940
diff
changeset
|
924 code->code = (ngx_stream_script_code_pt) (void *) |
6607 | 925 ngx_stream_script_full_name_len_code; |
926 code->conf_prefix = sc->conf_prefix; | |
927 | |
928 code = ngx_stream_script_add_code(*sc->values, | |
929 sizeof(ngx_stream_script_full_name_code_t), &sc->main); | |
930 if (code == NULL) { | |
931 return NGX_ERROR; | |
932 } | |
933 | |
934 code->code = ngx_stream_script_full_name_code; | |
935 code->conf_prefix = sc->conf_prefix; | |
936 | |
937 return NGX_OK; | |
938 } | |
939 | |
940 | |
941 static size_t | |
942 ngx_stream_script_full_name_len_code(ngx_stream_script_engine_t *e) | |
943 { | |
944 ngx_stream_script_full_name_code_t *code; | |
945 | |
946 code = (ngx_stream_script_full_name_code_t *) e->ip; | |
947 | |
948 e->ip += sizeof(ngx_stream_script_full_name_code_t); | |
949 | |
950 return code->conf_prefix ? ngx_cycle->conf_prefix.len: | |
951 ngx_cycle->prefix.len; | |
952 } | |
953 | |
954 | |
955 static void | |
956 ngx_stream_script_full_name_code(ngx_stream_script_engine_t *e) | |
957 { | |
958 ngx_stream_script_full_name_code_t *code; | |
959 | |
960 ngx_str_t value, *prefix; | |
961 | |
962 code = (ngx_stream_script_full_name_code_t *) e->ip; | |
963 | |
964 value.data = e->buf.data; | |
965 value.len = e->pos - e->buf.data; | |
966 | |
967 prefix = code->conf_prefix ? (ngx_str_t *) &ngx_cycle->conf_prefix: | |
968 (ngx_str_t *) &ngx_cycle->prefix; | |
969 | |
970 if (ngx_get_full_name(e->session->connection->pool, prefix, &value) | |
971 != NGX_OK) | |
972 { | |
973 e->ip = ngx_stream_script_exit; | |
974 return; | |
975 } | |
976 | |
977 e->buf = value; | |
978 | |
979 ngx_log_debug1(NGX_LOG_DEBUG_STREAM, e->session->connection->log, 0, | |
980 "stream script fullname: \"%V\"", &value); | |
981 | |
982 e->ip += sizeof(ngx_stream_script_full_name_code_t); | |
983 } |