Line data Source code
1 :
2 : /*
3 : * Copyright (C) Yichun Zhang (agentzh)
4 : */
5 :
6 :
7 : #ifndef DDEBUG
8 : #define DDEBUG 0
9 : #endif
10 : #include "ddebug.h"
11 :
12 :
13 : #include "ngx_http_lua_script.h"
14 :
15 :
16 : static void *ngx_http_lua_script_add_code(ngx_array_t *codes, size_t size);
17 : static size_t ngx_http_lua_script_copy_len_code(
18 : ngx_http_lua_script_engine_t *e);
19 : static void ngx_http_lua_script_copy_code(ngx_http_lua_script_engine_t *e);
20 : static ngx_int_t ngx_http_lua_script_add_copy_code(
21 : ngx_http_lua_script_compile_t *sc, ngx_str_t *value, ngx_uint_t last);
22 : static ngx_int_t ngx_http_lua_script_compile(ngx_http_lua_script_compile_t *sc);
23 : static ngx_int_t ngx_http_lua_script_add_capture_code(
24 : ngx_http_lua_script_compile_t *sc, ngx_uint_t n);
25 : static size_t ngx_http_lua_script_copy_capture_len_code(
26 : ngx_http_lua_script_engine_t *e);
27 : static void ngx_http_lua_script_copy_capture_code(
28 : ngx_http_lua_script_engine_t *e);
29 : static ngx_int_t ngx_http_lua_script_done(ngx_http_lua_script_compile_t *sc);
30 : static ngx_int_t ngx_http_lua_script_init_arrays(
31 : ngx_http_lua_script_compile_t *sc);
32 :
33 :
34 : ngx_int_t
35 0 : ngx_http_lua_compile_complex_value(ngx_http_lua_compile_complex_value_t *ccv)
36 : {
37 : ngx_str_t *v;
38 : ngx_uint_t i, n, nv;
39 : ngx_array_t lengths, values, *pl, *pv;
40 :
41 : ngx_http_lua_script_compile_t sc;
42 :
43 0 : v = ccv->value;
44 :
45 0 : nv = 0;
46 :
47 0 : for (i = 0; i < v->len; i++) {
48 0 : if (v->data[i] == '$') {
49 0 : nv++;
50 : }
51 : }
52 :
53 0 : ccv->complex_value->value = *v;
54 0 : ccv->complex_value->lengths = NULL;
55 0 : ccv->complex_value->values = NULL;
56 :
57 0 : if (nv == 0) {
58 0 : return NGX_OK;
59 : }
60 :
61 0 : n = nv * (2 * sizeof(ngx_http_lua_script_copy_code_t)
62 : + sizeof(ngx_http_lua_script_capture_code_t))
63 : + sizeof(uintptr_t);
64 :
65 0 : if (ngx_array_init(&lengths, ccv->pool, n, 1) != NGX_OK) {
66 0 : return NGX_ERROR;
67 : }
68 :
69 0 : n = (nv * (2 * sizeof(ngx_http_lua_script_copy_code_t)
70 : + sizeof(ngx_http_lua_script_capture_code_t))
71 : + sizeof(uintptr_t)
72 0 : + sizeof(uintptr_t) - 1)
73 : & ~(sizeof(uintptr_t) - 1);
74 :
75 0 : if (ngx_array_init(&values, ccv->pool, n, 1) != NGX_OK) {
76 0 : return NGX_ERROR;
77 : }
78 :
79 0 : pl = &lengths;
80 0 : pv = &values;
81 :
82 0 : ngx_memzero(&sc, sizeof(ngx_http_lua_script_compile_t));
83 :
84 0 : sc.pool = ccv->pool;
85 0 : sc.log = ccv->log;
86 0 : sc.source = v;
87 0 : sc.lengths = &pl;
88 0 : sc.values = &pv;
89 0 : sc.complete_lengths = 1;
90 0 : sc.complete_values = 1;
91 :
92 0 : if (ngx_http_lua_script_compile(&sc) != NGX_OK) {
93 0 : ngx_array_destroy(&lengths);
94 0 : ngx_array_destroy(&values);
95 0 : return NGX_ERROR;
96 : }
97 :
98 0 : ccv->complex_value->lengths = lengths.elts;
99 0 : ccv->complex_value->values = values.elts;
100 :
101 0 : return NGX_OK;
102 : }
103 :
104 :
105 : ngx_int_t
106 0 : ngx_http_lua_complex_value(ngx_http_request_t *r, ngx_str_t *subj,
107 : size_t offset, ngx_int_t count, int *cap,
108 : ngx_http_lua_complex_value_t *val, luaL_Buffer *luabuf)
109 : {
110 : size_t len;
111 : u_char *p;
112 : ngx_http_lua_script_code_pt code;
113 : ngx_http_lua_script_len_code_pt lcode;
114 : ngx_http_lua_script_engine_t e;
115 :
116 0 : if (val->lengths == NULL) {
117 0 : luaL_addlstring(luabuf, (char *) &subj->data[offset], cap[0] - offset);
118 0 : luaL_addlstring(luabuf, (char *) val->value.data, val->value.len);
119 :
120 0 : return NGX_OK;
121 : }
122 :
123 0 : ngx_memzero(&e, sizeof(ngx_http_lua_script_engine_t));
124 :
125 0 : e.log = r->connection->log;
126 0 : e.ncaptures = count * 2;
127 0 : e.captures = cap;
128 0 : e.captures_data = subj->data;
129 :
130 0 : e.ip = val->lengths;
131 :
132 0 : len = 0;
133 :
134 0 : while (*(uintptr_t *) e.ip) {
135 0 : lcode = *(ngx_http_lua_script_len_code_pt *) e.ip;
136 0 : len += lcode(&e);
137 : }
138 :
139 0 : p = ngx_pnalloc(r->pool, len);
140 0 : if (p == NULL) {
141 0 : return NGX_ERROR;
142 : }
143 :
144 0 : e.ip = val->values;
145 0 : e.pos = p;
146 :
147 0 : while (*(uintptr_t *) e.ip) {
148 0 : code = *(ngx_http_lua_script_code_pt *) e.ip;
149 0 : code((ngx_http_lua_script_engine_t *) &e);
150 : }
151 :
152 0 : luaL_addlstring(luabuf, (char *) &subj->data[offset], cap[0] - offset);
153 0 : luaL_addlstring(luabuf, (char *) p, len);
154 :
155 0 : ngx_pfree(r->pool, p);
156 :
157 0 : return NGX_OK;
158 : }
159 :
160 :
161 : static ngx_int_t
162 0 : ngx_http_lua_script_compile(ngx_http_lua_script_compile_t *sc)
163 : {
164 : u_char ch;
165 : ngx_str_t name;
166 : ngx_uint_t i, bracket;
167 : unsigned num_var;
168 0 : ngx_uint_t n = 0;
169 :
170 0 : if (ngx_http_lua_script_init_arrays(sc) != NGX_OK) {
171 0 : return NGX_ERROR;
172 : }
173 :
174 0 : for (i = 0; i < sc->source->len; /* void */ ) {
175 :
176 0 : name.len = 0;
177 :
178 0 : if (sc->source->data[i] == '$') {
179 :
180 0 : if (++i == sc->source->len) {
181 0 : goto invalid_variable;
182 : }
183 :
184 0 : if (sc->source->data[i] == '$') {
185 0 : name.data = &sc->source->data[i];
186 0 : i++;
187 0 : name.len++;
188 :
189 0 : if (ngx_http_lua_script_add_copy_code(sc, &name,
190 0 : (i == sc->source->len))
191 : != NGX_OK)
192 : {
193 0 : return NGX_ERROR;
194 : }
195 :
196 0 : continue;
197 : }
198 :
199 0 : if (sc->source->data[i] >= '0' && sc->source->data[i] <= '9') {
200 0 : num_var = 1;
201 0 : n = 0;
202 :
203 : } else {
204 0 : num_var = 0;
205 : }
206 :
207 0 : if (sc->source->data[i] == '{') {
208 0 : bracket = 1;
209 :
210 0 : if (++i == sc->source->len) {
211 0 : goto invalid_variable;
212 : }
213 :
214 0 : if (sc->source->data[i] >= '0' && sc->source->data[i] <= '9') {
215 0 : num_var = 1;
216 0 : n = 0;
217 : }
218 :
219 0 : name.data = &sc->source->data[i];
220 :
221 : } else {
222 0 : bracket = 0;
223 0 : name.data = &sc->source->data[i];
224 : }
225 :
226 0 : for ( /* void */ ; i < sc->source->len; i++, name.len++) {
227 0 : ch = sc->source->data[i];
228 :
229 0 : if (ch == '}' && bracket) {
230 0 : i++;
231 0 : bracket = 0;
232 0 : break;
233 : }
234 :
235 0 : if (num_var) {
236 0 : if (ch >= '0' && ch <= '9') {
237 0 : n = n * 10 + (ch - '0');
238 0 : continue;
239 : }
240 :
241 0 : break;
242 : }
243 :
244 : /* not a number variable like $1, $2, etc */
245 :
246 0 : if ((ch >= 'A' && ch <= 'Z')
247 0 : || (ch >= 'a' && ch <= 'z')
248 0 : || (ch >= '0' && ch <= '9')
249 0 : || ch == '_')
250 : {
251 0 : continue;
252 : }
253 :
254 0 : break;
255 : }
256 :
257 0 : if (bracket) {
258 0 : ngx_log_error(NGX_LOG_ERR, sc->log, 0,
259 : "the closing bracket in \"%V\" "
260 : "variable is missing", &name);
261 0 : return NGX_ERROR;
262 : }
263 :
264 0 : if (name.len == 0) {
265 0 : goto invalid_variable;
266 : }
267 :
268 0 : if (!num_var) {
269 0 : ngx_log_error(NGX_LOG_ERR, sc->log, 0,
270 : "attempt to use named capturing variable "
271 : "\"%V\" (named captures not supported yet)",
272 : &name);
273 :
274 0 : return NGX_ERROR;
275 : }
276 :
277 0 : sc->variables++;
278 :
279 0 : if (ngx_http_lua_script_add_capture_code(sc, n) != NGX_OK) {
280 0 : return NGX_ERROR;
281 : }
282 :
283 0 : continue;
284 : }
285 :
286 0 : name.data = &sc->source->data[i];
287 :
288 0 : while (i < sc->source->len) {
289 :
290 0 : if (sc->source->data[i] == '$') {
291 0 : break;
292 : }
293 :
294 0 : i++;
295 0 : name.len++;
296 : }
297 :
298 0 : if (ngx_http_lua_script_add_copy_code(sc, &name, (i == sc->source->len))
299 : != NGX_OK)
300 : {
301 0 : return NGX_ERROR;
302 : }
303 : }
304 :
305 0 : return ngx_http_lua_script_done(sc);
306 :
307 0 : invalid_variable:
308 :
309 0 : ngx_log_error(NGX_LOG_ERR, sc->log, 0,
310 : "lua script: invalid capturing variable name found in \"%V\"",
311 : sc->source);
312 :
313 0 : return NGX_ERROR;
314 : }
315 :
316 :
317 : static ngx_int_t
318 0 : ngx_http_lua_script_add_copy_code(ngx_http_lua_script_compile_t *sc,
319 : ngx_str_t *value, ngx_uint_t last)
320 : {
321 : size_t size, len;
322 : ngx_http_lua_script_copy_code_t *code;
323 :
324 0 : len = value->len;
325 :
326 0 : code = ngx_http_lua_script_add_code(*sc->lengths,
327 : sizeof(ngx_http_lua_script_copy_code_t));
328 0 : if (code == NULL) {
329 0 : return NGX_ERROR;
330 : }
331 :
332 0 : code->code = (ngx_http_lua_script_code_pt)
333 : ngx_http_lua_script_copy_len_code;
334 0 : code->len = len;
335 :
336 0 : size = (sizeof(ngx_http_lua_script_copy_code_t) + len +
337 0 : sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1);
338 :
339 0 : code = ngx_http_lua_script_add_code(*sc->values, size);
340 0 : if (code == NULL) {
341 0 : return NGX_ERROR;
342 : }
343 :
344 0 : code->code = ngx_http_lua_script_copy_code;
345 0 : code->len = len;
346 :
347 0 : ngx_memcpy((u_char *) code + sizeof(ngx_http_lua_script_copy_code_t),
348 : value->data, value->len);
349 :
350 0 : return NGX_OK;
351 : }
352 :
353 :
354 : static size_t
355 0 : ngx_http_lua_script_copy_len_code(ngx_http_lua_script_engine_t *e)
356 : {
357 : ngx_http_lua_script_copy_code_t *code;
358 :
359 0 : code = (ngx_http_lua_script_copy_code_t *) e->ip;
360 :
361 0 : e->ip += sizeof(ngx_http_lua_script_copy_code_t);
362 :
363 0 : return code->len;
364 : }
365 :
366 :
367 : static void
368 0 : ngx_http_lua_script_copy_code(ngx_http_lua_script_engine_t *e)
369 : {
370 : u_char *p;
371 : ngx_http_lua_script_copy_code_t *code;
372 :
373 0 : code = (ngx_http_lua_script_copy_code_t *) e->ip;
374 :
375 0 : p = e->pos;
376 :
377 0 : if (!e->skip) {
378 0 : e->pos = ngx_copy(p, e->ip + sizeof(ngx_http_lua_script_copy_code_t),
379 : code->len);
380 : }
381 :
382 0 : e->ip += sizeof(ngx_http_lua_script_copy_code_t)
383 0 : + ((code->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1));
384 :
385 0 : ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->log, 0,
386 : "lua script copy: \"%*s\"", e->pos - p, p);
387 0 : }
388 :
389 :
390 : static ngx_int_t
391 0 : ngx_http_lua_script_add_capture_code(ngx_http_lua_script_compile_t *sc,
392 : ngx_uint_t n)
393 : {
394 : ngx_http_lua_script_capture_code_t *code;
395 :
396 0 : code = ngx_http_lua_script_add_code(*sc->lengths,
397 : sizeof(ngx_http_lua_script_capture_code_t));
398 0 : if (code == NULL) {
399 0 : return NGX_ERROR;
400 : }
401 :
402 0 : code->code = (ngx_http_lua_script_code_pt)
403 : ngx_http_lua_script_copy_capture_len_code;
404 0 : code->n = 2 * n;
405 :
406 0 : code = ngx_http_lua_script_add_code(*sc->values,
407 : sizeof(ngx_http_lua_script_capture_code_t));
408 0 : if (code == NULL) {
409 0 : return NGX_ERROR;
410 : }
411 :
412 0 : code->code = ngx_http_lua_script_copy_capture_code;
413 0 : code->n = 2 * n;
414 :
415 0 : return NGX_OK;
416 : }
417 :
418 :
419 : static size_t
420 0 : ngx_http_lua_script_copy_capture_len_code(ngx_http_lua_script_engine_t *e)
421 : {
422 : int *cap;
423 : ngx_uint_t n;
424 : ngx_http_lua_script_capture_code_t *code;
425 :
426 0 : code = (ngx_http_lua_script_capture_code_t *) e->ip;
427 :
428 0 : e->ip += sizeof(ngx_http_lua_script_capture_code_t);
429 :
430 0 : n = code->n;
431 :
432 0 : if (n < e->ncaptures) {
433 0 : cap = e->captures;
434 0 : return cap[n + 1] - cap[n];
435 : }
436 :
437 0 : return 0;
438 : }
439 :
440 :
441 : static void
442 0 : ngx_http_lua_script_copy_capture_code(ngx_http_lua_script_engine_t *e)
443 : {
444 : int *cap;
445 : u_char *p, *pos;
446 : ngx_uint_t n;
447 : ngx_http_lua_script_capture_code_t *code;
448 :
449 0 : code = (ngx_http_lua_script_capture_code_t *) e->ip;
450 :
451 0 : e->ip += sizeof(ngx_http_lua_script_capture_code_t);
452 :
453 0 : n = code->n;
454 :
455 0 : pos = e->pos;
456 :
457 0 : if (n < e->ncaptures) {
458 :
459 0 : cap = e->captures;
460 0 : p = e->captures_data;
461 :
462 0 : e->pos = ngx_copy(pos, &p[cap[n]], cap[n + 1] - cap[n]);
463 : }
464 :
465 0 : ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->log, 0,
466 : "lua script capture: \"%*s\"", e->pos - pos, pos);
467 0 : }
468 :
469 :
470 : static ngx_int_t
471 0 : ngx_http_lua_script_init_arrays(ngx_http_lua_script_compile_t *sc)
472 : {
473 : ngx_uint_t n;
474 :
475 0 : if (*sc->lengths == NULL) {
476 0 : n = sc->variables * (2 * sizeof(ngx_http_lua_script_copy_code_t)
477 : + sizeof(ngx_http_lua_script_capture_code_t))
478 : + sizeof(uintptr_t);
479 :
480 0 : *sc->lengths = ngx_array_create(sc->pool, n, 1);
481 0 : if (*sc->lengths == NULL) {
482 0 : return NGX_ERROR;
483 : }
484 : }
485 :
486 0 : if (*sc->values == NULL) {
487 0 : n = (sc->variables * (2 * sizeof(ngx_http_lua_script_copy_code_t)
488 : + sizeof(ngx_http_lua_script_capture_code_t))
489 : + sizeof(uintptr_t)
490 0 : + sizeof(uintptr_t) - 1)
491 : & ~(sizeof(uintptr_t) - 1);
492 :
493 0 : *sc->values = ngx_array_create(sc->pool, n, 1);
494 0 : if (*sc->values == NULL) {
495 0 : return NGX_ERROR;
496 : }
497 : }
498 :
499 0 : sc->variables = 0;
500 :
501 0 : return NGX_OK;
502 : }
503 :
504 :
505 : static ngx_int_t
506 0 : ngx_http_lua_script_done(ngx_http_lua_script_compile_t *sc)
507 : {
508 : uintptr_t *code;
509 :
510 0 : if (sc->complete_lengths) {
511 0 : code = ngx_http_lua_script_add_code(*sc->lengths, sizeof(uintptr_t));
512 0 : if (code == NULL) {
513 0 : return NGX_ERROR;
514 : }
515 :
516 0 : *code = (uintptr_t) NULL;
517 : }
518 :
519 0 : if (sc->complete_values) {
520 0 : code = ngx_http_lua_script_add_code(*sc->values, sizeof(uintptr_t));
521 0 : if (code == NULL) {
522 0 : return NGX_ERROR;
523 : }
524 :
525 0 : *code = (uintptr_t) NULL;
526 : }
527 :
528 0 : return NGX_OK;
529 : }
530 :
531 :
532 : static void *
533 0 : ngx_http_lua_script_add_code(ngx_array_t *codes, size_t size)
534 : {
535 0 : return ngx_array_push_n(codes, size);
536 : }
537 :
538 : /* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|