diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..6fe6f35cec --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.t linguist-language=Text diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000000..e6359b0a07 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,23 @@ +This place is for bug reports and development discussions only. For general questions and +discussions, please join the openresty-en mailing list instead: https://openresty.org/en/community.html + +Ensure you have provided the following details while reporting a problem: + +* The exact version of the related software, including but not limited to the OpenResty version +(if any), the NGINX core version, the `ngx_lua` module version, +and your operating system version. +* A minimal and standalone test case that others can easily run on their side and +reproduce the issue you are seeing. +* Do not simply say "something is broken" or "something does not work". Always provide +as much details as possible. Always describe the symptoms and your expected results. +* You can (temporarily) enable the nginx debugging logs to see the internal workings +of NGINX in your nginx''s `error.log` file. See http://nginx.org/en/docs/debugging_log.html +The same instructions apply equally well to OpenResty. +* If you are seeing crashes, please provide the full backtrace for the crash. See +https://www.nginx.com/resources/wiki/start/topics/tutorials/debugging/#core-dump +for more details. + +Please, do not use Chinese here. This place is considered English only. If you +really want to use Chinese, please join and post to the openresty (Chinese) +mailing list instead. Please see https://openresty.org/en/community.html Thanks for +your cooperation. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000000..5e833bab31 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,2 @@ +I hereby granted the copyright of the changes in this pull request +to the authors of this lua-nginx-module project. diff --git a/.github/workflows/semantic-pull-request.yml b/.github/workflows/semantic-pull-request.yml new file mode 100644 index 0000000000..12b87cb3c1 --- /dev/null +++ b/.github/workflows/semantic-pull-request.yml @@ -0,0 +1,30 @@ +name: "Lint PR" + +on: + pull_request_target: + types: + - opened + - edited + - synchronize + +jobs: + main: + name: Validate PR title + runs-on: ubuntu-latest + steps: + - uses: amannn/action-semantic-pull-request@v4 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + # Configure which types are allowed. + # Default: https://github.com/commitizen/conventional-commit-types + types: | + bugfix # bug fixes + change # backward incompatible changes + doc # documentation changes including code comments + editor # code editor related configurations + feature # implementing a new feature + optimize # performance optimizations + refactor # code refactoring and other code rearrangement + style # coding style changes + tests # test suite changes diff --git a/.gitignore b/.gitignore index 334f0d7b06..5a8d398bb8 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ test/blib test.sh t.sh t/t.sh +t/servroot* test/t/servroot/ releng reset @@ -122,10 +123,13 @@ src/filter.[ch] src/shdict.[ch] src/body.[ch] src/uri.[ch] -src/socket.[ch] +src/api.[ch] +src/coroutine.[ch] +src/logby.[ch] +src/sleep.[ch] a.patch all -build1[01] +build1[0-9] g buildroot/ src/headerfilterby.[ch] @@ -133,3 +137,44 @@ src/headerfilterby.[ch] analyze tsock a.c +test.lua +build12 +ERRORS +src/bodyfilterby.[ch] +src/tcp.[ch] +src/initby.[ch] +src/initworkerby.[ch] +src/socket.[ch] +src/udp.[ch] +src/method.[ch] +tre +src/phase.[ch] +src/probe.h +src/uthread.[ch] +src/timer.[ch] +src/config.[ch] +src/worker.[ch] +src/certby.[ch] +src/storeby.[ch] +src/fetchby.[ch] +src/ssl.[ch] +src/ocsp.c +src/lex.[ch] +src/balancer.[ch] +src/semaphore.[ch] +*.plist +lua +ttimer +Makefile +tsubreq +tthread +addr2line +hup +theaders +src/ngx_http_lua_autoconf.h +src/autoconf.h +src/filters.c +src/filters.h +src/ringbuf.c +src/ringbuf.h +src/pipe.[ch] diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index db339a7d34..0000000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "deps/ngx_devel_kit"] - path = deps/ngx_devel_kit - url = git://github.com/simpl/ngx_devel_kit.git diff --git a/.mergify.yml b/.mergify.yml new file mode 100644 index 0000000000..f1a8a2e255 --- /dev/null +++ b/.mergify.yml @@ -0,0 +1,43 @@ +--- +pull_request_rules: + - name: warn on conflicts + conditions: + - conflict + actions: + comment: + message: This pull request is now in conflict :( + label: + add: + - conflict + - name: remove conflict label if not needed + conditions: + - -conflict + actions: + label: + remove: + - conflict + - name: add label needs-test-cases + conditions: + - files~=^src/ + - -files~=^t/ + actions: + label: + add: + - needs-test-cases + - name: remove label needs-test-cases + conditions: + - label=needs-test-cases + - files~=^src/ + - files~=^t/ + actions: + label: + remove: + - needs-test-cases + - name: add label could-be-merged + conditions: + - "#approved-reviews-by>=2" + - status-success=Travis CI - Pull Request + actions: + label: + add: + - could-be-merged diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..4aebcf6996 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,159 @@ +dist: focal + +branches: + only: + - "master" + +os: linux + +language: c + +compiler: + - gcc + +addons: + apt: + packages: + - ack + - axel + - cpanminus + - libtest-base-perl + - libtext-diff-perl + - liburi-perl + - libwww-perl + - libtest-longstring-perl + - liblist-moreutils-perl + - libgd-dev + - time + - cmake + - libunwind-dev + - wget + - libbrotli1 + - lsb-release + - wget + - gnupg + - ca-certificates + +cache: + directories: + - download-cache + +env: + global: + - JOBS=3 + - NGX_BUILD_JOBS=$JOBS + - LUAJIT_PREFIX=/opt/luajit21 + - LUAJIT_LIB=$LUAJIT_PREFIX/lib + - LUAJIT_INC=$LUAJIT_PREFIX/include/luajit-2.1 + - LUA_INCLUDE_DIR=$LUAJIT_INC + #- PCRE2_PREFIX=/usr/local/openresty/pcre2 + - PCRE2_PREFIX=/opt/pcre2 + - PCRE2_LIB=$PCRE2_PREFIX/lib + - PCRE2_INC=$PCRE2_PREFIX/include + #- OPENSSL_PREFIX=/usr/local/openresty/openssl3 + - OPENSSL_PREFIX=/opt/openssl3 + - OPENSSL_LIB=$OPENSSL_PREFIX/lib + - OPENSSL_INC=$OPENSSL_PREFIX/include + - LIBDRIZZLE_PREFIX=/opt/drizzle + - LIBDRIZZLE_INC=$LIBDRIZZLE_PREFIX/include/libdrizzle-1.0 + - LIBDRIZZLE_LIB=$LIBDRIZZLE_PREFIX/lib + - LD_LIBRARY_PATH=$LUAJIT_LIB:$LD_LIBRARY_PATH + - DRIZZLE_VER=2011.07.21 + - TEST_NGINX_SLEEP=0.006 + - MALLOC_PERTURB_=9 + jobs: + - NGINX_VERSION=1.29.2 OPENSSL_VER=3.5.4 OPENSSL_PATCH_VER=3.5.4 TEST_NGINX_TIMEOUT=5 PCRE2_VER=10.46 + - NGINX_VERSION=1.29.2 OPENSSL_VER=3.5.4 OPENSSL_PATCH_VER=3.5.4 TEST_NGINX_TIMEOUT=5 PCRE2_VER=10.46 TEST_NGINX_USE_HTTP2=1 + - NGINX_VERSION=1.29.2 OPENSSL_VER=3.5.4 OPENSSL_PATCH_VER=3.5.4 TEST_NGINX_USE_HTTP3=1 TEST_NGINX_QUIC_IDLE_TIMEOUT=3 PCRE2_VER=10.46 + - NGINX_VERSION=1.29.2 BORINGSSL=1 TEST_NGINX_USE_HTTP3=1 TEST_NGINX_QUIC_IDLE_TIMEOUT=3 PCRE2_VER=10.46 + +services: + - memcached + - redis + - mysql + +before_install: + - '! grep -n -P ''(?<=.{80}).+'' --color `find src -name ''*.c''` `find . -name ''*.h''` || (echo "ERROR: Found C source lines exceeding 80 columns." > /dev/stderr; exit 1)' + - '! grep -n -P ''\t+'' --color `find src -name ''*.c''` `find . -name ''*.h''` || (echo "ERROR: Cannot use tabs." > /dev/stderr; exit 1)' + - /usr/bin/env perl $(command -v cpanm) --sudo --notest Test::Nginx IPC::Run > build.log 2>&1 || (cat build.log && exit 1) + - wget -O - https://openresty.org/package/pubkey.gpg | sudo apt-key add - + - echo "deb http://openresty.org/package/ubuntu $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/openresty.list + - sudo apt-get update + - sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends openresty-pcre2 openresty-openssl3 openresty-pcre2-dev openresty-openssl3-dev + + +install: + - if [ ! -f download-cache/drizzle7-$DRIZZLE_VER.tar.gz ]; then wget -P download-cache https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/drizzle7-$DRIZZLE_VER.tar.gz; fi + - if [ -n "$PCRE2_VER" ] && [ ! -f download-cache/pcre2-$PCRE2_VER.tar.gz ]; then wget -P download-cache https://github.com/PCRE2Project/pcre2/releases/download/pcre2-${PCRE2_VER}/pcre2-${PCRE2_VER}.tar.gz; fi + - if [ -n "$OPENSSL_VER" ] && [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then wget -P download-cache https://github.com/openssl/openssl/releases/download/openssl-$OPENSSL_VER/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/openssl-$OPENSSL_VER.tar.gz || wget -P download-cache https://www.openssl.org/source/old/${OPENSSL_VER//[a-z]/}/openssl-$OPENSSL_VER.tar.gz; fi + - wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/boringssl-20230902-x64-focal.tar.gz + - wget https://github.com/openresty/openresty-deps-prebuild/releases/download/v20230902/curl-h3-x64-focal.tar.gz + - git clone https://github.com/openresty/test-nginx.git + - git clone https://github.com/openresty/openresty.git ../openresty + - git clone https://github.com/openresty/no-pool-nginx.git ../no-pool-nginx + - git clone https://github.com/openresty/openresty-devel-utils.git + - git clone https://github.com/openresty/mockeagain.git + - git clone https://github.com/openresty/lua-cjson.git lua-cjson + - git clone https://github.com/openresty/lua-upstream-nginx-module.git ../lua-upstream-nginx-module + - git clone https://github.com/openresty/echo-nginx-module.git ../echo-nginx-module + - git clone https://github.com/openresty/nginx-eval-module.git ../nginx-eval-module + - git clone https://github.com/simpl/ngx_devel_kit.git ../ndk-nginx-module + - git clone https://github.com/FRiCKLE/ngx_coolkit.git ../coolkit-nginx-module + - git clone https://github.com/openresty/headers-more-nginx-module.git ../headers-more-nginx-module + - git clone https://github.com/openresty/drizzle-nginx-module.git ../drizzle-nginx-module + - git clone https://github.com/openresty/set-misc-nginx-module.git ../set-misc-nginx-module + - git clone https://github.com/openresty/memc-nginx-module.git ../memc-nginx-module + - git clone https://github.com/openresty/rds-json-nginx-module.git ../rds-json-nginx-module + - git clone https://github.com/openresty/srcache-nginx-module.git ../srcache-nginx-module + - git clone https://github.com/openresty/redis2-nginx-module.git ../redis2-nginx-module + - git clone https://github.com/openresty/lua-resty-core.git ../lua-resty-core + - git clone https://github.com/openresty/lua-resty-lrucache.git ../lua-resty-lrucache + - git clone https://github.com/openresty/lua-resty-mysql.git ../lua-resty-mysql + - git clone https://github.com/spacewander/lua-resty-rsa.git ../lua-resty-rsa + - git clone https://github.com/openresty/lua-resty-string.git ../lua-resty-string + - git clone https://github.com/openresty/stream-lua-nginx-module.git ../stream-lua-nginx-module + - git clone -b v2.1-agentzh https://github.com/openresty/luajit2.git luajit2 + +before_script: + - mysql -uroot -e "create database ngx_test; CREATE USER 'ngx_test'@'%' IDENTIFIED WITH mysql_native_password BY 'ngx_test'; grant all on ngx_test.* to 'ngx_test'@'%'; flush privileges;" + +script: + - sudo tar -C / -xf curl-h3-x64-focal.tar.gz + - export PATH=$PWD/work/nginx/sbin:$PWD/openresty-devel-utils:/opt/curl-h3/bin:$PATH + - ngx-releng > check.txt || true + - lines=`wc -l check.txt | awk '{print $1}'`; if [ $lines -gt 5 ]; then cat check.txt; exit 1; fi + - sudo iptables -I OUTPUT 1 -p udp --dport 10086 -j REJECT + - sudo iptables -I OUTPUT -p tcp --dst 127.0.0.2 --dport 12345 -j DROP + - sudo iptables -I OUTPUT -p udp --dst 127.0.0.2 --dport 12345 -j DROP + - sudo ip route add prohibit 0.0.0.1/32 + - sudo sysctl -w kernel.pid_max=10000 + - cd luajit2/ + - make -j$JOBS CCDEBUG=-g Q= PREFIX=$LUAJIT_PREFIX CC=$CC XCFLAGS='-DLUA_USE_APICHECK -DLUA_USE_ASSERT -msse4.2' > build.log 2>&1 || (cat build.log && exit 1) + - sudo make install PREFIX=$LUAJIT_PREFIX > build.log 2>&1 || (cat build.log && exit 1) + - cd .. + - tar xzf download-cache/drizzle7-$DRIZZLE_VER.tar.gz && cd drizzle7-$DRIZZLE_VER + - ./configure --prefix=$LIBDRIZZLE_PREFIX --without-server > build.log 2>&1 || (cat build.log && exit 1) + - make libdrizzle-1.0 -j$JOBS > build.log 2>&1 || (cat build.log && exit 1) + - sudo make install-libdrizzle-1.0 > build.log 2>&1 || (cat build.log && exit 1) + - cd ../mockeagain/ && make CC=$CC -j$JOBS && cd .. + - cd lua-cjson/ && make -j$JOBS && sudo make install && cd .. + - if [ -n "$PCRE2_VER" ]; then tar zxf download-cache/pcre2-$PCRE2_VER.tar.gz; cd pcre2-$PCRE2_VER/; ./configure --prefix=$PCRE2_PREFIX --enable-jit --enable-utf > build.log 2>&1 || (cat build.log && exit 1); make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1); sudo PATH=$PATH make install > build.log 2>&1 || (cat build.log && exit 1); cd ..; fi + - if [ -n "$OPENSSL_VER" ]; then tar zxf download-cache/openssl-$OPENSSL_VER.tar.gz; cd openssl-$OPENSSL_VER/; patch -p1 < ../../openresty/patches/openssl-$OPENSSL_PATCH_VER-sess_set_get_cb_yield.patch; ./config shared enable-ssl3 enable-ssl3-method -g --prefix=$OPENSSL_PREFIX --libdir=lib -DPURIFY > build.log 2>&1 || (cat build.log && exit 1); make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1); sudo make PATH=$PATH install_sw > build.log 2>&1 || (cat build.log && exit 1); cd ..; fi + - if [ -n "$BORINGSSL" ]; then sudo rm -fr /usr/local/openresty/openssl3/ && sudo mkdir -p /usr/local/openresty/openssl3 && sudo tar -C /usr/local/openresty/openssl3 -xf boringssl-20230902-x64-focal.tar.gz --strip-components=1; fi + - export NGX_BUILD_CC=$CC + - sh util/build-without-ssl.sh $NGINX_VERSION > build.log 2>&1 || (cat build.log && exit 1) + - sh util/build-with-dd.sh $NGINX_VERSION > build.log 2>&1 || (cat build.log && exit 1) + - rm -fr buildroot + - sh util/build.sh $NGINX_VERSION > build.log 2>&1 || (cat build.log && exit 1) + - nginx -V + - python3 ./util/nc_server.py & + - ldd `which nginx`|grep -E 'luajit|ssl|pcre' + - export LD_PRELOAD=$PWD/mockeagain/mockeagain.so + - export LD_LIBRARY_PATH=$PWD/mockeagain:$LD_LIBRARY_PATH + - export TEST_NGINX_HTTP3_CRT=$PWD/t/cert/http3/http3.crt + - export TEST_NGINX_HTTP3_KEY=$PWD/t/cert/http3/http3.key + - export TEST_NGINX_RESOLVER=8.8.4.4 + - dig +short myip.opendns.com @resolver1.opendns.com || exit 0 + - dig +short @$TEST_NGINX_RESOLVER openresty.org || exit 0 + - dig +short @$TEST_NGINX_RESOLVER agentzh.org || exit 0 + - /usr/bin/env perl $(command -v prove) -I. -Itest-nginx/inc -Itest-nginx/lib -r t/ diff --git a/Changes b/Changes deleted file mode 100644 index 703f73ded4..0000000000 --- a/Changes +++ /dev/null @@ -1,51 +0,0 @@ -0.2.0 - 5 July 2011 -* now we support ngx.var[1], ngx.var[2], and etc to refer to the nginx regex capturing variables \$1, \$2, and etc in Lua. this resolved github issue #43. thanks Tobia Conforto for reporting it. - -* now we use the same value overriding mechanism as ngx_rewrite's set command for ngx.var.VAR = new_value. Assigning values to special variables like $limit_rate and $args should now work; also writing to built-in variables that are not changeable (like $arg_PARAMETER) will result in a 500 error page, as expected, now. thanks Richard Kearsley for reporting it. - -* fixed the lua_code_cache off warning when the lua_code_cache is explicitly on. thanks Feng Xingguo. - -* applied the patch from cyberty to add ngx.http_time() function to expose the nginx core function ngx_http_time to the Lua land. - -* fixed an issue on i386: we now use off_t consistently. mixing it with size_t on 32-bit systems can cause Bad Things. this fixed github issue #42. thanks moodydeath. - -* fixed an issue on i386: fixed a formatter mismatch issue in ngx_http_echo_adjust_subrequest. thanks Wang Bin. This caused incorrect subrequest Content-Length header when a body is specified. - -* now in the subrequest capturing processor, we worked around an issue in ngx_http_static_module that when it issues 301 redirect for directory access w/o a trailing slash, it does not inject r->headers_out.location into the r->headers_out.headers list. thanks moodydeath for reporting it in the discussion of github issue #41. - -* fixed a bug in ngx.location.capture() and ngx.location.capture_multi() that we could not capture locations with internal redirections in them. thanks moodydeath for reporting it in github issue #41. - -* fixed redundant last chunk issue for ngx.exec() invocation at rewrite and access phases: we should quit the current core_run_phases cycle; this also fixed github issue #40: 2 Subrequest calls when using access_by_lua, ngx.exec and echo_location. - -* fixed ngx.exit(status) where status >= 200 and status < 300 for access_by_lua* and rewrite_by_lua*: it should quit the whole request altegother and skip all those subsequent phase handlers (if any). thanks moodydeath for reporting it. - -* fixed github issue #39: setting differnt response headers in Lua with common prefix might interfere with each other. thanks moodydeath. - -* fixed GitHub issue #38: request headers did not forward to subrequests when the "method" or "body" option is explicitly specified by a non-nil value for ngx.location.capture(). thanks Richard Kearsley. - -* fixed a bug in output header set; we should always set the header->hash to 1. thanks moodydeath for reporting it. - -* fixed spots that trigger the "variable set but not used" warning issued by gcc 4.6.0. - -* now we turn the ngx.req.header table into an ngx.req.get_headers() function; we also added ngx.req.set_header(name, value) and ngx.req.clear_header(name). thanks moodydeath. - -* now we make ngx_devel_kit (NDK) optional. thanks Kirill A. Korinskiy. - -* removed a duplicate definition of the ngx_str_set macro caught by ctags; also fixed a warning thrown by gcc -O3 on Mac OS X 10.6. - -* added patch to use PCRE related Lua extensions in ngx_lua (chaoslawful) - -* now we change the way we process HTTP 1.0 requests by automatically buffering all the user outputs generated by ngx.print()/ngx.say() calls, which is much more natural than the old broken way. - -* fixed the "ngx.exec() after ngx.location.capture() hanging" bug for rewrite_by_lua* and access_by_lua* as well. thanks Wendal Chen. - -* applied a patch from moodydeath to introduce the "ngx.is_subrequest" attribute. - -* now we encourage use of the client_body_in_single_buffer directive instead of big client_body_buffer_size when lua_need_request_body is turned on. - -* fixed the config script and added extra linking options needed by LuaJIT in 64-bit Mac OS X. - -* fixed the zero size alert caused by ngx.print("") in Lua. - -* now we always allocate r->request_body for subrequests when the method option is specified for ngx.location.capture*. this prevents accidental inheritance of parent request's request body when client_body_buffer_size < client_max_body_size. - diff --git a/README b/README deleted file mode 100644 index 36611d94aa..0000000000 --- a/README +++ /dev/null @@ -1,4543 +0,0 @@ -Name - ngx_lua - Embed the power of Lua into Nginx - - *This module is not distributed with the Nginx source.* See the - installation instructions. - -Status - This module is under active development and is production ready. - -Version - This document describes ngx_lua v0.5.0rc16 - () released on 28 - February 2012. - -Synopsis - # set search paths for pure Lua external libraries (';;' is the default path): - lua_package_path '/foo/bar/?.lua;/blah/?.lua;;'; - - # set search paths for Lua external libraries written in C (can also use ';;'): - lua_package_cpath '/bar/baz/?.so;/blah/blah/?.so;;'; - - server { - location /inline_concat { - # MIME type determined by default_type: - default_type 'text/plain'; - - set $a "hello"; - set $b "world"; - # inline lua script - set_by_lua $res "return ngx.arg[1]..ngx.arg[2]" $a $b; - echo $res; - } - - location /rel_file_concat { - set $a "foo"; - set $b "bar"; - # script path relative to nginx prefix - # $ngx_prefix/conf/concat.lua contents: - # - # return ngx.arg[1]..ngx.arg[2] - # - set_by_lua_file $res conf/concat.lua $a $b; - echo $res; - } - - location /abs_file_concat { - set $a "fee"; - set $b "baz"; - # absolute script path not modified - set_by_lua_file $res /usr/nginx/conf/concat.lua $a $b; - echo $res; - } - - location /lua_content { - # MIME type determined by default_type: - default_type 'text/plain'; - - content_by_lua "ngx.say('Hello,world!')"; - } - - location /nginx_var { - # MIME type determined by default_type: - default_type 'text/plain'; - - # try access /nginx_var?a=hello,world - content_by_lua "ngx.print(ngx.var['arg_a'], '\\n')"; - } - - location /request_body { - # force reading request body (default off) - lua_need_request_body on; - client_max_body_size 50k; - client_body_buffer_size 50k; - - content_by_lua 'ngx.print(ngx.var.request_body)'; - } - - # transparent non-blocking I/O in Lua via subrequests - location /lua { - # MIME type determined by default_type: - default_type 'text/plain'; - - content_by_lua ' - local res = ngx.location.capture("/some_other_location") - if res.status == 200 then - ngx.print(res.body) - end'; - } - - # GET /recur?num=5 - location /recur { - # MIME type determined by default_type: - default_type 'text/plain'; - - content_by_lua ' - local num = tonumber(ngx.var.arg_num) or 0 - - if num > 50 then - ngx.say("num too big") - return - end - - ngx.say("num is: ", num) - - if num > 0 then - res = ngx.location.capture("/recur?num=" .. tostring(num - 1)) - ngx.print("status=", res.status, " ") - ngx.print("body=", res.body) - else - ngx.say("end") - end - '; - } - - location /foo { - rewrite_by_lua ' - res = ngx.location.capture("/memc", - { args = { cmd = 'incr', key = ngx.var.uri } } - ) - '; - - proxy_pass http://blah.blah.com; - } - - location /blah { - access_by_lua ' - local res = ngx.location.capture("/auth") - - if res.status == ngx.HTTP_OK then - return - end - - if res.status == ngx.HTTP_FORBIDDEN then - ngx.exit(res.status) - end - - ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) - '; - - # proxy_pass/fastcgi_pass/postgres_pass/... - } - - location /mixed { - rewrite_by_lua_file /path/to/rewrite.lua; - access_by_lua_file /path/to/access.lua; - content_by_lua_file /path/to/content.lua; - } - - # use nginx var in code path - # WARN: contents in nginx var must be carefully filtered, - # otherwise there'll be great security risk! - location ~ ^/app/(.+) { - content_by_lua_file /path/to/lua/app/root/$1.lua; - } - - location / { - lua_need_request_body on; - - client_max_body_size 100k; - client_body_buffer_size 100k; - - access_by_lua ' - -- check the client IP addr is in our black list - if ngx.var.remote_addr == "132.5.72.3" then - ngx.exit(ngx.HTTP_FORBIDDEN) - end - - -- check if the request body contains bad words - if ngx.var.request_body and - string.match(ngx.var.request_body, "fsck") - then - return ngx.redirect("/terms_of_use.html") - end - - -- tests passed - '; - - # proxy_pass/fastcgi_pass/etc settings - } - } - -Description - This module embeds Lua, via the standard interpreter or LuaJIT, into - Nginx and by leveraging Nginx subrequests, allows the integration of the - powerful Lua threads ( Lua coroutines) into the Nginx event model. - - Unlike Apache's mod_lua - () and Lighttpd's - mod_magnet (), Lua - code executed using this module can be *100% non-blocking* on network - traffic as long as either of the ngx.location.capture or - ngx.location.capture_multi interfaces are used to handle requests to - upstream services such as mysql, postgresql, memcached, redis, or - upstream http web services. (see [[HttpDrizzleModule]], ngx_postgres - (), [[HttpMemcModule]], - [[HttpRedis2Module]] and [[HttpProxyModule]] modules for details). - - The Lua interpreter or LuaJIT instance is shared across all the requests - in a single nginx worker process but request contexts are segregated - using lightweight Lua coroutines. Loaded Lua modules persist at the - nginx worker process level resulting in a small memory footprint even - when under heavy loads. - -Directives - lua_code_cache - syntax: *lua_code_cache on | off* - - default: *lua_code_cache on* - - context: *main, server, location, location if* - - Enables or disables the Lua code cache for set_by_lua_file, - content_by_lua_file, rewrite_by_lua_file, and access_by_lua_file, and - also force Lua module reloading on a per-request basis. - - The Lua files referenced in set_by_lua_file, content_by_lua_file, - access_by_lua_file, and rewrite_by_lua_file will not be cached and the - Lua "package.loaded" table will be cleared at the entry point of every - request (such that Lua modules will not be cached either). With this in - place, developers can adopt an edit and refresh approach. - - Please note however, that Lua code inlined into nginx.conf such as those - specified by set_by_lua, content_by_lua, access_by_lua, and - rewrite_by_lua will *always* be cached because only the Nginx config - file parser can correctly parse the "nginx.conf" file and the only ways - to to reload the config file are to send a "HUP" signal or to restart - Nginx. - - The ngx_lua module does not currently support the "stat" mode available - with the Apache "mod_lua" module but this is planned for implementation - in the future. - - Disabling the Lua code cache is strongly discouraged for production use - and should only be used during development as it has a significant - negative impact on overall performance. In addition, race conditions - when reloading Lua modules are common for concurrent requests when the - code cache is disabled. - - lua_regex_cache_max_entries - syntax: *lua_regex_cache_max_entries * - - default: *lua_regex_cache_max_entries 1024* - - context: *http* - - Specifies the maximum number of entries allowed in the worker process - level compiled regex cache. - - The regular expressions used in ngx.re.match, ngx.re.gmatch, ngx.re.sub, - and ngx.re.gsub will be cached within this cache if the regex option "o" - (i.e., compile-once flag) is specified. - - The default number of entries allowed is 1024 and when this limit is - reached, new regexes will not be cached (as if the "o" option was not - specified) and there will be one, and only one, warning in the - "error.log" file: - - 2011/08/27 23:18:26 [warn] 31997#0: *1 lua exceeding regex cache max entries (1024), ... - - Do not activate the "o" option for regexes (and/or "replace" string - arguments for ngx.re.sub and ngx.re.gsub) that are generated *on the - fly* and give rise to infinite variations to avoid hitting the specified - limit. - - lua_package_path - syntax: *lua_package_path * - - default: *The content of LUA_PATH environ variable or Lua's compiled-in - defaults.* - - context: *main* - - Sets the Lua module search path used by scripts specified by set_by_lua, - content_by_lua and others. The path string is in standard Lua path form, - and ";;" can be used to stand for the original path. - - lua_package_cpath - syntax: *lua_package_cpath * - - default: *The content of LUA_CPATH environ variable or Lua's compiled-in - defaults.* - - context: *main* - - Sets the Lua C-module search path used by scripts specified by - set_by_lua, content_by_lua and others. The cpath string is in standard - Lua cpath form, and ";;" can be used to stand for the original cpath. - - set_by_lua - syntax: *set_by_lua $res [$arg1 $arg2 ...]* - - context: *main, server, location, server if, location if* - - phase: *rewrite* - - Executes code specified in "" with optional input - arguments "$arg1 $arg2 ...", and returns string output to $res. The code - in "" can make API calls and can retrieve input - arguments from the "ngx.arg" table (index starts from 1 and increases - sequentially). - - This directive is designed to execute short, fast running code blocks as - the Nginx event loop is blocked during code execution. Time consuming - code sequences should therefore be avoided. - - Note that I/O operations such as ngx.say, ngx.exec, echo and similar are - not permitted within the context of this directive. - - In addition, note that this directive can only output a value to a - single Nginx variable at a time. However, a workaround is possible using - the ngx.var.VARIABLE interface. - - location /foo { - set $diff ''; # we have to predefine the $diff variable here - - set_by_lua $sum ' - local a = 32 - local b = 56 - - ngx.var.diff = a - b; -- write to $diff directly - return a + b; -- return the $sum value normally - '; - - echo "sum = $sum, diff = $diff"; - } - - This directive can be freely mixed with all directives of the - [[HttpRewriteModule]], [[HttpSetMiscModule]], and [[HttpArrayVarModule]] - modules. All of these directives will run in the same order as they - appear in the config file. - - set $foo 32; - set_by_lua $bar 'tonumber(ngx.var.foo) + 1'; - set $baz "bar: $bar"; # $baz == "bar: 33" - - This directive requires the ngx_devel_kit - () module. - - set_by_lua_file - syntax: *set_by_lua_file $res [$arg1 $arg2 - ...]* - - context: *main, server, location, server if, location if* - - phase: *rewrite* - - Equivalent to set_by_lua, except that the file specified by - "" contains the lua code to be executed. - - When the Lua code cache is on (default state), the user code is loaded - once at the first request and cached and the Nginx config must be - reloaded each time the Lua source file is modified. The Lua code cache - can be temporarily disabled during development by switching - lua_code_cache "off" in "nginx.conf" to avoid reloading Nginx. - - This directive requires the ngx_devel_kit - () module. - - content_by_lua - syntax: *content_by_lua * - - context: *location, location if* - - phase: *content* - - Acts as a "content handler" and executes lua code string specified in - "" for every request. The lua code may make API calls - and is executed as a new spawned coroutine in an independent global - environment (i.e. a sandbox). - - Do not use this directive and other content handler directives in the - same location. For example, this directive and the proxy_pass directive - should not be used in the same location. - - content_by_lua_file - syntax: *content_by_lua_file * - - context: *location, location if* - - phase: *content* - - Equivalent to content_by_lua, except that the file specified by - "" contains the lua code to be executed. - - Nginx variables can be used in the "" string to - provide flexibility. This however carries some risks and is not - ordinarily recommended. - - When the Lua code cache is on (default state), the user code is loaded - once at the first request and cached and the Nginx config must be - reloaded each time the Lua source file is modified. The Lua code cache - can be temporarily disabled during development by switching - lua_code_cache "off" in "nginx.conf" to avoid reloading Nginx. - - rewrite_by_lua - syntax: *rewrite_by_lua * - - context: *http, server, location, location if* - - phase: *rewrite tail* - - Acts as a rewrite phase handler and executes Lua code string specified - in "" for every request. The Lua code may make API calls - and is executed as a new spawned coroutine in an independent global - environment (i.e. a sandbox). - - Note that this handler always runs *after* the standard - [[HttpRewriteModule]]. So the following will work as expected: - - location /foo { - set $a 12; # create and initialize $a - set $b ""; # create and initialize $b - rewrite_by_lua 'ngx.var.b = tonumber(ngx.var.a) + 1'; - echo "res = $b"; - } - - because "set $a 12" and "set $b """ run *before* rewrite_by_lua. - - On the other hand, the following will not work as expected: - - ? location /foo { - ? set $a 12; # create and initialize $a - ? set $b ''; # create and initialize $b - ? rewrite_by_lua 'ngx.var.b = tonumber(ngx.var.a) + 1'; - ? if ($b = '13') { - ? rewrite ^ /bar redirect; - ? break; - ? } - ? - ? echo "res = $b"; - ? } - - because "if" runs *before* rewrite_by_lua even if it is put after - rewrite_by_lua in the config. - - The right way of doing this is as follows: - - location /foo { - set $a 12; # create and initialize $a - set $b ''; # create and initialize $b - rewrite_by_lua ' - ngx.var.b = tonumber(ngx.var.a) + 1 - if tonumber(ngx.var.b) == 13 then - return ngx.redirect("/bar"); - end - '; - - echo "res = $b"; - } - - Note that the ngx_eval () - module can be approximated using rewrite_by_lua. For example, - - location / { - eval $res { - proxy_pass http://foo.com/check-spam; - } - - if ($res = 'spam') { - rewrite ^ /terms-of-use.html redirect; - } - - fastcgi_pass ...; - } - - can be implemented in "ngx_lua" as: - - location = /check-spam { - internal; - proxy_pass http://foo.com/check-spam; - } - - location / { - rewrite_by_lua ' - local res = ngx.location.capture("/check-spam") - if res.body == "spam" then - ngx.redirect("/terms-of-use.html") - end - '; - - fastcgi_pass ...; - } - - Just as any other rewrite phase handlers, rewrite_by_lua also runs in - subrequests. - - Note that when calling "ngx.exit(ngx.OK)" within a rewrite_by_lua - handler, the nginx request processing control flow will still continue - to the content handler. To terminate the current request from within a - rewrite_by_lua handler, calling ngx.exit with status >= 200 - ("ngx.HTTP_OK") and status < 300 ("ngx.HTTP_SPECIAL_RESPONSE") for - successful quits and "ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)" (or its - friends) for failures. - - If the [[HttpRewriteModule]]'s rewrite directive is used to change the - URI and initiate location re-lookups (internal redirections), then any - rewrite_by_lua or rewrite_by_lua_file code sequences within the current - location will not be executed. For example, - - location /foo { - rewrite ^ /bar; - rewrite_by_lua 'ngx.exit(503)'; - } - location /bar { - ... - } - - Here the Lua code "ngx.exit(503)" will never run. This will be the case - if "rewrite ^ /bar last" is used as this will similarly initiate an - internal redirection. If the "break" modifier is used instead, there - will be no internal rediction and the rewrite_by_lua code will be - executed. - - rewrite_by_lua_file - syntax: *rewrite_by_lua_file * - - context: *http, server, location, location if* - - phase: *rewrite tail* - - Equivalent to rewrite_by_lua, except that the file specified by - "" contains the Lua code to be executed. - - Nginx variables can be used in the "" string to - provide flexibility. This however carries some risks and is not - ordinarily recommended. - - When the Lua code cache is on (default state), the user code is loaded - once at the first request and cached and the Nginx config must be - reloaded each time the Lua source file is modified. The Lua code cache - can be temporarily disabled during development by switching - lua_code_cache "off" in "nginx.conf" to avoid reloading Nginx. - - access_by_lua - syntax: *access_by_lua * - - context: *http, server, location, location if* - - phase: *access tail* - - Acts as an access phase handler and executes lua code string specified - in "" for every request. The Lua code may make API calls - and is executed as a new spawned coroutine in an independent global - environment (i.e. a sandbox). - - Note that this handler always runs *after* the standard - [[HttpAccessModule]]. So the following will work as expected: - - location / { - deny 192.168.1.1; - allow 192.168.1.0/24; - allow 10.1.1.0/16; - deny all; - - access_by_lua ' - local res = ngx.location.capture("/mysql", { ... }) - ... - '; - - # proxy_pass/fastcgi_pass/... - } - - That is, if a client IP address is in the blacklist, it will be denied - before the MySQL query for more complex authentication is executed by - access_by_lua. - - Note that the ngx_auth_request - () module can be - approximated using access_by_lua: - - location / { - auth_request /auth; - - # proxy_pass/fastcgi_pass/postgres_pass/... - } - - can be implemented in "ngx_lua" as: - - location / { - access_by_lua ' - local res = ngx.location.capture("/auth") - - if res.status == ngx.HTTP_OK then - return - end - - if res.status == ngx.HTTP_FORBIDDEN then - ngx.exit(res.status) - end - - ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR) - '; - - # proxy_pass/fastcgi_pass/postgres_pass/... - } - - As with other access phase handlers, access_by_lua will *not* run in - subrequests. - - Note that when calling "ngx.exit(ngx.OK)" within a access_by_lua - handler, the nginx request processing control flow will still continue - to the content handler. To terminate the current request from within a - access_by_lua handler, calling ngx.exit with status >= 200 - ("ngx.HTTP_OK") and status < 300 ("ngx.HTTP_SPECIAL_RESPONSE") for - successful quits and "ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)" (or its - friends) for failures. - - access_by_lua_file - syntax: *access_by_lua_file * - - context: *http, server, location, location if* - - phase: *access tail* - - Equivalent to access_by_lua, except that the file specified by - "" contains the Lua code to be executed. - - Nginx variables can be used in the "" string to - provide flexibility. This however carries some risks and is not - ordinarily recommended. - - When the Lua code cache is on (default state), the user code is loaded - once at the first request and cached and the Nginx config must be - reloaded each time the Lua source file is modified. The Lua code cache - can be temporarily disabled during development by switching - lua_code_cache "off" in "nginx.conf" to avoid repeatedly reloading - Nginx. - - header_filter_by_lua - syntax: *header_filter_by_lua * - - context: *http, server, location, location if* - - phase: *output-header-filter* - - Uses Lua code specified in "" to define an output header - filter. Note that the following API functions are currently disabled - within this context: - - * Output API functions (e.g., ngx.say and ngx.send_headers) - - * Control API functions (e.g., ngx.exit) - - * Subrequest API functions (e.g., ngx.location.capture and - ngx.location.capture_multi) - - Here is an example of overriding a response header (or adding one if - absent) in our Lua header filter: - - location / { - proxy_pass http://mybackend; - header_filter_by_lua 'ngx.header.Foo = "blah"'; - } - - This directive was first introduced in the "v0.2.1rc20" release. - - header_filter_by_lua_file - syntax: *header_filter_by_lua_file * - - context: *http, server, location, location if* - - phase: *output-header-filter* - - Equivalent to header_filter_by_lua, except that the file specified by - "" contains the lua code to be executed. - - This directive was first introduced in the "v0.2.1rc20" release. - - lua_need_request_body - syntax: *lua_need_request_body * - - default: *off* - - context: *main | server | location* - - phase: *depends on usage* - - Determines whether to force the request body data to be read before - running rewrite/access/access_by_lua* or not. The Nginx core does not - read the client request body by default and if request body data is - required, then this directive should be turned "on" or the - ngx.req.read_body function should be called within the Lua code. - - To read the request body data within the $request_body variable, - client_body_buffer_size must have the same value as - client_max_body_size. Because when the content length exceeds - client_body_buffer_size but less than client_max_body_size, Nginx will - automatically buffer the data into a temporary file on the disk, which - will lead to empty value in the $request_body variable. - - If the current location includes rewrite_by_lua or rewrite_by_lua_file - directives, then the request body will be read just before the - rewrite_by_lua or rewrite_by_lua_file code is run (and also at the - "rewrite" phase). Similarly, if only content_by_lua is specified, the - request body will not be read until the content handler's Lua code is - about to run (i.e., the request body will be read during the content - phase). - - It is recommended however, to use the ngx.req.read_body and - ngx.req.discard_body functions for finer control over the request body - reading process instead. - - This also applies to access_by_lua and access_by_lua_file. - - lua_shared_dict - syntax: *lua_shared_dict * - - default: *no* - - context: *http* - - phase: *depends on usage* - - Declares a shared memory zone, "", to serve as storage for the - shm-based Lua dictionary "ngx.shared.". - - The "" argument accepts size units such as "k" and "m": - - http { - lua_shared_dict dogs 10m; - ... - } - - See ngx.shared.DICT for details. - - This directive was first introduced in the "v0.3.1rc22" release. - - lua_socket_connect_timeout - syntax: *lua_socket_connect_timeout