• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

src/H01-Oct-2020-4,6523,227

t/H01-Oct-2020-5,9534,831

util/H01-Oct-2020-186132

.gitattributesH A D01-Oct-202027 21

.gitignoreH A D01-Oct-2020618 6665

.travis.ymlH A D01-Oct-20202.2 KiB5042

LICENSEH A D01-Oct-20201.3 KiB2621

README.markdownH A D01-Oct-202053.2 KiB1,8521,252

configH A D01-Oct-20203.1 KiB6457

valgrind.suppressH A D01-Oct-2020986 5453

README.markdown

1Name
2====
3
4**ngx_echo** - Brings "echo", "sleep", "time", "exec" and more shell-style goodies to Nginx config file.
5
6*This module is not distributed with the Nginx source.* See [the installation instructions](#installation).
7
8Table of Contents
9=================
10
11* [Name](#name)
12* [Status](#status)
13* [Version](#version)
14* [Synopsis](#synopsis)
15* [Description](#description)
16* [Content Handler Directives](#content-handler-directives)
17    * [echo](#echo)
18    * [echo_duplicate](#echo_duplicate)
19    * [echo_flush](#echo_flush)
20    * [echo_sleep](#echo_sleep)
21    * [echo_blocking_sleep](#echo_blocking_sleep)
22    * [echo_reset_timer](#echo_reset_timer)
23    * [echo_read_request_body](#echo_read_request_body)
24    * [echo_location_async](#echo_location_async)
25    * [echo_location](#echo_location)
26    * [echo_subrequest_async](#echo_subrequest_async)
27    * [echo_subrequest](#echo_subrequest)
28    * [echo_foreach_split](#echo_foreach_split)
29    * [echo_end](#echo_end)
30    * [echo_request_body](#echo_request_body)
31    * [echo_exec](#echo_exec)
32    * [echo_status](#echo_status)
33* [Filter Directives](#filter-directives)
34    * [echo_before_body](#echo_before_body)
35    * [echo_after_body](#echo_after_body)
36* [Variables](#variables)
37    * [$echo_it](#echo_it)
38    * [$echo_timer_elapsed](#echo_timer_elapsed)
39    * [$echo_request_body](#echo_request_body)
40    * [$echo_request_method](#echo_request_method)
41    * [$echo_client_request_method](#echo_client_request_method)
42    * [$echo_client_request_headers](#echo_client_request_headers)
43    * [$echo_cacheable_request_uri](#echo_cacheable_request_uri)
44    * [$echo_request_uri](#echo_request_uri)
45    * [$echo_incr](#echo_incr)
46    * [$echo_response_status](#echo_response_status)
47* [Installation](#installation)
48* [Compatibility](#compatibility)
49* [Modules that use this module for testing](#modules-that-use-this-module-for-testing)
50* [Community](#community)
51    * [English Mailing List](#english-mailing-list)
52    * [Chinese Mailing List](#chinese-mailing-list)
53* [Report Bugs](#report-bugs)
54* [Source Repository](#source-repository)
55* [Changes](#changes)
56* [Test Suite](#test-suite)
57* [TODO](#todo)
58* [Getting involved](#getting-involved)
59* [Author](#author)
60* [Copyright & License](#copyright--license)
61* [See Also](#see-also)
62
63Status
64======
65
66This module is production ready.
67
68Version
69=======
70
71This document describes ngx_echo [v0.62](https://github.com/openresty/echo-nginx-module/tags) released on 2 July, 2020.
72
73Synopsis
74========
75
76```nginx
77
78   location /hello {
79     echo "hello, world!";
80   }
81```
82
83```nginx
84
85   location /hello {
86     echo -n "hello, ";
87     echo "world!";
88   }
89```
90
91```nginx
92
93   location /timed_hello {
94     echo_reset_timer;
95     echo hello world;
96     echo "'hello world' takes about $echo_timer_elapsed sec.";
97     echo hiya igor;
98     echo "'hiya igor' takes about $echo_timer_elapsed sec.";
99   }
100```
101
102```nginx
103
104   location /echo_with_sleep {
105     echo hello;
106     echo_flush;  # ensure the client can see previous output immediately
107     echo_sleep   2.5;  # in sec
108     echo world;
109   }
110```
111
112```nginx
113
114   # in the following example, accessing /echo yields
115   #   hello
116   #   world
117   #   blah
118   #   hiya
119   #   igor
120   location /echo {
121       echo_before_body hello;
122       echo_before_body world;
123       proxy_pass $scheme://127.0.0.1:$server_port$request_uri/more;
124       echo_after_body hiya;
125       echo_after_body igor;
126   }
127   location /echo/more {
128       echo blah;
129   }
130```
131
132```nginx
133
134   # the output of /main might be
135   #   hello
136   #   world
137   #   took 0.000 sec for total.
138   # and the whole request would take about 2 sec to complete.
139   location /main {
140       echo_reset_timer;
141
142       # subrequests in parallel
143       echo_location_async /sub1;
144       echo_location_async /sub2;
145
146       echo "took $echo_timer_elapsed sec for total.";
147   }
148   location /sub1 {
149       echo_sleep 2;
150       echo hello;
151   }
152   location /sub2 {
153       echo_sleep 1;
154       echo world;
155   }
156```
157
158```nginx
159
160   # the output of /main might be
161   #   hello
162   #   world
163   #   took 3.003 sec for total.
164   # and the whole request would take about 3 sec to complete.
165   location /main {
166       echo_reset_timer;
167
168       # subrequests in series (chained by CPS)
169       echo_location /sub1;
170       echo_location /sub2;
171
172       echo "took $echo_timer_elapsed sec for total.";
173   }
174   location /sub1 {
175       echo_sleep 2;
176       echo hello;
177   }
178   location /sub2 {
179       echo_sleep 1;
180       echo world;
181   }
182```
183
184```nginx
185
186   # Accessing /dup gives
187   #   ------ END ------
188   location /dup {
189     echo_duplicate 3 "--";
190     echo_duplicate 1 " END ";
191     echo_duplicate 3 "--";
192     echo;
193   }
194```
195
196```nginx
197
198   # /bighello will generate 1000,000,000 hello's.
199   location /bighello {
200     echo_duplicate 1000_000_000 'hello';
201   }
202```
203
204```nginx
205
206   # echo back the client request
207   location /echoback {
208     echo_duplicate 1 $echo_client_request_headers;
209     echo "\r";
210
211     echo_read_request_body;
212
213     echo_request_body;
214   }
215```
216
217```nginx
218
219   # GET /multi will yields
220   #   querystring: foo=Foo
221   #   method: POST
222   #   body: hi
223   #   content length: 2
224   #   ///
225   #   querystring: bar=Bar
226   #   method: PUT
227   #   body: hello
228   #   content length: 5
229   #   ///
230   location /multi {
231       echo_subrequest_async POST '/sub' -q 'foo=Foo' -b 'hi';
232       echo_subrequest_async PUT '/sub' -q 'bar=Bar' -b 'hello';
233   }
234   location /sub {
235       echo "querystring: $query_string";
236       echo "method: $echo_request_method";
237       echo "body: $echo_request_body";
238       echo "content length: $http_content_length";
239       echo '///';
240   }
241```
242
243```nginx
244
245   # GET /merge?/foo.js&/bar/blah.js&/yui/baz.js will merge the .js resources together
246   location /merge {
247       default_type 'text/javascript';
248       echo_foreach_split '&' $query_string;
249           echo "/* JS File $echo_it */";
250           echo_location_async $echo_it;
251           echo;
252       echo_end;
253   }
254```
255
256```nginx
257
258   # accessing /if?val=abc yields the "hit" output
259   # while /if?val=bcd yields "miss":
260   location ^~ /if {
261       set $res miss;
262       if ($arg_val ~* '^a') {
263           set $res hit;
264           echo $res;
265       }
266       echo $res;
267   }
268```
269
270[Back to TOC](#table-of-contents)
271
272Description
273===========
274
275This module wraps lots of Nginx internal APIs for streaming input and output, parallel/sequential subrequests, timers and sleeping, as well as various meta data accessing.
276
277Basically it provides various utilities that help testing and debugging of other modules by trivially emulating different kinds of faked subrequest locations.
278
279People will also find it useful in real-world applications that need to
280
2811. serve static contents directly from memory (loading from the Nginx config file).
2821. wrap the upstream response with custom header and footer (kinda like the [addition module](http://nginx.org/en/docs/http/ngx_http_addition_module.html) but with contents read directly from the config file and Nginx variables).
2831. merge contents of various "Nginx locations" (i.e., subrequests) together in a single main request (using [echo_location](#echo_location) and its friends).
284
285This is a special dual-role module that can *lazily* serve as a content handler or register itself as an output filter only upon demand. By default, this module does not do anything at all.
286
287Technically, this module has also demonstrated the following techniques that might be helpful for module writers:
288
2891. Issue parallel subrequests directly from content handler.
2901. Issue chained subrequests directly from content handler, by passing continuation along the subrequest chain.
2911. Issue subrequests with all HTTP 1.1 methods and even an optional faked HTTP request body.
2921. Interact with the Nginx event model directly from content handler using custom events and timers, and resume the content handler back if necessary.
2931. Dual-role module that can (lazily) serve as a content handler or an output filter or both.
2941. Nginx config file variable creation and interpolation.
2951. Streaming output control using output_chain, flush and its friends.
2961. Read client request body from the content handler, and returns back (asynchronously) to the content handler after completion.
2971. Use Perl-based declarative [test suite](#test-suite) to drive the development of Nginx C modules.
298
299[Back to TOC](#table-of-contents)
300
301Content Handler Directives
302==========================
303
304Use of the following directives register this module to the current Nginx location as a content handler. If you want to use another module, like the [standard proxy module](http://nginx.org/en/docs/http/ngx_http_proxy_module.html), as the content handler, use the [filter directives](#filter-directives) provided by this module.
305
306All the content handler directives can be mixed together in a single Nginx location and they're supposed to run sequentially just as in the Bash scripting language.
307
308Every content handler directive supports variable interpolation in its arguments (if any).
309
310The MIME type set by the [standard default_type directive](http://nginx.org/en/docs/http/ngx_http_core_module.html#default_type) is respected by this module, as in:
311
312```nginx
313
314   location /hello {
315     default_type text/plain;
316     echo hello;
317   }
318```
319
320Then on the client side:
321
322```bash
323
324   $ curl -I 'http://localhost/echo'
325   HTTP/1.1 200 OK
326   Server: nginx/0.8.20
327   Date: Sat, 17 Oct 2009 03:40:19 GMT
328   Content-Type: text/plain
329   Connection: keep-alive
330```
331
332Since the [v0.22](#v022) release, all of the directives are allowed in the [rewrite module](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html)'s [if](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#if) directive block, for instance:
333
334```nginx
335
336 location ^~ /if {
337     set $res miss;
338     if ($arg_val ~* '^a') {
339         set $res hit;
340         echo $res;
341     }
342     echo $res;
343 }
344```
345
346[Back to TOC](#table-of-contents)
347
348echo
349----
350**syntax:** *echo \[options\] <string>...*
351
352**default:** *no*
353
354**context:** *location, location if*
355
356**phase:** *content*
357
358Sends arguments joined by spaces, along with a trailing newline, out to the client.
359
360Note that the data might be buffered by Nginx's underlying buffer. To force the output data flushed immediately, use the [echo_flush](#echo_flush) command just after `echo`, as in
361
362```nginx
363
364    echo hello world;
365    echo_flush;
366```
367
368When no argument is specified, *echo* emits the trailing newline alone, just like the *echo* command in shell.
369
370Variables may appear in the arguments. An example is
371
372```nginx
373
374    echo The current request uri is $request_uri;
375```
376
377where [$request_uri](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_uri) is a variable exposed by the [ngx_http_core_module](http://nginx.org/en/docs/http/ngx_http_core_module.html).
378
379This command can be used multiple times in a single location configuration, as in
380
381```nginx
382
383 location /echo {
384     echo hello;
385     echo world;
386 }
387```
388
389The output on the client side looks like this
390
391```bash
392
393 $ curl 'http://localhost/echo'
394 hello
395 world
396```
397
398Special characters like newlines (`\n`) and tabs (`\t`) can be escaped using C-style escaping sequences. But a notable exception is the dollar sign (`$`). As of Nginx 0.8.20, there's still no clean way to escape this character. (A work-around might be to use a `$echo_dollor` variable that is always evaluated to the constant `$` character. This feature will possibly be introduced in a future version of this module.)
399
400As of the echo [v0.28](#v028) release, one can suppress the trailing newline character in the output by using the `-n` option, as in
401
402```nginx
403
404 location /echo {
405     echo -n "hello, ";
406     echo "world";
407 }
408```
409
410Accessing `/echo` gives
411
412```bash
413
414 $ curl 'http://localhost/echo'
415 hello, world
416```
417
418Leading `-n` in variable values won't take effect and will be emitted literally, as in
419
420```nginx
421
422 location /echo {
423     set $opt -n;
424     echo $opt "hello,";
425     echo "world";
426 }
427```
428
429This gives the following output
430
431```bash
432
433 $ curl 'http://localhost/echo'
434 -n hello,
435 world
436```
437
438One can output leading `-n` literals and other options using the special `--` option like this
439
440```nginx
441
442 location /echo {
443     echo -- -n is an option;
444 }
445```
446
447which yields
448
449```bash
450
451 $ curl 'http://localhost/echo'
452 -n is an option
453```
454
455Use this form when you want to output anything leading with a dash (`-`).
456
457[Back to TOC](#table-of-contents)
458
459echo_duplicate
460--------------
461**syntax:** *echo_duplicate <count> <string>*
462
463**default:** *no*
464
465**context:** *location, location if*
466
467**phase:** *content*
468
469Outputs duplication of a string indicated by the second argument, using the count specified in the first argument.
470
471For instance,
472
473```nginx
474
475   location /dup {
476       echo_duplicate 3 "abc";
477   }
478```
479
480will lead to the output of `"abcabcabc"`.
481
482Underscores are allowed in the count number, just like in Perl. For example, to emit 1000,000,000 instances of `"hello, world"`:
483
484```nginx
485
486   location /many_hellos {
487       echo_duplicate 1000_000_000 "hello, world";
488   }
489```
490
491The `count` argument could be zero, but not negative. The second `string` argument could be an empty string ("") likewise.
492
493Unlike the [echo](#echo) directive, no trailing newline is appended to the result. So it's possible to "abuse" this directive as a no-trailing-newline version of [echo](#echo) by using "count" 1, as in
494
495```nginx
496
497   location /echo_art {
498       echo_duplicate 2 '---';
499       echo_duplicate 1 ' END ';  # we don't want a trailing newline here
500       echo_duplicate 2 '---';
501       echo;  # we want a trailing newline here...
502   }
503```
504
505You get
506
507```bash
508   ------ END ------
509```
510
511But use of the `-n` option in [echo](#echo) is more appropriate for this purpose.
512
513This directive was first introduced in [version 0.11](#v011).
514
515[Back to TOC](#table-of-contents)
516
517echo_flush
518----------
519**syntax:** *echo_flush*
520
521**default:** *no*
522
523**context:** *location, location if*
524
525**phase:** *content*
526
527Forces the data potentially buffered by underlying Nginx output filters to send immediately to the client side via socket.
528
529Note that techically the command just emits a ngx_buf_t object with `flush` slot set to 1, so certain weird third-party output filter module could still block it before it reaches Nginx's (last) write filter.
530
531This directive does not take any argument.
532
533Consider the following example:
534
535```nginx
536
537   location /flush {
538      echo hello;
539
540      echo_flush;
541
542      echo_sleep 1;
543      echo world;
544   }
545```
546
547Then on the client side, using curl to access `/flush`, you'll see the "hello" line immediately, but only after 1 second, the last "world" line. Without calling `echo_flush` in the example above, you'll most likely see no output until 1 second is elapsed due to the internal buffering of Nginx.
548
549This directive will fail to flush the output buffer in case of subrequests get involved. Consider the following example:
550
551```nginx
552
553   location /main {
554       echo_location_async /sub;
555       echo hello;
556       echo_flush;
557   }
558   location /sub {
559       echo_sleep 1;
560   }
561```
562
563Then the client won't see "hello" appear even if `echo_flush` has been executed before the subrequest to `/sub` has actually started executing. The outputs of `/main` that are sent *after* [echo_location_async](#echo_location_async) will be postponed and buffered firmly.
564
565This does *not* apply to outputs sent before the subrequest initiated. For a modified version of the example given above:
566
567```nginx
568
569   location /main {
570       echo hello;
571       echo_flush;
572       echo_location_async /sub;
573   }
574   location /sub {
575       echo_sleep 1;
576   }
577```
578
579The client will immediately see "hello" before `/sub` enters sleeping.
580
581See also [echo](#echo), [echo_sleep](#echo_sleep), and [echo_location_async](#echo_location_async).
582
583[Back to TOC](#table-of-contents)
584
585echo_sleep
586----------
587**syntax:** *echo_sleep <seconds>*
588
589**default:** *no*
590
591**context:** *location, location if*
592
593**phase:** *content*
594
595Sleeps for the time period specified by the argument, which is in seconds.
596
597This operation is non-blocking on server side, so unlike the [echo_blocking_sleep](#echo_blocking_sleep) directive, it won't block the whole Nginx worker process.
598
599The period might takes three digits after the decimal point and must be greater than 0.001.
600
601An example is
602
603```nginx
604
605    location /echo_after_sleep {
606        echo_sleep 1.234;
607        echo resumed!;
608    }
609```
610
611Behind the scene, it sets up a per-request "sleep" ngx_event_t object, and adds a timer using that custom event to the Nginx event model and just waits for a timeout on that event. Because the "sleep" event is per-request, this directive can work in parallel subrequests.
612
613[Back to TOC](#table-of-contents)
614
615echo_blocking_sleep
616-------------------
617**syntax:** *echo_blocking_sleep <seconds>*
618
619**default:** *no*
620
621**context:** *location, location if*
622
623**phase:** *content*
624
625This is a blocking version of the [echo_sleep](#echo_sleep) directive.
626
627See the documentation of [echo_sleep](#echo_sleep) for more detail.
628
629Behind the curtain, it calls the ngx_msleep macro provided by the Nginx core which maps to usleep on POSIX-compliant systems.
630
631Note that this directive will block the current Nginx worker process completely while being executed, so never use it in production environment.
632
633[Back to TOC](#table-of-contents)
634
635echo_reset_timer
636----------------
637**syntax:** *echo_reset_timer*
638
639**default:** *no*
640
641**context:** *location, location if*
642
643**phase:** *content*
644
645Reset the timer begin time to *now*, i.e., the time when this command is executed during request.
646
647The timer begin time is default to the starting time of the current request and can be overridden by this directive, potentially multiple times in a single location. For example:
648
649```nginx
650
651   location /timed_sleep {
652       echo_sleep 0.03;
653       echo "$echo_timer_elapsed sec elapsed.";
654
655       echo_reset_timer;
656
657       echo_sleep 0.02;
658       echo "$echo_timer_elapsed sec elapsed.";
659   }
660```
661
662The output on the client side might be
663
664```bash
665
666 $ curl 'http://localhost/timed_sleep'
667 0.032 sec elapsed.
668 0.020 sec elapsed.
669```
670
671The actual figures you get on your side may vary a bit due to your system's current activities.
672
673Invocation of this directive will force the underlying Nginx timer to get updated to the current system time (regardless the timer resolution specified elsewhere in the config file). Furthermore, references of the [$echo_timer_elapsed](#echo_timer_elapsed) variable will also trigger timer update forcibly.
674
675See also [echo_sleep](#echo_sleep) and [$echo_timer_elapsed](#echo_timer_elapsed).
676
677[Back to TOC](#table-of-contents)
678
679echo_read_request_body
680----------------------
681**syntax:** *echo_read_request_body*
682
683**default:** *no*
684
685**context:** *location, location if*
686
687**phase:** *content*
688
689Explicitly reads request body so that the [$request_body](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_body) variable will always have non-empty values (unless the body is so big that it has been saved by Nginx to a local temporary file).
690
691Note that this might not be the original client request body because the current request might be a subrequest with a "artificial" body specified by its parent.
692
693This directive does not generate any output itself, just like [echo_sleep](#echo_sleep).
694
695Here's an example for echo'ing back the original HTTP client request (both headers and body are included):
696
697```nginx
698
699   location /echoback {
700     echo_duplicate 1 $echo_client_request_headers;
701     echo "\r";
702     echo_read_request_body;
703     echo $request_body;
704   }
705```
706
707The content of `/echoback` looks like this on my side (I was using Perl's LWP utility to access this location on the server):
708
709```bash
710
711   $ (echo hello; echo world) | lwp-request -m POST 'http://localhost/echoback'
712   POST /echoback HTTP/1.1
713   TE: deflate,gzip;q=0.3
714   Connection: TE, close
715   Host: localhost
716   User-Agent: lwp-request/5.818 libwww-perl/5.820
717   Content-Length: 12
718   Content-Type: application/x-www-form-urlencoded
719
720   hello
721   world
722```
723
724Because `/echoback` is the main request, [$request_body](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_body) holds the original client request body.
725
726Before Nginx 0.7.56, it makes no sense to use this directive because [$request_body](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_body) was first introduced in Nginx 0.7.58.
727
728This directive itself was first introduced in the echo module's [v0.14 release](#v014).
729
730[Back to TOC](#table-of-contents)
731
732echo_location_async
733-------------------
734**syntax:** *echo_location_async <location> [<url_args>]*
735
736**default:** *no*
737
738**context:** *location, location if*
739
740**phase:** *content*
741
742Issue GET subrequest to the location specified (first argument) with optional url arguments specified in the second argument.
743
744As of Nginx 0.8.20, the `location` argument does *not* support named location, due to a limitation in the `ngx_http_subrequest` function. The same is true for its brother, the [echo_location](#echo_location) directive.
745
746A very simple example is
747
748```nginx
749
750 location /main {
751     echo_location_async /sub;
752     echo world;
753 }
754 location /sub {
755     echo hello;
756 }
757```
758
759Accessing `/main` gets
760
761```bash
762
763   hello
764   world
765```
766
767Calling multiple locations in parallel is also possible:
768
769```nginx
770
771 location /main {
772     echo_reset_timer;
773     echo_location_async /sub1;
774     echo_location_async /sub2;
775     echo "took $echo_timer_elapsed sec for total.";
776 }
777 location /sub1 {
778     echo_sleep 2; # sleeps 2 sec
779     echo hello;
780 }
781 location /sub2 {
782     echo_sleep 1; # sleeps 1 sec
783     echo world;
784 }
785```
786
787Accessing `/main` yields
788
789```bash
790
791   $ time curl 'http://localhost/main'
792   hello
793   world
794   took 0.000 sec for total.
795
796   real  0m2.006s
797   user  0m0.000s
798   sys   0m0.004s
799```
800
801You can see that the main handler `/main` does *not* wait the subrequests `/sub1` and `/sub2` to complete and quickly goes on, hence the "0.000 sec" timing result. The whole request, however takes approximately 2 sec in total to complete because `/sub1` and `/sub2` run in parallel (or "concurrently" to be more accurate).
802
803If you use [echo_blocking_sleep](#echo_blocking_sleep) in the previous example instead, then you'll get the same output, but with 3 sec total response time, because "blocking sleep" blocks the whole Nginx worker process.
804
805Locations can also take an optional querystring argument, for instance
806
807```nginx
808
809 location /main {
810     echo_location_async /sub 'foo=Foo&bar=Bar';
811 }
812 location /sub {
813     echo $arg_foo $arg_bar;
814 }
815```
816
817Accessing `/main` yields
818
819```bash
820
821   $ curl 'http://localhost/main'
822   Foo Bar
823```
824
825Querystrings is *not* allowed to be concatenated onto the `location` argument with "?" directly, for example, `/sub?foo=Foo&bar=Bar` is an invalid location, and shouldn't be fed as the first argument to this directive.
826
827Technically speaking, this directive is an example that Nginx content handler issues one or more subrequests directly. AFAIK, the [fancyindex module](https://connectical.com/projects/ngx-fancyindex/wiki) also does such kind of things ;)
828
829Nginx named locations like `@foo` is *not* supported here.
830
831This directive is logically equivalent to the GET version of [echo_subrequest_async](#echo_subrequest_async). For example,
832
833```nginx
834
835   echo_location_async /foo 'bar=Bar';
836```
837
838is logically equivalent to
839
840```nginx
841
842   echo_subrequest_async GET /foo -q 'bar=Bar';
843```
844
845But calling this directive is slightly faster than calling [echo_subrequest_async](#echo_subrequest_async) using `GET` because we don't have to parse the HTTP method names like `GET` and options like `-q`.
846
847This directive is first introduced in [version 0.09](#v009) of this module and requires at least Nginx 0.7.46.
848
849[Back to TOC](#table-of-contents)
850
851echo_location
852-------------
853**syntax:** *echo_location <location> [<url_args>]*
854
855**default:** *no*
856
857**context:** *location, location if*
858
859**phase:** *content*
860
861Just like the [echo_location_async](#echo_location_async) directive, but `echo_location` issues subrequests *in series* rather than in parallel. That is, the content handler directives following this directive won't be executed until the subrequest issued by this directive completes.
862
863The final response body is almost always equivalent to the case when [echo_location_async](#echo_location_async) is used instead, only if timing variables is used in the outputs.
864
865Consider the following example:
866
867```nginx
868
869 location /main {
870     echo_reset_timer;
871     echo_location /sub1;
872     echo_location /sub2;
873     echo "took $echo_timer_elapsed sec for total.";
874 }
875 location /sub1 {
876     echo_sleep 2;
877     echo hello;
878 }
879 location /sub2 {
880     echo_sleep 1;
881     echo world;
882 }
883```
884
885The location `/main` above will take for total 3 sec to complete (compared to 2 sec if [echo_location_async](#echo_location_async) is used instead here). Here's the result in action on my machine:
886
887```bash
888
889   $ curl 'http://localhost/main'
890   hello
891   world
892   took 3.003 sec for total.
893
894   real  0m3.027s
895   user  0m0.020s
896   sys   0m0.004s
897```
898
899This directive is logically equivalent to the GET version of [echo_subrequest](#echo_subrequest). For example,
900
901```nginx
902
903   echo_location /foo 'bar=Bar';
904```
905
906is logically equivalent to
907
908```nginx
909
910   echo_subrequest GET /foo -q 'bar=Bar';
911```
912
913But calling this directive is slightly faster than calling [echo_subrequest](#echo_subrequest) using `GET` because we don't have to parse the HTTP method names like `GET` and options like `-q`.
914
915Behind the scene, it creates an `ngx_http_post_subrequest_t` object as a *continuation* and passes it into the `ngx_http_subrequest` function call. Nginx will later reopen this "continuation" in the subrequest's `ngx_http_finalize_request` function call. We resumes the execution of the parent-request's content handler and starts to run the next directive (command) if any.
916
917Nginx named locations like `@foo` is *not* supported here.
918
919This directive was first introduced in the [release v0.12](#v012).
920
921See also [echo_location_async](#echo_location_async) for more details about the meaning of the arguments.
922
923[Back to TOC](#table-of-contents)
924
925echo_subrequest_async
926---------------------
927**syntax:** *echo_subrequest_async <HTTP_method> <location> [-q <url_args>] [-b <request_body>] [-f <request_body_path>]*
928
929**default:** *no*
930
931**context:** *location, location if*
932
933**phase:** *content*
934
935Initiate an asynchronous subrequest using HTTP method, an optional url arguments (or querystring) and an optional request body which can be defined as a string or as a path to a file which contains the body.
936
937This directive is very much like a generalized version of the [echo_location_async](#echo_location_async) directive.
938
939Here's a small example demonstrating its usage:
940
941```nginx
942
943 location /multi {
944     # body defined as string
945     echo_subrequest_async POST '/sub' -q 'foo=Foo' -b 'hi';
946     # body defined as path to a file, relative to nginx prefix path if not absolute
947     echo_subrequest_async PUT '/sub' -q 'bar=Bar' -f '/tmp/hello.txt';
948 }
949 location /sub {
950     echo "querystring: $query_string";
951     echo "method: $echo_request_method";
952     echo "body: $echo_request_body";
953     echo "content length: $http_content_length";
954     echo '///';
955 }
956```
957
958Then on the client side:
959
960```bash
961
962   $ echo -n hello > /tmp/hello.txt
963   $ curl 'http://localhost/multi'
964   querystring: foo=Foo
965   method: POST
966   body: hi
967   content length: 2
968   ///
969   querystring: bar=Bar
970   method: PUT
971   body: hello
972   content length: 5
973   ///
974```
975
976Here's more funny example using the standard [proxy module](#httpproxymodule) to handle the subrequest:
977
978```nginx
979
980 location /main {
981     echo_subrequest_async POST /sub -b 'hello, world';
982 }
983 location /sub {
984     proxy_pass $scheme://127.0.0.1:$server_port/proxied;
985 }
986 location /proxied {
987     echo "method: $echo_request_method.";
988
989     # we need to read body explicitly here...or $echo_request_body
990     #   will evaluate to empty ("")
991     echo_read_request_body;
992
993     echo "body: $echo_request_body.";
994 }
995```
996
997Then on the client side, we can see that
998
999```bash
1000
1001   $ curl 'http://localhost/main'
1002   method: POST.
1003   body: hello, world.
1004```
1005
1006Nginx named locations like `@foo` is *not* supported here.
1007
1008This directive takes several options:
1009
1010
1011    -q <url_args>        Specify the URL arguments (or URL querystring) for the subrequest.
1012
1013    -f <path>            Specify the path for the file whose content will be serve as the
1014                         subrequest's request body.
1015
1016    -b <data>            Specify the request body data
1017
1018
1019This directive was first introduced in the [release v0.15](#v015).
1020
1021The `-f` option to define a file path for the body was introduced in the [release v0.35](#v035).
1022
1023See also the [echo_subrequest](#echo_subrequest) and [echo_location_async](#echo_location_async) directives.
1024
1025[Back to TOC](#table-of-contents)
1026
1027echo_subrequest
1028---------------
1029**syntax:** *echo_subrequest &lt;HTTP_method&gt; &lt;location&gt; [-q &lt;url_args&gt;] [-b &lt;request_body&gt;] [-f &lt;request_body_path&gt;]*
1030
1031**default:** *no*
1032
1033**context:** *location, location if*
1034
1035**phase:** *content*
1036
1037This is the synchronous version of the [echo_subrequest_async](#echo_subrequest_async) directive. And just like [echo_location](#echo_location), it does not block the Nginx worker process (while [echo_blocking_sleep](#echo_blocking_sleep) does), rather, it uses continuation to pass control along the subrequest chain.
1038
1039See [echo_subrequest_async](#echo_subrequest_async) for more details.
1040
1041Nginx named locations like `@foo` is *not* supported here.
1042
1043This directive was first introduced in the [release v0.15](#v015).
1044
1045[Back to TOC](#table-of-contents)
1046
1047echo_foreach_split
1048------------------
1049**syntax:** *echo_foreach_split &lt;delimiter&gt; &lt;string&gt;*
1050
1051**default:** *no*
1052
1053**context:** *location, location if*
1054
1055**phase:** *content*
1056
1057Split the second argument `string` using the delimiter specified in the first argument, and then iterate through the resulting items. For instance:
1058
1059```nginx
1060
1061   location /loop {
1062     echo_foreach_split ',' $arg_list;
1063       echo "item: $echo_it";
1064     echo_end;
1065   }
1066```
1067
1068Accessing /main yields
1069
1070```bash
1071
1072   $ curl 'http://localhost/loop?list=cat,dog,mouse'
1073   item: cat
1074   item: dog
1075   item: mouse
1076```
1077
1078As seen in the previous example, this directive should always be accompanied by an [echo_end](#echo_end) directive.
1079
1080Parallel `echo_foreach_split` loops are allowed, but nested ones are currently forbidden.
1081
1082The `delimiter` argument could contain *multiple* arbitrary characters, like
1083
1084```nginx
1085
1086   # this outputs "cat\ndog\nmouse\n"
1087   echo_foreach_split -- '-a-' 'cat-a-dog-a-mouse';
1088     echo $echo_it;
1089   echo_end;
1090```
1091
1092Logically speaking, this looping structure is just the `foreach` loop combined with a `split` function call in Perl (using the previous example):
1093
1094```perl
1095
1096    foreach (split ',', $arg_list) {
1097        print "item $_\n";
1098    }
1099```
1100
1101People will also find it useful in merging multiple `.js` or `.css` resources into a whole. Here's an example:
1102
1103```nginx
1104
1105   location /merge {
1106       default_type 'text/javascript';
1107
1108       echo_foreach_split '&' $query_string;
1109           echo "/* JS File $echo_it */";
1110           echo_location_async $echo_it;
1111           echo;
1112       echo_end;
1113   }
1114```
1115
1116Then accessing /merge to merge the `.js` resources specified in the query string:
1117
1118```bash
1119
1120   $ curl 'http://localhost/merge?/foo/bar.js&/yui/blah.js&/baz.js'
1121```
1122
1123One can also use third-party Nginx cache module to cache the merged response generated by the `/merge` location in the previous example.
1124
1125This directive was first introduced in the [release v0.17](#v017).
1126
1127[Back to TOC](#table-of-contents)
1128
1129echo_end
1130--------
1131**syntax:** *echo_end*
1132
1133**default:** *no*
1134
1135**context:** *location, location if*
1136
1137**phase:** *content*
1138
1139This directive is used to terminate the body of looping and conditional control structures like [echo_foreach_split](#echo_foreach_split).
1140
1141This directive was first introduced in the [release v0.17](#v017).
1142
1143[Back to TOC](#table-of-contents)
1144
1145echo_request_body
1146-----------------
1147**syntax:** *echo_request_body*
1148
1149**default:** *no*
1150
1151**context:** *location, location if*
1152
1153**phase:** *content*
1154
1155Outputs the contents of the request body previous read.
1156
1157Behind the scene, it's implemented roughly like this:
1158
1159```C
1160
1161   if (r->request_body && r->request_body->bufs) {
1162       return ngx_http_output_filter(r, r->request_body->bufs);
1163   }
1164```
1165
1166Unlike the [$echo_request_body](#echo_request_body) and $request_body variables, this directive will show the whole request body even if some parts or all parts of it are saved in temporary files on the disk.
1167
1168It is a "no-op" if no request body has been read yet.
1169
1170This directive was first introduced in the [release v0.18](#v018).
1171
1172See also [echo_read_request_body](#echo_read_request_body) and the [chunkin module](http://github.com/agentzh/chunkin-nginx-module).
1173
1174[Back to TOC](#table-of-contents)
1175
1176echo_exec
1177---------
1178**syntax:** *echo_exec &lt;location&gt; [&lt;query_string&gt;]*
1179
1180**syntax:** *echo_exec &lt;named_location&gt;*
1181
1182**default:** *no*
1183
1184**context:** *location, location if*
1185
1186**phase:** *content*
1187
1188Does an internal redirect to the location specified. An optional query string can be specified for normal locations, as in
1189
1190```nginx
1191
1192   location /foo {
1193       echo_exec /bar weight=5;
1194   }
1195   location /bar {
1196       echo $arg_weight;
1197   }
1198```
1199
1200Or equivalently
1201
1202```nginx
1203
1204   location /foo {
1205       echo_exec /bar?weight=5;
1206   }
1207   location /bar {
1208       echo $arg_weight;
1209   }
1210```
1211
1212Named locations are also supported. Here's an example:
1213
1214```nginx
1215
1216   location /foo {
1217       echo_exec @bar;
1218   }
1219   location @bar {
1220       # you'll get /foo rather than @bar
1221       #  due to a potential bug in nginx.
1222       echo $echo_request_uri;
1223   }
1224```
1225
1226But query string (if any) will always be ignored for named location redirects due to a limitation in the `ngx_http_named_location` function.
1227
1228Never try to echo things before the `echo_exec` directive or you won't see the proper response of the location you want to redirect to. Because any echoing will cause the original location handler to send HTTP headers before the redirection happens.
1229
1230Technically speaking, this directive exposes the Nginx internal API functions `ngx_http_internal_redirect` and `ngx_http_named_location`.
1231
1232This directive was first introduced in the [v0.21 release](#v021).
1233
1234[Back to TOC](#table-of-contents)
1235
1236echo_status
1237-----------
1238**syntax:** *echo_status &lt;status-num&gt;*
1239
1240**default:** *echo_status 200*
1241
1242**context:** *location, location if*
1243
1244**phase:** *content*
1245
1246Specify the default response status code. Default to `200`. This directive is declarative and the relative order with other echo-like directives is not important.
1247
1248Here is an example,
1249
1250```nginx
1251
1252 location = /bad {
1253     echo_status 404;
1254     echo "Something is missing...";
1255 }
1256```
1257
1258then we get a response like this:
1259
1260
1261    HTTP/1.1 404 Not Found
1262    Server: nginx/1.2.1
1263    Date: Sun, 24 Jun 2012 03:58:18 GMT
1264    Content-Type: text/plain
1265    Transfer-Encoding: chunked
1266    Connection: keep-alive
1267
1268    Something is missing...
1269
1270
1271This directive was first introduced in the `v0.40` release.
1272
1273[Back to TOC](#table-of-contents)
1274
1275Filter Directives
1276=================
1277
1278Use of the following directives trigger the filter registration of this module. By default, no filter will be registered by this module.
1279
1280Every filter directive supports variable interpolation in its arguments (if any).
1281
1282[Back to TOC](#table-of-contents)
1283
1284echo_before_body
1285----------------
1286**syntax:** *echo_before_body \[options\] \[argument\]...*
1287
1288**default:** *no*
1289
1290**context:** *location, location if*
1291
1292**phase:** *output filter*
1293
1294It's the filter version of the [echo](#echo) directive, and prepends its output to the beginning of the original outputs generated by the underlying content handler.
1295
1296An example is
1297
1298```nginx
1299
1300 location /echo {
1301     echo_before_body hello;
1302     proxy_pass $scheme://127.0.0.1:$server_port$request_uri/more;
1303 }
1304 location /echo/more {
1305     echo world
1306 }
1307```
1308
1309Accessing `/echo` from the client side yields
1310
1311```bash
1312
1313   hello
1314   world
1315```
1316
1317In the previous sample, we borrow the [standard proxy module](http://nginx.org/en/docs/http/ngx_http_proxy_module.html) to serve as the underlying content handler that generates the "main contents".
1318
1319Multiple instances of this filter directive are also allowed, as in:
1320
1321```nginx
1322
1323 location /echo {
1324     echo_before_body hello;
1325     echo_before_body world;
1326     echo !;
1327 }
1328```
1329
1330On the client side, the output is like
1331
1332```bash
1333
1334   $ curl 'http://localhost/echo'
1335   hello
1336   world
1337   !
1338```
1339
1340In this example, we also use the [content handler directives](#content-handler-directives) provided by this module as the underlying content handler.
1341
1342This directive also supports the `-n` and `--` options like the [echo](#echo) directive.
1343
1344This directive can be mixed with its brother directive [echo_after_body](#echo_after_body).
1345
1346[Back to TOC](#table-of-contents)
1347
1348echo_after_body
1349---------------
1350**syntax:** *echo_after_body \[argument\]...*
1351
1352**default:** *no*
1353
1354**context:** *location, location if*
1355
1356**phase:** *output filter*
1357
1358It's very much like the [echo_before_body](#echo_before_body) directive, but *appends* its output to the end of the original outputs generated by the underlying content handler.
1359
1360Here's a simple example:
1361
1362```nginx
1363
1364 location /echo {
1365     echo_after_body hello;
1366     proxy_pass http://127.0.0.1:$server_port$request_uri/more;
1367 }
1368 location /echo/more {
1369     echo world
1370 }
1371```
1372
1373Accessing `/echo` from the client side yields
1374
1375
1376      world
1377      hello
1378
1379
1380Multiple instances are allowed, as in:
1381
1382```nginx
1383
1384 location /echo {
1385     echo_after_body hello;
1386     echo_after_body world;
1387     echo i;
1388     echo say;
1389 }
1390```
1391
1392The output on the client side while accessing the `/echo` location looks like
1393
1394
1395      i
1396      say
1397      hello
1398      world
1399
1400
1401This directive also supports the `-n` and `--` options like the [echo](#echo) directive.
1402
1403This directive can be mixed with its brother directive [echo_before_body](#echo_before_body).
1404
1405[Back to TOC](#table-of-contents)
1406
1407Variables
1408=========
1409
1410[Back to TOC](#table-of-contents)
1411
1412$echo_it
1413--------
1414
1415This is a "topic variable" used by [echo_foreach_split](#echo_foreach_split), just like the `$_` variable in Perl.
1416
1417[Back to TOC](#table-of-contents)
1418
1419$echo_timer_elapsed
1420-------------------
1421
1422This variable holds the seconds elapsed since the start of the current request (might be a subrequest though) or the last invocation of the [echo_reset_timer](#echo_reset_timer) command.
1423
1424The timing result takes three digits after the decimal point.
1425
1426References of this variable will force the underlying Nginx timer to update to the current system time, regardless the timer resolution settings elsewhere in the config file, just like the [echo_reset_timer](#echo_reset_timer) directive.
1427
1428[Back to TOC](#table-of-contents)
1429
1430$echo_request_body
1431------------------
1432
1433Evaluates to the current (sub)request's request body previously read if no part of the body has been saved to a temporary file. To always show the request body even if it's very large, use the [echo_request_body](#echo_request_body) directive.
1434
1435[Back to TOC](#table-of-contents)
1436
1437$echo_request_method
1438--------------------
1439
1440Evaluates to the HTTP request method of the current request (it can be a subrequest).
1441
1442Behind the scene, it just takes the string data stored in `r->method_name`.
1443
1444Compare it to the [$echo_client_request_method](#echo_client_request_method) variable.
1445
1446At least for Nginx 0.8.20 and older, the [$request_method](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_method) variable provided by the [http core module](http://nginx.org/en/docs/http/ngx_http_core_module.html) is actually doing what our [$echo_client_request_method](#echo_client_request_method) is doing.
1447
1448This variable was first introduced in our [v0.15 release](#v015).
1449
1450[Back to TOC](#table-of-contents)
1451
1452$echo_client_request_method
1453---------------------------
1454
1455Always evaluates to the main request's HTTP method even if the current request is a subrequest.
1456
1457Behind the scene, it just takes the string data stored in `r->main->method_name`.
1458
1459Compare it to the [$echo_request_method](#echo_request_method) variable.
1460
1461This variable was first introduced in our [v0.15 release](#v015).
1462
1463[Back to TOC](#table-of-contents)
1464
1465$echo_client_request_headers
1466----------------------------
1467
1468Evaluates to the original client request's headers.
1469
1470Just as the name suggests, it will always take the main request (or the client request) even if it's currently executed in a subrequest.
1471
1472A simple example is below:
1473
1474```nginx
1475
1476   location /echoback {
1477      echo "headers are:"
1478      echo $echo_client_request_headers;
1479   }
1480```
1481
1482Accessing `/echoback` yields
1483
1484```bash
1485
1486   $ curl 'http://localhost/echoback'
1487   headers are
1488   GET /echoback HTTP/1.1
1489   User-Agent: curl/7.18.2 (i486-pc-linux-gnu) libcurl/7.18.2 OpenSSL/0.9.8g
1490   Host: localhost:1984
1491   Accept: */*
1492```
1493
1494Behind the scene, it recovers `r->main->header_in` (or the large header buffers, if any) on the C level and does not construct the headers itself by traversing parsed results in the request object.
1495
1496This varible is always evaluated to an empty value in HTTP/2 requests for now due to the current implementation.
1497
1498This variable was first introduced in [version 0.15](#v015).
1499
1500[Back to TOC](#table-of-contents)
1501
1502$echo_cacheable_request_uri
1503---------------------------
1504
1505Evaluates to the parsed form of the URI (usually led by `/`) of the current (sub-)request. Unlike the [$echo_request_uri](#echo_request_uri) variable, it is cacheable.
1506
1507See [$echo_request_uri](#echo_request_uri) for more details.
1508
1509This variable was first introduced in [version 0.17](#v017).
1510
1511[Back to TOC](#table-of-contents)
1512
1513$echo_request_uri
1514-----------------
1515
1516Evaluates to the parsed form of the URI (usually led by `/`) of the current (sub-)request. Unlike the [$echo_cacheable_request_uri](#echo_cacheable_request_uri) variable, it is *not* cacheable.
1517
1518This is quite different from the [$request_uri](http://nginx.org/en/docs/http/ngx_http_core_module.html#var_request_uri) variable exported by the [ngx_http_core_module](http://nginx.org/en/docs/http/ngx_http_core_module.html), because `$request_uri` is the *unparsed* form of the current request's URI.
1519
1520This variable was first introduced in [version 0.17](#v017).
1521
1522[Back to TOC](#table-of-contents)
1523
1524$echo_incr
1525----------
1526
1527It is a counter that always generate the current counting number, starting from 1. The counter is always associated with the main request even if it is accessed within a subrequest.
1528
1529Consider the following example
1530
1531```Nginx
1532
1533 location /main {
1534     echo "main pre: $echo_incr";
1535     echo_location_async /sub;
1536     echo_location_async /sub;
1537     echo "main post: $echo_incr";
1538 }
1539 location /sub {
1540     echo "sub: $echo_incr";
1541 }
1542```
1543
1544Accessing `/main` yields
1545
1546    main pre: 1
1547    sub: 3
1548    sub: 4
1549    main post: 2
1550
1551This directive was first introduced in the [v0.18 release](#v018).
1552
1553[Back to TOC](#table-of-contents)
1554
1555$echo_response_status
1556---------------------
1557
1558Evaluates to the status code of the current (sub)request, null if not any.
1559
1560Behind the scene, it's just the textual representation of `r->headers_out->status`.
1561
1562This directive was first introduced in the [v0.23 release](#v023).
1563
1564[Back to TOC](#table-of-contents)
1565
1566Installation
1567============
1568
1569You're recommended to install this module (as well as the Nginx core and many other goodies) via the [OpenResty bundle](http://openresty.org). See [the detailed instructions](http://openresty.org/#Installation) for downloading and installing OpenResty into your system. This is the easiest and most safe way to set things up.
1570
1571Alternatively, you can install this module manually with the Nginx source:
1572
1573Grab the nginx source code from [nginx.org](http://nginx.org/), for example,
1574the version 1.11.2 (see [nginx compatibility](#compatibility)), and then build the source with this module:
1575
1576```bash
1577
1578 $ wget 'http://nginx.org/download/nginx-1.11.2.tar.gz'
1579 $ tar -xzvf nginx-1.11.2.tar.gz
1580 $ cd nginx-1.11.2/
1581
1582 # Here we assume you would install you nginx under /opt/nginx/.
1583 $ ./configure --prefix=/opt/nginx \
1584     --add-module=/path/to/echo-nginx-module
1585
1586 $ make -j2
1587 $ make install
1588```
1589
1590Download the latest version of the release tarball of this module from [echo-nginx-module file list](https://github.com/openresty/echo-nginx-module/tags).
1591
1592Starting from NGINX 1.9.11, you can also compile this module as a dynamic module, by using the `--add-dynamic-module=PATH` option instead of `--add-module=PATH` on the
1593`./configure` command line above. And then you can explicitly load the module in your `nginx.conf` via the [load_module](http://nginx.org/en/docs/ngx_core_module.html#load_module)
1594directive, for example,
1595
1596```nginx
1597load_module /path/to/modules/ngx_http_echo_module.so;
1598```
1599
1600Also, this module is included and enabled by default in the [OpenResty bundle](http://openresty.org).
1601
1602[Back to TOC](#table-of-contents)
1603
1604Compatibility
1605=============
1606
1607The following versions of Nginx should work with this module:
1608
1609* **1.16.x**
1610* **1.15.x**                      (last tested: 1.15.8)
1611* **1.14.x**
1612* **1.13.x**                      (last tested: 1.13.6)
1613* **1.12.x**
1614* **1.11.x**                      (last tested: 1.11.2)
1615* **1.10.x**
1616* **1.9.x**                       (last tested: 1.9.15)
1617* **1.8.x**
1618* **1.7.x**                       (last tested: 1.7.10)
1619* **1.6.x**
1620* **1.5.x**                       (last tested: 1.5.12)
1621* **1.4.x**                       (last tested: 1.4.4)
1622* **1.3.x**                       (last tested: 1.3.7)
1623* **1.2.x**                       (last tested: 1.2.9)
1624* **1.1.x**                       (last tested: 1.1.5)
1625* **1.0.x**                       (last tested: 1.0.11)
1626* **0.9.x**                       (last tested: 0.9.4)
1627* **0.8.x**                       (last tested: 0.8.54)
1628* **0.7.x >= 0.7.21**             (last tested: 0.7.68)
1629
1630In particular,
1631
1632* the directive [echo_location_async](#echo_location_async) and its brother [echo_subrequest_async](#echo_subrequest_async) do *not* work with **0.7.x < 0.7.46**.
1633* the [echo_after_body](#echo_after_body) directive does *not* work at all with nginx **< 0.8.7**.
1634* the [echo_sleep](#echo_sleep) directive cannot be used after [echo_location](#echo_location) or [echo_subrequest](#echo_subrequest) for nginx **< 0.8.11**.
1635
1636Earlier versions of Nginx like 0.6.x and 0.5.x will *not* work at all.
1637
1638If you find that any particular version of Nginx above 0.7.21 does not work with this module, please consider [reporting a bug](#report-bugs).
1639
1640[Back to TOC](#table-of-contents)
1641
1642Modules that use this module for testing
1643========================================
1644
1645The following modules take advantage of this `echo` module in their test suite:
1646
1647* The [memc](http://github.com/openresty/memc-nginx-module) module that supports almost the whole memcached TCP protocol.
1648* The [chunkin](http://github.com/agentzh/chunkin-nginx-module) module that adds HTTP 1.1 chunked input support to Nginx.
1649* The [headers_more](http://github.com/openresty/headers-more-nginx-module) module that allows you to add, set, and clear input and output headers under the conditions that you specify.
1650* The `echo` module itself.
1651
1652Please mail me other modules that use `echo` in any form and I'll add them to the list above :)
1653
1654[Back to TOC](#table-of-contents)
1655
1656Community
1657=========
1658
1659[Back to TOC](#table-of-contents)
1660
1661English Mailing List
1662--------------------
1663
1664The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers.
1665
1666[Back to TOC](#table-of-contents)
1667
1668Chinese Mailing List
1669--------------------
1670
1671The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers.
1672
1673[Back to TOC](#table-of-contents)
1674
1675Report Bugs
1676===========
1677
1678Although a lot of effort has been put into testing and code tuning, there must be some serious bugs lurking somewhere in this module. So whenever you are bitten by any quirks, please don't hesitate to
1679
16801. create a ticket on the [issue tracking interface](https://github.com/openresty/echo-nginx-module/issues) provided by GitHub,
16811. or send a bug report, questions, or even patches to the [OpenResty Community](#community).
1682
1683[Back to TOC](#table-of-contents)
1684
1685Source Repository
1686=================
1687
1688Available on github at [openresty/echo-nginx-module](https://github.com/openresty/echo-nginx-module).
1689
1690[Back to TOC](#table-of-contents)
1691
1692Changes
1693=======
1694
1695The changes of every release of this module can be obtained from the OpenResty bundle's change logs:
1696
1697<http://openresty.org/#Changes>
1698
1699[Back to TOC](#table-of-contents)
1700
1701Test Suite
1702==========
1703
1704This module comes with a Perl-driven test suite. The [test cases](https://github.com/openresty/echo-nginx-module/tree/master/t/) are
1705[declarative](https://github.com/openresty/echo-nginx-module/blob/master/t/echo.t) too. Thanks to the [Test::Nginx](http://search.cpan.org/perldoc?Test::Nginx) module in the Perl world.
1706
1707To run it on your side:
1708
1709```bash
1710
1711 $ PATH=/path/to/your/nginx-with-echo-module:$PATH prove -r t
1712```
1713
1714You need to terminate any Nginx processes before running the test suite if you have changed the Nginx server binary.
1715
1716Because a single nginx server (by default, `localhost:1984`) is used across all the test scripts (`.t` files), it's meaningless to run the test suite in parallel by specifying `-jN` when invoking the `prove` utility.
1717
1718Some parts of the test suite requires standard modules [proxy](http://nginx.org/en/docs/http/ngx_http_proxy_module.html), [rewrite](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html) and [SSI](http://nginx.org/en/docs/http/ngx_http_ssi_module.html) to be enabled as well when building Nginx.
1719
1720[Back to TOC](#table-of-contents)
1721
1722TODO
1723====
1724
1725* Fix the [echo_after_body](#echo_after_body) directive in subrequests.
1726* Add directives *echo_read_client_request_body* and *echo_request_headers*.
1727* Add new directive *echo_log* to use Nginx's logging facility directly from the config file and specific loglevel can be specified, as in
1728
1729```nginx
1730
1731   echo_log debug "I am being called.";
1732```
1733
1734* Add support for options `-h` and `-t` to [echo_subrequest_async](#echo_subrequest_async) and [echo_subrequest](#echo_subrequest). For example
1735
1736```nginx
1737
1738   echo_subrequest POST /sub -q 'foo=Foo&bar=Bar' -b 'hello' -t 'text/plan' -h 'X-My-Header: blah blah'
1739```
1740
1741* Add options to control whether a subrequest should inherit cached variables from its parent request (i.e. the current request that is calling the subrequest in question). Currently none of the subrequests issued by this module inherit the cached variables from the parent request.
1742* Add new variable *$echo_active_subrequests* to show `r->main->count - 1`.
1743* Add the *echo_file* and *echo_cached_file* directives.
1744* Add new varaible *$echo_request_headers* to accompany the existing [$echo_client_request_headers](#echo_client_request_headers) variable.
1745* Add new directive *echo_foreach*, as in
1746
1747```nginx
1748
1749   echo_foreach 'cat' 'dog' 'mouse';
1750     echo_location_async "/animals/$echo_it";
1751   echo_end;
1752```
1753
1754* Add new directive *echo_foreach_range*, as in
1755
1756```nginx
1757
1758   echo_foreach_range '[1..100]' '[a-zA-z0-9]';
1759     echo_location_async "/item/$echo_it";
1760   echo_end;
1761```
1762
1763* Add new directive *echo_repeat*, as in
1764
1765```nginx
1766
1767   echo_repeat 10 $i {
1768       echo "Page $i";
1769       echo_location "/path/to/page/$i";
1770   }
1771```
1772
1773This is just another way of saying
1774
1775```nginx
1776
1777   echo_foreach_range $i [1..10];
1778       echo "Page $i";
1779       echo_location "/path/to/page/$i";
1780   echo_end;
1781```
1782
1783Thanks Marcus Clyne for providing this idea.
1784
1785* Add new variable $echo_random which always returns a random non-negative integer with the lower/upper limit specified by the new directives `echo_random_min` and `echo_random_max`. For example,
1786
1787```nginx
1788
1789   echo_random_min  10
1790   echo_random_max  200
1791   echo "random number: $echo_random";
1792```
1793
1794Thanks Marcus Clyne for providing this idea.
1795
1796[Back to TOC](#table-of-contents)
1797
1798Getting involved
1799================
1800
1801You'll be very welcomed to submit patches to the [author](#author) or just ask for a commit bit to the [source repository](#source-repository) on GitHub.
1802
1803[Back to TOC](#table-of-contents)
1804
1805Author
1806======
1807
1808Yichun "agentzh" Zhang (章亦春) *&lt;agentzh@gmail.com&gt;*, OpenResty Inc.
1809
1810This wiki page is also maintained by the author himself, and everybody is encouraged to improve this page as well.
1811
1812[Back to TOC](#table-of-contents)
1813
1814Copyright & License
1815===================
1816
1817Copyright (c) 2009-2018, Yichun "agentzh" Zhang (章亦春) <agentzh@gmail.com>, OpenResty Inc.
1818
1819This module is licensed under the terms of the BSD license.
1820
1821Redistribution and use in source and binary forms, with or without
1822modification, are permitted provided that the following conditions
1823are met:
1824
1825* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
1826* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
1827
1828THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1829"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1830LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1831A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
1832HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
1833SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
1834TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
1835PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
1836LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
1837NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
1838SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
1839
1840[Back to TOC](#table-of-contents)
1841
1842See Also
1843========
1844
1845* The original [blog post](http://agentzh.blogspot.com/2009/10/hacking-on-nginx-echo-module.html) about this module's initial development.
1846* The standard [addition filter module](http://nginx.org/en/docs/http/ngx_http_addition_module.html).
1847* The standard [proxy module](http://nginx.org/en/docs/http/ngx_http_proxy_module.html).
1848* The [OpenResty](http://openresty.org) bundle.
1849
1850[Back to TOC](#table-of-contents)
1851
1852