Mercurial > hg > nginx-quic
annotate src/stream/ngx_stream_script.c @ 7623:72b792bb3885
HTTP/2: fixed socket leak with an incomplete HEADERS frame.
A connection could get stuck without timers if a client has partially sent
the HEADERS frame such that it was split on the individual header boundary.
In this case, it cannot be processed without the rest of the HEADERS frame.
The fix is to call ngx_http_v2_state_headers_save() in this case. Normally,
it would be called from the ngx_http_v2_state_header_block() handler on the
next iteration, when there is not enough data to continue processing. This
isn't the case if recv_buffer became empty and there's no more data to read.
author | Sergey Kandaurov <pluknet@nginx.com> |
---|---|
date | Wed, 05 Feb 2020 16:29:23 +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 } |