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