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_echo_handler.h"
14 #include "ngx_http_echo_filter.h"
15 #include "ngx_http_echo_echo.h"
16 #include "ngx_http_echo_request_info.h"
17 #include "ngx_http_echo_var.h"
18 #include "ngx_http_echo_util.h"
19 
20 
21 #include <nginx.h>
22 #include <ngx_config.h>
23 #include <ngx_log.h>
24 
25 
26 /* config init handler */
27 static void *ngx_http_echo_create_loc_conf(ngx_conf_t *cf);
28 static char *ngx_http_echo_merge_loc_conf(ngx_conf_t *cf, void *parent,
29     void *child);
30 static void *ngx_http_echo_create_main_conf(ngx_conf_t *cf);
31 static ngx_int_t ngx_http_echo_post_config(ngx_conf_t *cf);
32 
33 /* config directive handlers */
34 static char *ngx_http_echo_echo(ngx_conf_t *cf, ngx_command_t *cmd,
35     void *conf);
36 static char *ngx_http_echo_echo_request_body(ngx_conf_t *cf,
37     ngx_command_t *cmd, void *conf);
38 static char *ngx_http_echo_echo_sleep(ngx_conf_t *cf, ngx_command_t *cmd,
39     void *conf);
40 static char *ngx_http_echo_echo_flush(ngx_conf_t *cf, ngx_command_t *cmd,
41     void *conf);
42 static char *ngx_http_echo_echo_blocking_sleep(ngx_conf_t *cf,
43     ngx_command_t *cmd, void *conf);
44 static char *ngx_http_echo_echo_reset_timer(ngx_conf_t *cf,
45     ngx_command_t *cmd, void *conf);
46 static char *ngx_http_echo_echo_before_body(ngx_conf_t *cf,
47     ngx_command_t *cmd, void *conf);
48 static char *ngx_http_echo_echo_after_body(ngx_conf_t *cf,
49     ngx_command_t *cmd, void *conf);
50 static char *ngx_http_echo_echo_location_async(ngx_conf_t *cf,
51     ngx_command_t *cmd, void *conf);
52 static char *ngx_http_echo_echo_location(ngx_conf_t *cf,
53     ngx_command_t *cmd, void *conf);
54 static char *ngx_http_echo_echo_subrequest_async(ngx_conf_t *cf,
55     ngx_command_t *cmd, void *conf);
56 static char *ngx_http_echo_echo_subrequest(ngx_conf_t *cf,
57     ngx_command_t *cmd, void *conf);
58 static char *ngx_http_echo_echo_duplicate(ngx_conf_t *cf,
59     ngx_command_t *cmd, void *conf);
60 static char *ngx_http_echo_echo_read_request_body(ngx_conf_t *cf,
61     ngx_command_t *cmd, void *conf);
62 static char *ngx_http_echo_echo_foreach_split(ngx_conf_t *cf,
63     ngx_command_t *cmd, void *conf);
64 static char *ngx_http_echo_echo_end(ngx_conf_t *cf,
65     ngx_command_t *cmd, void *conf);
66 static char *ngx_http_echo_echo_abort_parent(ngx_conf_t *cf,
67     ngx_command_t *cmd, void *conf);
68 static char *ngx_http_echo_echo_exec(ngx_conf_t *cf,
69     ngx_command_t *cmd, void *conf);
70 static char *ngx_http_echo_helper(ngx_http_echo_opcode_t opcode,
71     ngx_http_echo_cmd_category_t cat,
72     ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
73 
74 
75 static ngx_http_module_t ngx_http_echo_module_ctx = {
76     NULL,                           /* preconfiguration */
77     ngx_http_echo_post_config,      /* postconfiguration */
78 
79     ngx_http_echo_create_main_conf, /* create main configuration */
80     NULL,                           /* init main configuration */
81 
82     NULL,                           /* create server configuration */
83     NULL,                           /* merge server configuration */
84 
85     ngx_http_echo_create_loc_conf,  /* create location configuration */
86     ngx_http_echo_merge_loc_conf    /* merge location configuration */
87 };
88 
89 
90 static ngx_command_t  ngx_http_echo_commands[] = {
91 
92     { ngx_string("echo"),
93       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_ANY,
94       ngx_http_echo_echo,
95       NGX_HTTP_LOC_CONF_OFFSET,
96       offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
97       NULL },
98 
99     { ngx_string("echo_request_body"),
100       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_NOARGS,
101       ngx_http_echo_echo_request_body,
102       NGX_HTTP_LOC_CONF_OFFSET,
103       offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
104       NULL },
105 
106     { ngx_string("echo_sleep"),
107       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
108       ngx_http_echo_echo_sleep,
109       NGX_HTTP_LOC_CONF_OFFSET,
110       offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
111       NULL },
112 
113     { ngx_string("echo_flush"),
114       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_NOARGS,
115       ngx_http_echo_echo_flush,
116       NGX_HTTP_LOC_CONF_OFFSET,
117       offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
118       NULL },
119 
120     { ngx_string("echo_blocking_sleep"),
121       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
122       ngx_http_echo_echo_blocking_sleep,
123       NGX_HTTP_LOC_CONF_OFFSET,
124       offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
125       NULL },
126 
127     { ngx_string("echo_reset_timer"),
128       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_NOARGS,
129       ngx_http_echo_echo_reset_timer,
130       NGX_HTTP_LOC_CONF_OFFSET,
131       offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
132       NULL },
133 
134     { ngx_string("echo_before_body"),
135       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_ANY,
136       ngx_http_echo_echo_before_body,
137       NGX_HTTP_LOC_CONF_OFFSET,
138       offsetof(ngx_http_echo_loc_conf_t, before_body_cmds),
139       NULL },
140 
141     { ngx_string("echo_after_body"),
142       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_ANY,
143       ngx_http_echo_echo_after_body,
144       NGX_HTTP_LOC_CONF_OFFSET,
145       offsetof(ngx_http_echo_loc_conf_t, after_body_cmds),
146       NULL },
147 
148     { ngx_string("echo_location_async"),
149       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE12,
150       ngx_http_echo_echo_location_async,
151       NGX_HTTP_LOC_CONF_OFFSET,
152       offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
153       NULL },
154 
155     { ngx_string("echo_location"),
156       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE12,
157       ngx_http_echo_echo_location,
158       NGX_HTTP_LOC_CONF_OFFSET,
159       offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
160       NULL },
161 
162     { ngx_string("echo_subrequest_async"),
163       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_2MORE,
164       ngx_http_echo_echo_subrequest_async,
165       NGX_HTTP_LOC_CONF_OFFSET,
166       offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
167       NULL },
168 
169     { ngx_string("echo_subrequest"),
170       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_2MORE,
171       ngx_http_echo_echo_subrequest,
172       NGX_HTTP_LOC_CONF_OFFSET,
173       offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
174       NULL },
175 
176     { ngx_string("echo_duplicate"),
177       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_2MORE,
178       ngx_http_echo_echo_duplicate,
179       NGX_HTTP_LOC_CONF_OFFSET,
180       offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
181       NULL },
182 
183     { ngx_string("echo_read_request_body"),
184       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_NOARGS,
185       ngx_http_echo_echo_read_request_body,
186       NGX_HTTP_LOC_CONF_OFFSET,
187       offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
188       NULL },
189 
190     { ngx_string("echo_foreach_split"),
191       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_2MORE,
192       ngx_http_echo_echo_foreach_split,
193       NGX_HTTP_LOC_CONF_OFFSET,
194       offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
195       NULL },
196 
197     { ngx_string("echo_end"),
198       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_NOARGS,
199       ngx_http_echo_echo_end,
200       NGX_HTTP_LOC_CONF_OFFSET,
201       offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
202       NULL },
203 
204     { ngx_string("echo_abort_parent"),
205       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_NOARGS,
206       ngx_http_echo_echo_abort_parent,
207       NGX_HTTP_LOC_CONF_OFFSET,
208       offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
209       NULL },
210 
211     { ngx_string("echo_exec"),
212       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE12,
213       ngx_http_echo_echo_exec,
214       NGX_HTTP_LOC_CONF_OFFSET,
215       offsetof(ngx_http_echo_loc_conf_t, handler_cmds),
216       NULL },
217 
218     { ngx_string("echo_status"),
219       NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
220       ngx_conf_set_num_slot,
221       NGX_HTTP_LOC_CONF_OFFSET,
222       offsetof(ngx_http_echo_loc_conf_t, status),
223       NULL },
224 
225       ngx_null_command
226 };
227 
228 
229 ngx_module_t ngx_http_echo_module = {
230     NGX_MODULE_V1,
231     &ngx_http_echo_module_ctx,     /* module context */
232     ngx_http_echo_commands,        /* module directives */
233     NGX_HTTP_MODULE,               /* module type */
234     NULL,                          /* init master */
235     NULL,                          /* init module */
236     NULL,                          /* init process */
237     NULL,                          /* init thread */
238     NULL,                          /* exit thread */
239     NULL,                          /* exit process */
240     NULL,                          /* exit master */
241     NGX_MODULE_V1_PADDING
242 };
243 
244 
245 static void *
ngx_http_echo_create_loc_conf(ngx_conf_t * cf)246 ngx_http_echo_create_loc_conf(ngx_conf_t *cf)
247 {
248     ngx_http_echo_loc_conf_t        *conf;
249 
250     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_echo_loc_conf_t));
251     if (conf == NULL) {
252         return NULL;
253     }
254 
255     /* set by ngx_pcalloc
256      *  conf->handler_cmds = NULL
257      *  conf->before_body_cmds = NULL
258      *  conf->after_body_cmds = NULL
259      *  conf->seen_leading_output = 0
260      *  conf->seen_trailing_output = 0
261      */
262 
263     conf->status = NGX_CONF_UNSET;
264 
265     return conf;
266 }
267 
268 
269 static char *
ngx_http_echo_merge_loc_conf(ngx_conf_t * cf,void * parent,void * child)270 ngx_http_echo_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
271 {
272     ngx_http_echo_loc_conf_t    *prev = parent;
273     ngx_http_echo_loc_conf_t    *conf = child;
274 
275     if (conf->handler_cmds == NULL) {
276         conf->handler_cmds = prev->handler_cmds;
277         conf->seen_leading_output = prev->seen_leading_output;
278     }
279 
280     if (conf->before_body_cmds == NULL) {
281         conf->before_body_cmds = prev->before_body_cmds;
282     }
283 
284     if (conf->after_body_cmds == NULL) {
285         conf->after_body_cmds = prev->after_body_cmds;
286     }
287 
288     ngx_conf_merge_value(conf->status, prev->status, 200);
289 
290     return NGX_CONF_OK;
291 }
292 
293 
294 static char *
ngx_http_echo_helper(ngx_http_echo_opcode_t opcode,ngx_http_echo_cmd_category_t cat,ngx_conf_t * cf,ngx_command_t * cmd,void * conf)295 ngx_http_echo_helper(ngx_http_echo_opcode_t opcode,
296     ngx_http_echo_cmd_category_t cat,
297     ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
298 {
299     ngx_str_t                       *raw_args;
300     ngx_uint_t                       i, n;
301     ngx_array_t                    **args_ptr;
302     ngx_array_t                    **cmds_ptr;
303     ngx_http_echo_cmd_t             *echo_cmd;
304     ngx_http_core_loc_conf_t        *clcf;
305     ngx_http_script_compile_t        sc;
306     ngx_http_echo_main_conf_t       *emcf;
307     ngx_http_echo_arg_template_t    *arg;
308 
309     emcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_echo_module);
310 
311     /* cmds_ptr points to ngx_http_echo_loc_conf_t's
312      * handler_cmds, before_body_cmds, or after_body_cmds
313      * array, depending on the actual offset */
314     cmds_ptr = (ngx_array_t **) (((u_char *) conf) + cmd->offset);
315 
316     if (*cmds_ptr == NULL) {
317         *cmds_ptr = ngx_array_create(cf->pool, 1,
318                                      sizeof(ngx_http_echo_cmd_t));
319 
320         if (*cmds_ptr == NULL) {
321             return NGX_CONF_ERROR;
322         }
323 
324         if (cat == echo_handler_cmd) {
325             dd("registering the content handler");
326             /* register the content handler */
327             clcf = ngx_http_conf_get_module_loc_conf(cf,
328                                                      ngx_http_core_module);
329 
330             dd("registering the content handler (2)");
331             clcf->handler = ngx_http_echo_handler;
332 
333         } else {
334             dd("filter used = 1");
335             emcf->requires_filter = 1;
336         }
337     }
338 
339     echo_cmd = ngx_array_push(*cmds_ptr);
340 
341     if (echo_cmd == NULL) {
342         return NGX_CONF_ERROR;
343     }
344 
345     echo_cmd->opcode = opcode;
346 
347     args_ptr = &echo_cmd->args;
348     *args_ptr = ngx_array_create(cf->pool, 1,
349                                  sizeof(ngx_http_echo_arg_template_t));
350 
351     if (*args_ptr == NULL) {
352         return NGX_CONF_ERROR;
353     }
354 
355     raw_args = cf->args->elts;
356 
357     /* we skip the first arg and start from the second */
358 
359     for (i = 1 ; i < cf->args->nelts; i++) {
360         arg = ngx_array_push(*args_ptr);
361 
362         if (arg == NULL) {
363             return NGX_CONF_ERROR;
364         }
365 
366         arg->raw_value = raw_args[i];
367 
368         dd("found raw arg %s", raw_args[i].data);
369 
370         arg->lengths = NULL;
371         arg->values  = NULL;
372 
373         n = ngx_http_script_variables_count(&arg->raw_value);
374 
375         if (n > 0) {
376             ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
377 
378             sc.cf = cf;
379             sc.source = &arg->raw_value;
380             sc.lengths = &arg->lengths;
381             sc.values = &arg->values;
382             sc.variables = n;
383             sc.complete_lengths = 1;
384             sc.complete_values = 1;
385 
386             if (ngx_http_script_compile(&sc) != NGX_OK) {
387                 return NGX_CONF_ERROR;
388             }
389         }
390     } /* end for */
391 
392     return NGX_CONF_OK;
393 }
394 
395 
396 static char *
ngx_http_echo_echo(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)397 ngx_http_echo_echo(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
398 {
399     ngx_http_echo_loc_conf_t        *elcf = conf;
400 
401     if (!elcf->seen_leading_output) {
402         elcf->seen_leading_output = 1;
403     }
404 
405     dd("in echo_echo...");
406     return ngx_http_echo_helper(echo_opcode_echo, echo_handler_cmd,
407                                 cf, cmd, conf);
408 }
409 
410 
411 static char *
ngx_http_echo_echo_request_body(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)412 ngx_http_echo_echo_request_body(ngx_conf_t *cf, ngx_command_t *cmd,
413     void *conf)
414 {
415     ngx_http_echo_loc_conf_t        *elcf = conf;
416 
417     if (!elcf->seen_leading_output) {
418         elcf->seen_leading_output = 1;
419     }
420 
421     dd("in echo_echo_request_body...");
422     return ngx_http_echo_helper(echo_opcode_echo_request_body, echo_handler_cmd,
423                                 cf, cmd, conf);
424 }
425 
426 
427 static char *
ngx_http_echo_echo_sleep(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)428 ngx_http_echo_echo_sleep(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
429 {
430     dd("in echo_sleep...");
431     return ngx_http_echo_helper(echo_opcode_echo_sleep, echo_handler_cmd,
432                                 cf, cmd, conf);
433 }
434 
435 
436 static char *
ngx_http_echo_echo_flush(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)437 ngx_http_echo_echo_flush(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
438 {
439     ngx_http_echo_loc_conf_t        *elcf = conf;
440 
441     if (!elcf->seen_leading_output) {
442         elcf->seen_leading_output = 1;
443     }
444 
445     dd("in echo_flush...");
446     return ngx_http_echo_helper(echo_opcode_echo_flush, echo_handler_cmd,
447                                 cf, cmd, conf);
448 }
449 
450 
451 static char *
ngx_http_echo_echo_blocking_sleep(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)452 ngx_http_echo_echo_blocking_sleep(ngx_conf_t *cf, ngx_command_t *cmd,
453     void *conf)
454 {
455     dd("in echo_blocking_sleep...");
456     return ngx_http_echo_helper(echo_opcode_echo_blocking_sleep,
457                                 echo_handler_cmd, cf, cmd, conf);
458 }
459 
460 
461 static char *
ngx_http_echo_echo_reset_timer(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)462 ngx_http_echo_echo_reset_timer(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
463 {
464     return ngx_http_echo_helper(echo_opcode_echo_reset_timer, echo_handler_cmd,
465                                 cf, cmd, conf);
466 }
467 
468 
469 static char *
ngx_http_echo_echo_before_body(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)470 ngx_http_echo_echo_before_body(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
471 {
472     dd("processing echo_before_body directive...");
473     return ngx_http_echo_helper(echo_opcode_echo_before_body, echo_filter_cmd,
474                                 cf, cmd, conf);
475 }
476 
477 
478 static char *
ngx_http_echo_echo_after_body(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)479 ngx_http_echo_echo_after_body(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
480 {
481     return ngx_http_echo_helper(echo_opcode_echo_after_body, echo_filter_cmd,
482                                 cf, cmd, conf);
483 }
484 
485 
486 static char *
ngx_http_echo_echo_location_async(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)487 ngx_http_echo_echo_location_async(ngx_conf_t *cf, ngx_command_t *cmd,
488     void *conf)
489 {
490     ngx_http_echo_loc_conf_t        *elcf = conf;
491     char                            *ret;
492 
493     if (!elcf->seen_leading_output) {
494         elcf->seen_leading_output = 1;
495 
496         ret = ngx_http_echo_helper(echo_opcode_echo_sync, echo_handler_cmd,
497                                    cf, cmd, conf);
498 
499         if (ret != NGX_CONF_OK) {
500             return ret;
501         }
502     }
503 
504     return ngx_http_echo_helper(echo_opcode_echo_location_async,
505                                 echo_handler_cmd, cf, cmd, conf);
506 }
507 
508 
509 static char *
ngx_http_echo_echo_location(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)510 ngx_http_echo_echo_location(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
511 {
512     ngx_http_echo_loc_conf_t        *elcf = conf;
513     char                            *ret;
514 
515     if (!elcf->seen_leading_output) {
516         elcf->seen_leading_output = 1;
517 
518         ret = ngx_http_echo_helper(echo_opcode_echo_sync, echo_handler_cmd,
519                                    cf, cmd, conf);
520 
521         if (ret != NGX_CONF_OK) {
522             return ret;
523         }
524     }
525 
526     return ngx_http_echo_helper(echo_opcode_echo_location, echo_handler_cmd,
527                                 cf, cmd, conf);
528 }
529 
530 
531 static char *
ngx_http_echo_echo_subrequest_async(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)532 ngx_http_echo_echo_subrequest_async(ngx_conf_t *cf, ngx_command_t *cmd,
533     void *conf)
534 {
535     char                            *ret;
536     ngx_http_echo_loc_conf_t        *elcf = conf;
537 
538     if (!elcf->seen_leading_output) {
539         elcf->seen_leading_output = 1;
540 
541         ret = ngx_http_echo_helper(echo_opcode_echo_sync, echo_handler_cmd,
542                                    cf, cmd, conf);
543 
544         if (ret != NGX_CONF_OK) {
545             return ret;
546         }
547     }
548 
549     return ngx_http_echo_helper(echo_opcode_echo_subrequest_async,
550                                 echo_handler_cmd, cf, cmd, conf);
551 }
552 
553 
554 static char *
ngx_http_echo_echo_subrequest(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)555 ngx_http_echo_echo_subrequest(ngx_conf_t *cf, ngx_command_t *cmd,
556     void *conf)
557 {
558     ngx_http_echo_loc_conf_t        *elcf = conf;
559     char                            *ret;
560 
561     if (!elcf->seen_leading_output) {
562         elcf->seen_leading_output = 1;
563 
564         ret = ngx_http_echo_helper(echo_opcode_echo_sync, echo_handler_cmd,
565                                    cf, cmd, conf);
566 
567         if (ret != NGX_CONF_OK) {
568             return ret;
569         }
570     }
571 
572     return ngx_http_echo_helper(echo_opcode_echo_subrequest, echo_handler_cmd,
573                                 cf, cmd, conf);
574 }
575 
576 
577 static char *
ngx_http_echo_echo_duplicate(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)578 ngx_http_echo_echo_duplicate(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
579 {
580     ngx_http_echo_loc_conf_t        *elcf = conf;
581 
582     if (!elcf->seen_leading_output) {
583         elcf->seen_leading_output = 1;
584     }
585 
586     return ngx_http_echo_helper(echo_opcode_echo_duplicate, echo_handler_cmd,
587                                 cf, cmd, conf);
588 }
589 
590 
591 static char *
ngx_http_echo_echo_read_request_body(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)592 ngx_http_echo_echo_read_request_body(ngx_conf_t *cf, ngx_command_t *cmd,
593     void *conf)
594 {
595     return ngx_http_echo_helper(echo_opcode_echo_read_request_body,
596                                 echo_handler_cmd, cf, cmd, conf);
597 }
598 
599 
600 static char *
ngx_http_echo_echo_foreach_split(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)601 ngx_http_echo_echo_foreach_split(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
602 {
603     return ngx_http_echo_helper(echo_opcode_echo_foreach_split,
604                                 echo_handler_cmd, cf, cmd, conf);
605 }
606 
607 
608 static char *
ngx_http_echo_echo_end(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)609 ngx_http_echo_echo_end(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
610 {
611     return ngx_http_echo_helper(echo_opcode_echo_end, echo_handler_cmd, cf,
612                                 cmd, conf);
613 }
614 
615 
616 static char *
ngx_http_echo_echo_abort_parent(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)617 ngx_http_echo_echo_abort_parent(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
618 {
619     return ngx_http_echo_helper(echo_opcode_echo_abort_parent, echo_handler_cmd,
620                                 cf, cmd, conf);
621 }
622 
623 
624 static char *
ngx_http_echo_echo_exec(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)625 ngx_http_echo_echo_exec(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
626 {
627     return ngx_http_echo_helper(echo_opcode_echo_exec, echo_handler_cmd,
628                                 cf, cmd, conf);
629 }
630 
631 
632 static void *
ngx_http_echo_create_main_conf(ngx_conf_t * cf)633 ngx_http_echo_create_main_conf(ngx_conf_t *cf)
634 {
635 #if nginx_version >= 1011011
636     ngx_pool_cleanup_t           *cln;
637 #endif
638     ngx_http_echo_main_conf_t    *emcf;
639 
640     emcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_echo_main_conf_t));
641     if (emcf == NULL) {
642         return NULL;
643     }
644 
645     /* set by ngx_pcalloc:
646      *      hmcf->requires_filter = 0;
647      */
648 
649 #if nginx_version >= 1011011
650     cln = ngx_pool_cleanup_add(cf->pool, 0);
651     if (cln == NULL) {
652         return NULL;
653     }
654 
655     cln->data = emcf;
656     cln->handler = ngx_http_echo_request_headers_cleanup;
657 #endif
658 
659     return emcf;
660 }
661 
662 
663 static ngx_int_t
ngx_http_echo_post_config(ngx_conf_t * cf)664 ngx_http_echo_post_config(ngx_conf_t *cf)
665 {
666     ngx_int_t         rc;
667 
668     rc = ngx_http_echo_filter_init(cf);
669     if (rc != NGX_OK) {
670         return rc;
671     }
672 
673     rc = ngx_http_echo_echo_init(cf);
674     if (rc != NGX_OK) {
675         return rc;
676     }
677 
678     ngx_http_echo_content_length_hash =
679                                   ngx_http_echo_hash_literal("content-length");
680 
681     return ngx_http_echo_add_variables(cf);
682 }
683