pax_global_header00006660000000000000000000000064147423672260014527gustar00rootroot0000000000000052 comment=cb7264da6d94c259c4ad01ee5c61b5f65e3c7eb4 lua-resty-core-0.1.31/000077500000000000000000000000001474236722600144645ustar00rootroot00000000000000lua-resty-core-0.1.31/.gitattributes000066400000000000000000000000331474236722600173530ustar00rootroot00000000000000*.t linguist-language=Text lua-resty-core-0.1.31/.github/000077500000000000000000000000001474236722600160245ustar00rootroot00000000000000lua-resty-core-0.1.31/.github/ISSUE_TEMPLATE.md000066400000000000000000000031201474236722600205250ustar00rootroot00000000000000This place is for bug reports and development discussions only. For general questions and discussions, please join the openresty-en mailing list instead: https://groups.google.com/group/openresty-en. If you want to use Chinese, please join the openresty (Chinese) mailing list instead: https://groups.google.com/group/openresty. Do not use Chinese in this place. Before you open a new issue, please search the internet and make sure it is not duplicate. 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(via `openresty -V` or `nginx -V`), and the `lua-resty-core` version(via `resty -e 'print(require("resty.core").version)'`), and your operating system version(via `uname -a`). - [ ] **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. Thanks for your cooperation. lua-resty-core-0.1.31/.github/PULL_REQUEST_TEMPLATE.md000066400000000000000000000001621474236722600216240ustar00rootroot00000000000000I hereby granted the copyright of the changes in this pull request to the authors of this lua-resty-core project. lua-resty-core-0.1.31/.github/workflows/000077500000000000000000000000001474236722600200615ustar00rootroot00000000000000lua-resty-core-0.1.31/.github/workflows/semantic-pull-request.yml000066400000000000000000000016161474236722600250530ustar00rootroot00000000000000name: "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 lua-resty-core-0.1.31/.gitignore000066400000000000000000000001131474236722600164470ustar00rootroot00000000000000*.swp *.swo *~ go t/servroot* reindex nginx ctags tags a.lua mockeagain.so lua-resty-core-0.1.31/.luacheckrc000066400000000000000000000001511474236722600165660ustar00rootroot00000000000000std = 'ngx_lua' globals = { 'ngx', 'ndk' } unused_args = false read_globals = { "coroutine._yield" } lua-resty-core-0.1.31/.travis.yml000066400000000000000000000146011474236722600165770ustar00rootroot00000000000000--- sudo: required dist: focal branches: only: - "master" os: linux language: c compiler: - gcc addons: apt: packages: - axel - luarocks - daemonize cache: directories: - download-cache env: global: - JOBS=2 - 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 - LUA_CMODULE_DIR=/lib - PCRE_VER=8.45 - PCRE2_VER=10.37 - PCRE_PREFIX=/opt/pcre - PCRE2_PREFIX=/opt/pcre2 - PCRE_LIB=$PCRE_PREFIX/lib - PCRE2_LIB=$PCRE2_PREFIX/lib - PCRE_INC=$PCRE_PREFIX/include - PCRE2_INC=$PCRE2_PREFIX/include - OPENSSL_PREFIX=/opt/ssl - OPENSSL_LIB=$OPENSSL_PREFIX/lib - OPENSSL_INC=$OPENSSL_PREFIX/include - LD_LIBRARY_PATH=$LUAJIT_LIB:$LD_LIBRARY_PATH - TEST_NGINX_SLEEP=0.005 - TEST_NGINX_RANDOMIZE=1 - LUACHECK_VER=0.21.1 matrix: - NGINX_VERSION=1.27.1 OPENSSL_VER=1.1.1w OPENSSL_PATCH_VER=1.1.1f USE_PCRE2=Y - NGINX_VERSION=1.25.3 OPENSSL_VER=1.1.1w OPENSSL_PATCH_VER=1.1.1f services: - memcache before_install: - sudo luarocks install luacheck $LUACHECK_VER - luacheck --globals coroutine -q . - '! grep -n -P ''(?<=.{80}).+'' --color `find . -name ''*.lua''` || (echo "ERROR: Found Lua source lines exceeding 80 columns." > /dev/stderr; exit 1)' - '! grep -n -P ''\t+'' --color `find . -name ''*.lua''` || (echo "ERROR: Cannot use tabs." > /dev/stderr; exit 1)' - cpanm --sudo --notest Test::Nginx IPC::Run > build.log 2>&1 || (cat build.log && exit 1) install: - if [ ! -d download-cache ]; then mkdir download-cache; fi - if [ ! -f download-cache/openssl-$OPENSSL_VER.tar.gz ]; then 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 - if [ "$USE_PCRE2" != "Y" ] && [ ! -f download-cache/pcre-$PCRE_VER.tar.gz ]; then wget -P download-cache http://ftp.cs.stanford.edu/pub/exim/pcre/pcre-$PCRE_VER.tar.gz; fi - if [ "$USE_PCRE2" = "Y" ] && [ ! -f download-cache/pcre2-$PCRE2_VER.tar.gz ]; then wget -P download-cache https://downloads.sourceforge.net/project/pcre/pcre2/${PCRE2_VER}/pcre2-${PCRE2_VER}.tar.gz; fi - git clone https://github.com/openresty/openresty.git ../openresty - git clone https://github.com/openresty/openresty-devel-utils.git - git clone https://github.com/simpl/ngx_devel_kit.git ../ndk-nginx-module - git clone https://github.com/openresty/lua-nginx-module.git ../lua-nginx-module - git clone https://github.com/openresty/no-pool-nginx.git ../no-pool-nginx - git clone https://github.com/openresty/echo-nginx-module.git ../echo-nginx-module - git clone https://github.com/openresty/lua-resty-lrucache.git - git clone https://github.com/openresty/headers-more-nginx-module.git ../headers-more-nginx-module - git clone -b v2.1-agentzh https://github.com/openresty/luajit2.git luajit2 - git clone https://github.com/openresty/set-misc-nginx-module.git ../set-misc-nginx-module - git clone https://github.com/openresty/mockeagain.git - git clone https://github.com/openresty/test-nginx.git - git clone https://github.com/openresty/stream-lua-nginx-module.git ../stream-lua-nginx-module script: - cd luajit2/ - make -j$JOBS CCDEBUG=-g Q= PREFIX=$LUAJIT_PREFIX CC=$CC XCFLAGS='-DLUA_USE_APICHECK -DLUA_USE_ASSERT -msse4.2 -O1 -DLUAJIT_SECURITY_STRID=0 -DLUAJIT_SECURITY_STRHASH=0 -DLUAJIT_SECURITY_PRNG=0 -DLUAJIT_SECURITY_MCODE=0 -DLUAJIT_TEST_FIXED_ORDER' > 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 .. - cd lua-resty-lrucache && sudo make DESTDIR=$LUAJIT_PREFIX LUA_LIB_DIR=/share/lua/5.1 install && cd .. - tar zxf download-cache/openssl-$OPENSSL_VER.tar.gz - cd openssl-$OPENSSL_VER/ - if [ -n "$OPENSSL_PATCH_VER" ]; then patch -p1 < ../../openresty/patches/openssl-$OPENSSL_PATCH_VER-sess_set_get_cb_yield.patch; fi - ./config no-threads shared enable-ssl3 enable-ssl3-method -g --prefix=$OPENSSL_PREFIX -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 ../mockeagain/ && make CC=$CC -j$JOBS && cd .. - if [ "$USE_PCRE2" != "Y" ]; then tar zxf download-cache/pcre-$PCRE_VER.tar.gz; cd pcre-$PCRE_VER/; ./configure --prefix=$PCRE_PREFIX --enable-jit --enable-utf --enable-unicode-properties > 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 [ "$USE_PCRE2" = "Y" ]; 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 - export PATH=$PWD/work/nginx/sbin:$PWD/openresty-devel-utils:$PATH - export LD_PRELOAD=$PWD/mockeagain/mockeagain.so - export LD_LIBRARY_PATH=$PWD/mockeagain:$LD_LIBRARY_PATH - export TEST_NGINX_RESOLVER=8.8.4.4 - export NGX_BUILD_CC=$CC - export add_http3_module=--with-http_v3_module - export disable_pcre2=--without-pcre2 - answer=`util/ver-ge "$NGINX_VERSION" 1.25.1` - if [ "$OPENSSL_VER" = "1.1.0l" ] || [ "$answer" = "N" ]; then add_http3_module=""; fi - if [ "$answer" = "N" ] || [ "$USE_PCRE2" = "Y" ]; then disable_pcre2=""; fi - if [ "$USE_PCRE2" = "Y" ]; then PCRE_INC=$PCRE2_INC; PCRE_LIB=$PCRE2_LIB; fi - ngx-build $NGINX_VERSION $disable_pcre2 $add_http3_module --with-http_v2_module --with-http_realip_module --with-http_ssl_module --with-pcre-jit --with-cc-opt="-I$OPENSSL_INC -I$PCRE_INC" --with-ld-opt="-L$OPENSSL_LIB -Wl,-rpath,$OPENSSL_LIB -L$PCRE_LIB -Wl,-rpath,$PCRE_LIB" --add-module=../ndk-nginx-module --add-module=../echo-nginx-module --add-module=../set-misc-nginx-module --add-module=../headers-more-nginx-module --add-module=../lua-nginx-module --with-debug --with-stream_ssl_module --with-stream --with-ipv6 --add-module=../stream-lua-nginx-module > build.log 2>&1 || (cat build.log && exit 1) - nginx -V - ldd `which nginx`|grep -E 'luajit|ssl|pcre' - prove -I. -Itest-nginx/lib -j$JOBS -r t lua-resty-core-0.1.31/Makefile000066400000000000000000000021521474236722600161240ustar00rootroot00000000000000OPENRESTY_PREFIX=/usr/local/openresty #LUA_VERSION := 5.1 PREFIX ?= /usr/local LUA_INCLUDE_DIR ?= $(PREFIX)/include LUA_LIB_DIR ?= $(PREFIX)/lib/lua/$(LUA_VERSION) INSTALL ?= install .PHONY: all test install all: ; install: all $(INSTALL) -d $(DESTDIR)$(LUA_LIB_DIR)/resty/core/ $(INSTALL) -d $(DESTDIR)$(LUA_LIB_DIR)/ngx/ $(INSTALL) -d $(DESTDIR)$(LUA_LIB_DIR)/ngx/ssl $(INSTALL) lib/resty/*.lua $(DESTDIR)$(LUA_LIB_DIR)/resty/ $(INSTALL) lib/resty/core/*.lua $(DESTDIR)$(LUA_LIB_DIR)/resty/core/ $(INSTALL) lib/ngx/*.lua $(DESTDIR)$(LUA_LIB_DIR)/ngx/ $(INSTALL) lib/ngx/ssl/*.lua $(DESTDIR)$(LUA_LIB_DIR)/ngx/ssl/ ifeq ($(LUA_LIB_DIR),/usr/local/lib/lua/) @echo @printf "\033[33mPLEASE NOTE: \033[0m\n" @printf "\033[33mThe necessary lua_package_path directive needs to be added to nginx.conf\033[0m\n" @printf "\033[33min the http context, because \"/usr/local/lib/lua/\" is not in LuaJIT’s default search path.\033[0m\n" @printf "\033[33mRefer to the Installation section of README.markdown.\033[0m\n" endif test: all PATH=$(OPENRESTY_PREFIX)/nginx/sbin:$$PATH prove -I../test-nginx/lib -r t lua-resty-core-0.1.31/README.markdown000066400000000000000000000410751474236722600171740ustar00rootroot00000000000000Name ==== lua-resty-core - New FFI-based Lua API for ngx_http_lua_module and/or ngx_stream_lua_module Table of Contents ================= * [Name](#name) * [Status](#status) * [Synopsis](#synopsis) * [Description](#description) * [Prerequisites](#prerequisites) * [Installation](#installation) * [API Implemented](#api-implemented) * [resty.core.hash](#restycorehash) * [resty.core.base64](#restycorebase64) * [resty.core.uri](#restycoreuri) * [resty.core.regex](#restycoreregex) * [resty.core.exit](#restycoreexit) * [resty.core.shdict](#restycoreshdict) * [resty.core.var](#restycorevar) * [resty.core.ctx](#restycorectx) * [get_ctx_table](#get_ctx_table) * [resty.core.request](#restycorerequest) * [resty.core.response](#restycoreresponse) * [resty.core.misc](#restycoremisc) * [resty.core.time](#restycoretime) * [resty.core.worker](#restycoreworker) * [resty.core.phase](#restycorephase) * [resty.core.ndk](#restycorendk) * [resty.core.socket](#restycoresocket) * [resty.core.param](#restycoreparam) * [ngx.semaphore](#ngxsemaphore) * [ngx.balancer](#ngxbalancer) * [ngx.ssl](#ngxssl) * [ngx.ssl.clienthello](#ngxsslclienthello) * [ngx.ssl.session](#ngxsslsession) * [ngx.re](#ngxre) * [ngx.resp](#ngxresp) * [ngx.pipe](#ngxpipe) * [ngx.process](#ngxprocess) * [ngx.errlog](#ngxerrlog) * [ngx.base64](#ngxbase64) * [Caveat](#caveat) * [TODO](#todo) * [Author](#author) * [Copyright and License](#copyright-and-license) * [See Also](#see-also) Status ====== This library is production ready. Synopsis ======== This library is automatically loaded by default since OpenResty 1.15.8.1. This behavior can be disabled via the [lua_load_resty_core](https://github.com/openresty/lua-nginx-module#lua_load_resty_core) directive, but note that the use of this library is vividly recommended, as its FFI implementation is both faster, safer, and more complete than the Lua C API of the ngx_lua module. If you are using an older version of OpenResty, you must load this library like so: ```nginx # nginx.conf http { # you do NOT need to configure the following line when you # are using the OpenResty bundle 1.4.3.9+. lua_package_path "/path/to/lua-resty-core/lib/?.lua;;"; init_by_lua_block { require "resty.core" collectgarbage("collect") -- just to collect any garbage } ... } ``` Description =========== This pure Lua library reimplements part of the [ngx_lua](https://github.com/openresty/lua-nginx-module#readme) module's [Nginx API for Lua](https://github.com/openresty/lua-nginx-module#nginx-api-for-lua) with LuaJIT FFI and installs the new FFI-based Lua API into the ngx.* and ndk.* namespaces used by the ngx_lua module. In addition, this Lua library implements any significant new Lua APIs of the [ngx_lua](https://github.com/openresty/lua-nginx-module#readme) module as proper Lua modules, like [ngx.semaphore](#ngxsemaphore) and [ngx.balancer](#ngxbalancer). The FFI-based Lua API can work with LuaJIT's JIT compiler. ngx_lua's default API is based on the standard Lua C API, which will never be JIT compiled and the user Lua code is always interpreted (slowly). Support for the new [ngx_stream_lua_module](https://github.com/openresty/stream-lua-nginx-module) has also begun. This library is shipped with the OpenResty bundle by default. So you do not really need to worry about the dependencies and requirements. [Back to TOC](#table-of-contents) Prerequisites ============= **WARNING** This library is included with every OpenResty release. You should use the bundled version of this library in the particular OpenResty release you are using. Otherwise you may run into serious compatibility issues. * LuaJIT 2.1 (for now, it is the v2.1 git branch in the official luajit-2.0 git repository: http://luajit.org/download.html ) * [ngx_http_lua_module](https://github.com/openresty/lua-nginx-module) v0.10.25. * [ngx_stream_lua_module](https://github.com/openresty/stream-lua-nginx-module) v0.0.13. * [lua-resty-lrucache](https://github.com/openresty/lua-resty-lrucache) [Back to TOC](#table-of-contents) Installation ============ By default, LuaJIT will search Lua files in /usr/local/share/lua/5.1/. But `make install` will install this module to /usr/local/lib/lua. So you may find the error like this: ```text nginx: [alert] failed to load the 'resty.core' module ``` You can install this module with the following command to resolve the above problem. ```bash cd lua-resty-core sudo make install LUA_LIB_DIR=/usr/local/share/lua/5.1 ``` You can also change the installation directory to any other directory you like with the LUA_LIB_DIR argument. ```bash cd lua-resty-core sudo make install LUA_LIB_DIR=/opt/nginx/lualib ``` After that, you need to add the above directory to the LuaJIT search direcotries with `lua_package_path` nginx directive in the http context and stream context. ``` lua_package_path "/opt/nginx/lualib/?.lua;;"; ``` [Back to TOC](#table-of-contents) API Implemented =============== [Back to TOC](#table-of-contents) ## resty.core.hash * [ngx.md5](https://github.com/openresty/lua-nginx-module#ngxmd5) * [ngx.md5_bin](https://github.com/openresty/lua-nginx-module#ngxmd5_bin) * [ngx.sha1_bin](https://github.com/openresty/lua-nginx-module#ngxsha1_bin) [Back to TOC](#table-of-contents) ## resty.core.base64 * [ngx.encode_base64](https://github.com/openresty/lua-nginx-module#ngxencode_base64) * [ngx.decode_base64](https://github.com/openresty/lua-nginx-module#ngxdecode_base64) * [ngx.decode_base64mime](https://github.com/openresty/lua-nginx-module#ngxdecode_base64mime) [Back to TOC](#table-of-contents) ## resty.core.uri * [ngx.escape_uri](https://github.com/openresty/lua-nginx-module#ngxescape_uri) * [ngx.unescape_uri](https://github.com/openresty/lua-nginx-module#ngxunescape_uri) [Back to TOC](#table-of-contents) ## resty.core.regex * [ngx.re.match](https://github.com/openresty/lua-nginx-module#ngxrematch) * [ngx.re.gmatch](https://github.com/openresty/lua-nginx-module#ngxregmatch) * [ngx.re.find](https://github.com/openresty/lua-nginx-module#ngxrefind) * [ngx.re.sub](https://github.com/openresty/lua-nginx-module#ngxresub) * [ngx.re.gsub](https://github.com/openresty/lua-nginx-module#ngxregsub) [Back to TOC](#table-of-contents) ## resty.core.exit * [ngx.exit](https://github.com/openresty/lua-nginx-module#ngxexit) [Back to TOC](#table-of-contents) ## resty.core.shdict * [ngx.shared.DICT.get](https://github.com/openresty/lua-nginx-module#ngxshareddictget) * [ngx.shared.DICT.get_stale](https://github.com/openresty/lua-nginx-module#ngxshareddictget_stale) * [ngx.shared.DICT.incr](https://github.com/openresty/lua-nginx-module#ngxshareddictincr) * [ngx.shared.DICT.set](https://github.com/openresty/lua-nginx-module#ngxshareddictset) * [ngx.shared.DICT.safe_set](https://github.com/openresty/lua-nginx-module#ngxshareddictsafe_set) * [ngx.shared.DICT.add](https://github.com/openresty/lua-nginx-module#ngxshareddictadd) * [ngx.shared.DICT.safe_add](https://github.com/openresty/lua-nginx-module#ngxshareddictsafe_add) * [ngx.shared.DICT.replace](https://github.com/openresty/lua-nginx-module#ngxshareddictreplace) * [ngx.shared.DICT.delete](https://github.com/openresty/lua-nginx-module#ngxshareddictdelete) * [ngx.shared.DICT.ttl](https://github.com/openresty/lua-nginx-module#ngxshareddictttl) * [ngx.shared.DICT.expire](https://github.com/openresty/lua-nginx-module#ngxshareddictexpire) * [ngx.shared.DICT.flush_all](https://github.com/openresty/lua-nginx-module#ngxshareddictflush_all) * [ngx.shared.DICT.free_space](https://github.com/openresty/lua-nginx-module#ngxshareddictfree_space) * [ngx.shared.DICT.capacity](https://github.com/openresty/lua-nginx-module#ngxshareddictcapacity) [Back to TOC](#table-of-contents) ## resty.core.var * [ngx.var.VARIABLE](https://github.com/openresty/lua-nginx-module#ngxvarvariable) [Back to TOC](#table-of-contents) ## resty.core.ctx * [ngx.ctx](https://github.com/openresty/lua-nginx-module#ngxctx) [Back to TOC](#table-of-contents) ## get_ctx_table **syntax:** *ctx = resty.core.ctx.get_ctx_table(ctx?)* Similar to [ngx.ctx](#restycorectx) but it accepts an optional `ctx` argument. It will use the `ctx` from caller instead of creating a new table when the `ctx` table does not exist. Notice: the `ctx` table will be used in the current request's whole life cycle. Please be very careful when you try to reuse the `ctx` table. You need to make sure there is no Lua code using or going to use the `ctx` table in the current request before you reusing the `ctx` table in some other place. [Back to TOC](#table-of-contents) ## resty.core.request * [ngx.req.get_headers](https://github.com/openresty/lua-nginx-module#ngxreqget_headers) * [ngx.req.get_uri_args](https://github.com/openresty/lua-nginx-module#ngxreqget_uri_args) * [ngx.req.start_time](https://github.com/openresty/lua-nginx-module#ngxreqstart_time) * [ngx.req.get_method](https://github.com/openresty/lua-nginx-module#ngxreqget_method) * [ngx.req.set_method](https://github.com/openresty/lua-nginx-module#ngxreqset_method) * [ngx.req.set_header](https://github.com/openresty/lua-nginx-module#ngxreqset_header) * [ngx.req.clear_header](https://github.com/openresty/lua-nginx-module#ngxreqclear_header) [Back to TOC](#table-of-contents) ## resty.core.response * [ngx.header.HEADER](https://github.com/openresty/lua-nginx-module#ngxheaderheader) [Back to TOC](#table-of-contents) ## resty.core.misc * [ngx.status](https://github.com/openresty/lua-nginx-module#ngxstatus) * [ngx.is_subrequest](https://github.com/openresty/lua-nginx-module#ngxis_subrequest) * [ngx.headers_sent](https://github.com/openresty/lua-nginx-module#ngxheaders_sent) * [ngx.req.is_internal](https://github.com/openresty/lua-nginx-module#ngxreqis_internal) [Back to TOC](#table-of-contents) ## resty.core.time * [ngx.time](https://github.com/openresty/lua-nginx-module#ngxtime) * [ngx.now](https://github.com/openresty/lua-nginx-module#ngxnow) * [ngx.update_time](https://github.com/openresty/lua-nginx-module#ngxupdate_time) * [ngx.localtime](https://github.com/openresty/lua-nginx-module#ngxlocaltime) * [ngx.utctime](https://github.com/openresty/lua-nginx-module#ngxutctime) * [ngx.cookie_time](https://github.com/openresty/lua-nginx-module#ngxcookie_time) * [ngx.http_time](https://github.com/openresty/lua-nginx-module#ngxhttp_time) * [ngx.parse_http_time](https://github.com/openresty/lua-nginx-module#ngxparse_http_time) * [monotonic_msec](./lib/resty/core/time.md#monotonic_msec) * [monotonic_time](./lib/resty/core/time.md#monotonic_time) [Back to TOC](#table-of-contents) ## resty.core.worker * [ngx.worker.exiting](https://github.com/openresty/lua-nginx-module#ngxworkerexiting) * [ngx.worker.pid](https://github.com/openresty/lua-nginx-module#ngxworkerpid) * [ngx.worker.id](https://github.com/openresty/lua-nginx-module#ngxworkerid) * [ngx.worker.count](https://github.com/openresty/lua-nginx-module#ngxworkercount) [Back to TOC](#table-of-contents) ## resty.core.phase * [ngx.get_phase](https://github.com/openresty/lua-nginx-module#ngxget_phase) [Back to TOC](#table-of-contents) ## resty.core.ndk * [ndk.set_var](https://github.com/openresty/lua-nginx-module#ndkset_vardirective) [Back to TOC](#table-of-contents) ## resty.core.socket * [socket.setoption](https://github.com/openresty/lua-nginx-module#tcpsocksetoption) * [socket.setclientcert](https://github.com/openresty/lua-nginx-module#tcpsocksetclientcert) * [socket.sslhandshake](https://github.com/openresty/lua-nginx-module#tcpsocksslhandshake) [Back to TOC](#table-of-contents) ## resty.core.param * [ngx.arg](https://github.com/openresty/lua-nginx-module#ngxarg) (getter only) [Back to TOC](#table-of-contents) ## ngx.semaphore This Lua module implements a semaphore API for efficient "light thread" synchronization, which can work across different requests (but not across nginx worker processes). See the [documentation](./lib/ngx/semaphore.md) for this Lua module for more details. [Back to TOC](#table-of-contents) ## ngx.balancer This Lua module implements for defining dynamic upstream balancers in Lua. See the [documentation](./lib/ngx/balancer.md) for this Lua module for more details. [Back to TOC](#table-of-contents) ## ngx.ssl This Lua module provides a Lua API for controlling SSL certificates, private keys, SSL protocol versions, and etc in NGINX downstream SSL handshakes. See the [documentation](./lib/ngx/ssl.md) for this Lua module for more details. [Back to TOC](#table-of-contents) ## ngx.ssl.clienthello This Lua module provides a Lua API for post-processing SSL client hello message for NGINX downstream SSL connections. See the [documentation](./lib/ngx/ssl/clienthello.md) for this Lua module for more details. [Back to TOC](#table-of-contents) ## ngx.ssl.session This Lua module provides a Lua API for manipulating SSL session data and IDs for NGINX downstream SSL connections. See the [documentation](./lib/ngx/ssl/session.md) for this Lua module for more details. [Back to TOC](#table-of-contents) ## ngx.re This Lua module provides a Lua API which implements convenience utilities for the `ngx.re` API. See the [documentation](./lib/ngx/re.md) for this Lua module for more details. [Back to TOC](#table-of-contents) ## ngx.resp This Lua module provides Lua API which could be used to handle HTTP response. See the [documentation](./lib/ngx/resp.md) for this Lua module for more details. [Back to TOC](#table-of-contents) ## ngx.pipe This module provides a Lua API to spawn processes and communicate with them in a non-blocking fashion. See the [documentation](./lib/ngx/pipe.md) for this Lua module for more details. This module was first introduced in lua-resty-core v0.1.16. [Back to TOC](#table-of-contents) ## ngx.process This Lua module is used to manage the nginx process in Lua. See the [documentation](./lib/ngx/process.md) for this Lua module for more details. This module was first introduced in lua-resty-core v0.1.12. [Back to TOC](#table-of-contents) ## ngx.errlog This Lua module provides Lua API to capture and manage nginx error log messages. See the [documentation](./lib/ngx/errlog.md) for this Lua module for more details. This module was first introduced in lua-resty-core v0.1.12. [Back to TOC](#table-of-contents) ## ngx.base64 This Lua module provides Lua API to urlsafe base64 encode/decode. See the [documentation](./lib/ngx/base64.md) for this Lua module for more details. This module was first introduced in lua-resty-core v0.1.14. [Back to TOC](#table-of-contents) Caveat ====== If the user Lua code is not JIT compiled, then use of this library may lead to performance drop in interpreted mode. You will only observe speedup when you get a good part of your user Lua code JIT compiled. [Back to TOC](#table-of-contents) TODO ==== * Re-implement `ngx_lua`'s cosocket API with FFI. * Re-implement `ngx_lua`'s `ngx.eof` and `ngx.flush` API functions with FFI. [Back to TOC](#table-of-contents) Author ====== Yichun "agentzh" Zhang (章亦春) , OpenResty Inc. [Back to TOC](#table-of-contents) Copyright and License ===================== This module is licensed under the BSD license. Copyright (C) 2013-2019, by Yichun "agentzh" Zhang, OpenResty Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * 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. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [Back to TOC](#table-of-contents) See Also ======== * the ngx_lua module: https://github.com/openresty/lua-nginx-module#readme * LuaJIT FFI: http://luajit.org/ext_ffi.html [Back to TOC](#table-of-contents) lua-resty-core-0.1.31/dist.ini000066400000000000000000000005531474236722600161330ustar00rootroot00000000000000name=lua-resty-core abstract=New FFI-based Lua API for the ngx_lua module author=Yichun "agentzh" Zhang (agentzh) is_original=yes license=2bsd lib_dir=lib doc_dir=lib repo_link=https://github.com/openresty/lua-resty-core main_module=lib/resty/core/base.lua requires = luajit >= 2.1.0, nginx >= 1.27.1, ngx_http_lua = 0.10.28, openresty/lua-resty-lrucache >= 0.08 lua-resty-core-0.1.31/lib/000077500000000000000000000000001474236722600152325ustar00rootroot00000000000000lua-resty-core-0.1.31/lib/ngx/000077500000000000000000000000001474236722600160265ustar00rootroot00000000000000lua-resty-core-0.1.31/lib/ngx/balancer.lua000066400000000000000000000263351474236722600203110ustar00rootroot00000000000000-- Copyright (C) Yichun Zhang (agentzh) local base = require "resty.core.base" base.allows_subsystem('http', 'stream') local ffi = require "ffi" local C = ffi.C local ffi_str = ffi.string local errmsg = base.get_errmsg_ptr() local FFI_OK = base.FFI_OK local FFI_ERROR = base.FFI_ERROR local int_out = ffi.new("int[1]") local get_request = base.get_request local get_string_buf = base.get_string_buf local get_size_ptr = base.get_size_ptr local error = error local type = type local tonumber = tonumber local max = math.max local subsystem = ngx.config.subsystem local ngx_lua_ffi_balancer_set_current_peer local ngx_lua_ffi_balancer_enable_keepalive local ngx_lua_ffi_balancer_set_more_tries local ngx_lua_ffi_balancer_get_last_failure local ngx_lua_ffi_balancer_set_timeouts -- used by both stream and http local ngx_lua_ffi_balancer_set_upstream_tls local ngx_lua_ffi_balancer_bind_to_local_addr if subsystem == 'http' then ffi.cdef[[ int ngx_http_lua_ffi_balancer_set_current_peer(ngx_http_request_t *r, const unsigned char *addr, size_t addr_len, int port, const unsigned char *host, ssize_t host_len, char **err); int ngx_http_lua_ffi_balancer_enable_keepalive(ngx_http_request_t *r, unsigned long timeout, unsigned int max_requests, char **err); int ngx_http_lua_ffi_balancer_set_more_tries(ngx_http_request_t *r, int count, char **err); int ngx_http_lua_ffi_balancer_get_last_failure(ngx_http_request_t *r, int *status, char **err); int ngx_http_lua_ffi_balancer_set_timeouts(ngx_http_request_t *r, long connect_timeout, long send_timeout, long read_timeout, char **err); int ngx_http_lua_ffi_balancer_recreate_request(ngx_http_request_t *r, char **err); int ngx_http_lua_ffi_balancer_set_upstream_tls(ngx_http_request_t *r, int on, char **err); int ngx_http_lua_ffi_balancer_bind_to_local_addr(ngx_http_request_t *r, const u_char *addr, size_t addr_len, u_char *errbuf, size_t *errbuf_size); ]] ngx_lua_ffi_balancer_set_current_peer = C.ngx_http_lua_ffi_balancer_set_current_peer ngx_lua_ffi_balancer_enable_keepalive = C.ngx_http_lua_ffi_balancer_enable_keepalive ngx_lua_ffi_balancer_set_more_tries = C.ngx_http_lua_ffi_balancer_set_more_tries ngx_lua_ffi_balancer_get_last_failure = C.ngx_http_lua_ffi_balancer_get_last_failure ngx_lua_ffi_balancer_set_timeouts = C.ngx_http_lua_ffi_balancer_set_timeouts ngx_lua_ffi_balancer_set_upstream_tls = C.ngx_http_lua_ffi_balancer_set_upstream_tls ngx_lua_ffi_balancer_bind_to_local_addr = C.ngx_http_lua_ffi_balancer_bind_to_local_addr elseif subsystem == 'stream' then ffi.cdef[[ int ngx_stream_lua_ffi_balancer_set_current_peer( ngx_stream_lua_request_t *r, const unsigned char *addr, size_t addr_len, int port, char **err); int ngx_stream_lua_ffi_balancer_set_more_tries(ngx_stream_lua_request_t *r, int count, char **err); int ngx_stream_lua_ffi_balancer_get_last_failure( ngx_stream_lua_request_t *r, int *status, char **err); int ngx_stream_lua_ffi_balancer_set_timeouts(ngx_stream_lua_request_t *r, long connect_timeout, long timeout, char **err); int ngx_stream_lua_ffi_balancer_bind_to_local_addr( ngx_stream_lua_request_t *r, const char *addr, size_t addr_len, char *errbuf, size_t *errbuf_size); ]] ngx_lua_ffi_balancer_set_current_peer = C.ngx_stream_lua_ffi_balancer_set_current_peer ngx_lua_ffi_balancer_set_more_tries = C.ngx_stream_lua_ffi_balancer_set_more_tries ngx_lua_ffi_balancer_get_last_failure = C.ngx_stream_lua_ffi_balancer_get_last_failure local ngx_stream_lua_ffi_balancer_set_timeouts = C.ngx_stream_lua_ffi_balancer_set_timeouts ngx_lua_ffi_balancer_set_timeouts = function(r, connect_timeout, send_timeout, read_timeout, err) local timeout = max(send_timeout, read_timeout) return ngx_stream_lua_ffi_balancer_set_timeouts(r, connect_timeout, timeout, err) end ngx_lua_ffi_balancer_bind_to_local_addr = C.ngx_stream_lua_ffi_balancer_bind_to_local_addr else error("unknown subsystem: " .. subsystem) end local DEFAULT_KEEPALIVE_IDLE_TIMEOUT = 60000 local DEFAULT_KEEPALIVE_MAX_REQUESTS = 100 local peer_state_names = { [1] = "keepalive", [2] = "next", [4] = "failed", } local _M = { version = base.version } if subsystem == "http" then function _M.set_current_peer(addr, port, host) local r = get_request() if not r then error("no request found") end if not port then port = 0 elseif type(port) ~= "number" then port = tonumber(port) end if host ~= nil and type(host) ~= "string" then error("bad argument #3 to 'set_current_peer' " .. "(string expected, got " .. type(host) .. ")") end local rc = ngx_lua_ffi_balancer_set_current_peer(r, addr, #addr, port, host, host and #host or 0, errmsg) if rc == FFI_OK then return true end return nil, ffi_str(errmsg[0]) end else function _M.set_current_peer(addr, port, host) local r = get_request() if not r then error("no request found") end if not port then port = 0 elseif type(port) ~= "number" then port = tonumber(port) end if host ~= nil then error("bad argument #3 to 'set_current_peer' ('host' not yet " .. "implemented in " .. subsystem .. " subsystem)", 2) end local rc = ngx_lua_ffi_balancer_set_current_peer(r, addr, #addr, port, errmsg) if rc == FFI_OK then return true end return nil, ffi_str(errmsg[0]) end end if subsystem == "http" then function _M.enable_keepalive(idle_timeout, max_requests) local r = get_request() if not r then error("no request found") end if not idle_timeout then idle_timeout = DEFAULT_KEEPALIVE_IDLE_TIMEOUT elseif type(idle_timeout) ~= "number" then error("bad argument #1 to 'enable_keepalive' " .. "(number expected, got " .. type(idle_timeout) .. ")", 2) elseif idle_timeout < 0 then error("bad argument #1 to 'enable_keepalive' (expected >= 0)", 2) else idle_timeout = idle_timeout * 1000 end if not max_requests then max_requests = DEFAULT_KEEPALIVE_MAX_REQUESTS elseif type(max_requests) ~= "number" then error("bad argument #2 to 'enable_keepalive' " .. "(number expected, got " .. type(max_requests) .. ")", 2) elseif max_requests < 0 then error("bad argument #2 to 'enable_keepalive' (expected >= 0)", 2) end local rc = ngx_lua_ffi_balancer_enable_keepalive(r, idle_timeout, max_requests, errmsg) if rc == FFI_OK then return true end return nil, ffi_str(errmsg[0]) end else function _M.enable_keepalive() error("'enable_keepalive' not yet implemented in " .. subsystem .. " subsystem", 2) end end function _M.set_more_tries(count) local r = get_request() if not r then error("no request found") end local rc = ngx_lua_ffi_balancer_set_more_tries(r, count, errmsg) if rc == FFI_OK then if errmsg[0] == nil then return true end return true, ffi_str(errmsg[0]) -- return the warning end return nil, ffi_str(errmsg[0]) end function _M.get_last_failure() local r = get_request() if not r then error("no request found") end local state = ngx_lua_ffi_balancer_get_last_failure(r, int_out, errmsg) if state == 0 then return nil end if state == FFI_ERROR then return nil, nil, ffi_str(errmsg[0]) end return peer_state_names[state] or "unknown", int_out[0] end function _M.set_timeouts(connect_timeout, send_timeout, read_timeout) local r = get_request() if not r then error("no request found") end if not connect_timeout then connect_timeout = 0 elseif type(connect_timeout) ~= "number" or connect_timeout <= 0 then error("bad connect timeout", 2) else connect_timeout = connect_timeout * 1000 end if not send_timeout then send_timeout = 0 elseif type(send_timeout) ~= "number" or send_timeout <= 0 then error("bad send timeout", 2) else send_timeout = send_timeout * 1000 end if not read_timeout then read_timeout = 0 elseif type(read_timeout) ~= "number" or read_timeout <= 0 then error("bad read timeout", 2) else read_timeout = read_timeout * 1000 end local rc rc = ngx_lua_ffi_balancer_set_timeouts(r, connect_timeout, send_timeout, read_timeout, errmsg) if rc == FFI_OK then return true end return false, ffi_str(errmsg[0]) end if subsystem == 'http' then function _M.recreate_request() local r = get_request() if not r then error("no request found") end local rc = C.ngx_http_lua_ffi_balancer_recreate_request(r, errmsg) if rc == FFI_OK then return true end if errmsg[0] ~= nil then return nil, ffi_str(errmsg[0]) end return nil, "failed to recreate the upstream request" end function _M.set_upstream_tls(on) local r = get_request() if not r then return error("no request found") end local rc if on == 0 or on == false then on = 0 else on = 1 end rc = ngx_lua_ffi_balancer_set_upstream_tls(r, on, errmsg); if rc == FFI_OK then return true end return nil, ffi_str(errmsg[0]) end end function _M.bind_to_local_addr(addr) local r = get_request() if not r then error("no request found") end if type(addr) ~= "string" then error("bad argument #1 to 'bind_to_local_addr' " .. "(string expected, got " .. type(addr) .. ")") end local errbuf_size = 1024 local errbuf = get_string_buf(errbuf_size) local sizep = get_size_ptr() sizep[0] = errbuf_size local rc = ngx_lua_ffi_balancer_bind_to_local_addr(r, addr, #addr, errbuf, sizep) if rc == FFI_OK then return true end return nil, ffi_str(errbuf, sizep[0]) end return _M lua-resty-core-0.1.31/lib/ngx/balancer.md000066400000000000000000000455031474236722600201260ustar00rootroot00000000000000Name ==== ngx.balancer - Lua API for defining dynamic upstream balancers in Lua Table of Contents ================= * [Name](#name) * [Status](#status) * [Synopsis](#synopsis) * [http subsystem](#http-subsystem) * [stream subsystem](#stream-subsystem) * [Description](#description) * [Methods](#methods) * [get_last_failure](#get_last_failure) * [recreate_request](#recreate_request) * [set_current_peer](#set_current_peer) * [bind_to_local_addr](#bind_to_local_addr) * [enable_keepalive](#enable_keepalive) * [set_more_tries](#set_more_tries) * [set_timeouts](#set_timeouts) * [set_upstream_tls](#set_upstream_tls) * [Community](#community) * [English Mailing List](#english-mailing-list) * [Chinese Mailing List](#chinese-mailing-list) * [Bugs and Patches](#bugs-and-patches) * [Author](#author) * [Copyright and License](#copyright-and-license) * [See Also](#see-also) Status ====== This Lua module is production ready. Synopsis ======== http subsystem -------------- ```nginx http { upstream backend { server 0.0.0.1; # just an invalid address as a place holder balancer_by_lua_block { local balancer = require "ngx.balancer" -- well, usually we calculate the peer's host and port -- according to some balancing policies instead of using -- hard-coded values like below local host = "127.0.0.2" local port = 8080 local ok, err = balancer.set_current_peer(host, port) if not ok then ngx.log(ngx.ERR, "failed to set the current peer: ", err) return ngx.exit(500) end } keepalive 10; # connection pool } server { # this is the real entry point listen 80; location / { # make use of the upstream named "backend" defined above: proxy_pass http://backend/fake; } } server { # this server is just for mocking up a backend peer here... listen 127.0.0.2:8080; location = /fake { echo "this is the fake backend peer..."; } } } ``` [Back to TOC](#table-of-contents) stream subsystem ---------------- ```nginx stream { upstream backend { server 0.0.0.1:1234; # just an invalid address as a place holder balancer_by_lua_block { local balancer = require "ngx.balancer" -- well, usually we calculate the peer's host and port -- according to some balancing policies instead of using -- hard-coded values like below local host = "127.0.0.2" local port = 8080 local ok, err = balancer.set_current_peer(host, port) if not ok then ngx.log(ngx.ERR, "failed to set the current peer: ", err) return ngx.exit(ngx.ERROR) end } } server { # this is the real entry point listen 10000; # make use of the upstream named "backend" defined above: proxy_pass backend; } server { # this server is just for mocking up a backend peer here... listen 127.0.0.2:8080; echo "this is the fake backend peer..."; } } ``` [Back to TOC](#table-of-contents) Description =========== This Lua module provides API functions to allow defining highly dynamic NGINX load balancers for any existing nginx upstream modules like [ngx_http_proxy_module](http://nginx.org/en/docs/http/ngx_http_proxy_module.html), [ngx_http_fastcgi_module](http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html) and [ngx_stream_proxy_module](https://nginx.org/en/docs/stream/ngx_stream_proxy_module.html). It allows you to dynamically select a backend peer to connect to (or retry) on a per-request basis from a list of backend peers which may also be dynamic. [Back to TOC](#table-of-contents) Methods ======= All the methods of this module are static (or module-level). That is, you do not need an object (or instance) to call these methods. [Back to TOC](#table-of-contents) set_current_peer ---------------- **syntax:** *ok, err = balancer.set_current_peer(host, port, host?)* **context:** *balancer_by_lua** Sets the peer address (host and port) for the current backend query (which may be a retry). Domain names in `host` do not make sense. You need to use OpenResty libraries like [lua-resty-dns](https://github.com/openresty/lua-resty-dns) to obtain IP address(es) from all the domain names before entering the `balancer_by_lua*` handler (for example, you can perform DNS lookups in an earlier phase like [access_by_lua*](https://github.com/openresty/lua-nginx-module#access_by_lua) and pass the results to the `balancer_by_lua*` handler via [ngx.ctx](https://github.com/openresty/lua-nginx-module#ngxctx). `host` can be set to a string value or nil. If you set `host` to `nil`, this function will use the host set by directive `proxy_ssl_name`. You should not specify `host` and `proxy_ssl_name` at the same time. This directive should be used on the toplevel scope of your `nginx.conf`. In case of an error, this function returns `nil` and a string describing the error. [Back to TOC](#table-of-contents) bind_to_local_addr -------------- **syntax:** *ok, err = balancer.bind_to_local_addr(addr)* **context:** *balancer_by_lua** Makes outgoing connections to a proxied server originate from the specified local IP address with an optional port. `addr` is a string value of the IP address with optional port. For example: 127.0.0.1, 127.0.0.1:12345. In case of an error, this function returns `nil` and a string describing the error. [Back to TOC](#table-of-contents) enable_keepalive ---------------- **syntax:** `ok, err = balancer.enable_keepalive(idle_timeout?, max_requests?)` **context:** *balancer_by_lua** Instructs the current upstream connection to be kept-alive once the current request succeeds. The connection will be inserted in the pool specified by the `pool` option of the [set_current_peer](#set_current_peer) function (if unspecified, the default pool name will be `":"`). The keepalive capabilities offered via this function are similar to that of the [keepalive](http://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive) directive of the ngx_http_upstream_module, with more dynamic capabilities addressing a wide range of use-cases. The first optional argument `idle_timeout` may be a number used to specify the maximum amount of time the connection may remain unused in the pool. The value is to be specified in seconds, with floating point numbers allowing for millisecond precision. If omitted, the default value is `60` (60 seconds). When the idle timeout threshold is reached and the connection hasn't been reused, it will be closed. A value of `0` will keep the connection in the pool indefinitely (it may still be eventually closed by the remote peer). This argument is identical to the [keepalive_timeout](http://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive_timeout) directive of the ngx_http_upstream_module, but can be set dynamically for each upstream connection. The second optional argument `max_requests` may be a number used to specify the amount of upstream requests a given connection should be reused for before being closed. If omitted, the default value is `100`. When the connection has been reused as many times as the `max_requests` value, it will be closed instead of being inserted back into the connection pool. A value of `0` will allow for the connection to be reused for any number of upstream requests. This argument is identical to the [keepalive_requests](http://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive_requests) directive of the ngx_http_upstream_module, but can be set dynamically for each upstream connection. This function returns `true` upon success, or `nil` and a string describing the error otherwise. Below is a standard example usage: ```nginx http { upstream backend { server 0.0.0.1; # placeholder balancer_by_lua_block { local balancer = require "ngx.balancer" local ok, err = balancer.set_current_peer("127.0.0.2", 8080) if not ok then ngx.log(ngx.ERR, "failed to set current peer: ", err) return end -- default pool will be "host:port" -- default pool_size will be 30 ok, err = balancer.enable_keepalive() if not ok then ngx.log(ngx.ERR, "failed to set keepalive: ", err) return end } } server { listen 80; location / { proxy_pass http://backend/; } } } ``` A more advanced usage of this API can be made to overcome specific limitations of NGINX's upstream keepalive pooling behavior. One of such limitations is the lack of consideration for TLS attributes in the connection reuse logic: within a given `upstream {}` block, NGINX's connection reuse logic only considers the IP and port attributes of a connection, and fails to consider the SNI extension (among others), which could result in requests being sent over the wrong TLS connection. NGINX's official stance on this limitation is to use different `upstream {}` blocks (e.g. one for each SNI), which would not only be wasteful but also defeat the purpose of the dynamic capabilities offered by OpenResty. Below is an example of how to overcome this limitation and pool connections by IP, port, and SNI: ```nginx http { upstream backend { server 0.0.0.1; # placeholder balancer_by_lua_block { local balancer = require "ngx.balancer" local host = "example.org" local ip = "127.0.0.2" local port = 8080 local ok, err = balancer.set_current_peer("127.0.0.2", 8080, host) if not ok then ngx.log(ngx.ERR, "failed to set current peer: ", err) return end ok, err = balancer.enable_keepalive(60, 100) if not ok then ngx.log(ngx.ERR, "failed to set keepalive: ", err) return end } } ... } ``` Should not specify nginx keepalive with balancer_by_lua at the same time. The following configurations are not recommended: ```nginx http { upstream backend_ngx_keepalive { server 0.0.0.1; # placeholder balancer_by_lua_block { local balancer = require "ngx.balancer" local host = "example.org" balancer.set_current_peer("127.0.0.2", 8080, host) balancer.enable_keepalive(60, 100) } keepalive 60; keepalive_timeout 60s; keepalive_requests 100; } } ``` This function was first added to the `http` subsystem in the `v0.1.18` release of this library. It is not yet supported in the `stream` subsystem. [Back to TOC](#table-of-contents) set_more_tries -------------- **syntax:** *ok, err = balancer.set_more_tries(count)* **context:** *balancer_by_lua** Sets the tries performed when the current attempt (which may be a retry) fails (as determined by directives like [proxy_next_upstream](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream), depending on what particular nginx uptream module you are currently using). Note that the current attempt is *excluded* in the `count` number set here. Please note that, the total number of tries in a single downstream request cannot exceed the hard limit configured by directives like [proxy_next_upstream_tries](http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_next_upstream_tries), depending on what concrete nginx upstream module you are using. When exceeding this limit, the `count` value will get reduced to meet the limit and the second return value will be the string `"reduced tries due to limit"`, which is a warning, while the first return value is still a `true` value. [Back to TOC](#table-of-contents) get_last_failure ---------------- **syntax:** *state_name, status_code = balancer.get_last_failure()* **context:** *balancer_by_lua** Retrieves the failure details about the previous failed attempt (if any) when the `next_upstream` retrying mechanism is in action. When there was indeed a failed previous attempt, it returned a string describing that attempt's state name, as well as an integer describing the status code of that attempt. Possible state names are as follows: * `"next"` Failures due to bad status codes sent from the backend server. The origin's response is same though, which means the backend connection can still be reused for future requests. * `"failed"` Fatal errors while communicating to the backend server (like connection timeouts, connection resets, and etc). In this case, the backend connection must be aborted and cannot get reused. Possible status codes are those HTTP error status codes like `502` and `504`. For stream module, `status_code` will always be 0 (ngx.OK) and is provided for compatibility reasons. When the current attempt is the first attempt for the current downstream request (which means there is no previous attempts at all), this method always returns a single `nil` value. [Back to TOC](#table-of-contents) set_timeouts ------------ **syntax:** `ok, err = balancer.set_timeouts(connect_timeout, send_timeout, read_timeout)` **context:** *balancer_by_lua** Sets the upstream timeout (connect, send and read) in seconds for the current and any subsequent backend requests (which might be a retry). If you want to inherit the timeout value of the global `nginx.conf` configuration (like `proxy_connect_timeout`), then just specify the `nil` value for the corresponding argument (like the `connect_timeout` argument). Zero and negative timeout values are not allowed. You can specify millisecond precision in the timeout values by using floating point numbers like 0.001 (which means 1ms). **Note:** `send_timeout` and `read_timeout` are controlled by the same config [`proxy_timeout`](https://nginx.org/en/docs/stream/ngx_stream_proxy_module.html#proxy_timeout) for `ngx_stream_proxy_module`. To keep API compatibility, this function will use `max(send_timeout, read_timeout)` as the value for setting `proxy_timeout`. Returns `true` when the operation is successful; returns `nil` and a string describing the error otherwise. This only affects the current downstream request. It is not a global change. For the best performance, you should use the [OpenResty](https://openresty.org/) bundle. This function was first added in the `0.1.7` version of this library. [Back to TOC](#table-of-contents) recreate_request ---------------- **syntax:** `ok, err = balancer.recreate_request()` **context:** *balancer_by_lua** Recreates the request buffer for sending to the upstream server. This is useful, for example if you want to change a request header field to the new upstream server on balancer retries. Normally this does not work because the request buffer is created once during upstream module initialization and won't be regenerated for subsequent retries. However you can use `proxy_set_header My-Header $my_header` and set the `ngx.var.my_header` variable inside the balancer phase. Calling `balancer.recreate_request()` after updating a header field will cause the request buffer to be re-generated and the `My-Header` header will thus contain the new value. **Warning:** because the request buffer has to be recreated and such allocation occurs on the request memory pool, the old buffer has to be thrown away and will only be freed after the request finishes. Do not call this function too often or memory leaks may be noticeable. Even so, a call to this function should be made **only** if you know the request buffer must be regenerated, instead of unconditionally in each balancer retries. This function was first added in the `0.1.20` version of this library. [Back to TOC](#table-of-contents) set_upstream_tls ------------ **syntax:** `ok, err = balancer.set_upstream_tls(on)` **context:** *balancer_by_lua** Turn off the HTTPs or reenable the HTTPs for the upstream connection. - If `on` is `true`, then the https protocol will be used to connect to the upstream server. - If `on` is `false`, then the http protocol will be used to connect to the upstream server. This function was first added in the `0.1.29` version of this library. [Back to TOC](#table-of-contents) Community ========= [Back to TOC](#table-of-contents) English Mailing List -------------------- The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. [Back to TOC](#table-of-contents) Chinese Mailing List -------------------- The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. [Back to TOC](#table-of-contents) Bugs and Patches ================ Please report bugs or submit patches by 1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), 1. or posting to the [OpenResty community](#community). [Back to TOC](#table-of-contents) Author ====== Yichun Zhang <agentzh@gmail.com> (agentzh), OpenResty Inc. [Back to TOC](#table-of-contents) Copyright and License ===================== This module is licensed under the BSD license. Copyright (C) 2015-2017, by Yichun "agentzh" Zhang, OpenResty Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * 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. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [Back to TOC](#table-of-contents) See Also ======== * the ngx_lua module: https://github.com/openresty/lua-nginx-module * the [balancer_by_lua*](https://github.com/openresty/lua-nginx-module#balancer_by_lua_block) directive. * the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. * OpenResty: https://openresty.org [Back to TOC](#table-of-contents) lua-resty-core-0.1.31/lib/ngx/base64.lua000066400000000000000000000032661474236722600176240ustar00rootroot00000000000000-- Copyright (C) by Yichun Zhang (agentzh) -- Copyright (C) by OpenResty Inc. local ffi = require("ffi") local base = require("resty.core.base") local ffi_str = ffi.string local type = type local C = ffi.C local NGX_ERROR = ngx.ERROR local _M = { version = base.version } ffi.cdef[[ typedef intptr_t ngx_int_t; void ngx_encode_base64url(ngx_str_t *dst, ngx_str_t *src); ngx_int_t ngx_decode_base64url(ngx_str_t *dst, ngx_str_t *src); ]] local get_string_buf = base.get_string_buf local dst_str_t = ffi.new("ngx_str_t[1]") local src_str_t = ffi.new("ngx_str_t[1]") local function base64_encoded_length(len) return ((len + 2) / 3) * 4 end local function base64_decoded_length(len) return ((len + 3) / 4) * 3 end function _M.encode_base64url(s) if type(s) ~= "string" then return nil, "must provide a string" end local len = #s local trans_len = base64_encoded_length(len) local src = src_str_t[0] local dst = dst_str_t[0] src.data = s src.len = len dst.data = get_string_buf(trans_len) dst.len = trans_len C.ngx_encode_base64url(dst_str_t, src_str_t) return ffi_str(dst.data, dst.len) end function _M.decode_base64url(s) if type(s) ~= "string" then return nil, "must provide a string" end local len = #s local trans_len = base64_decoded_length(len) local src = src_str_t[0] local dst = dst_str_t[0] src.data = s src.len = len dst.data = get_string_buf(trans_len) dst.len = trans_len local ret = C.ngx_decode_base64url(dst_str_t, src_str_t) if ret == NGX_ERROR then return nil, "invalid input" end return ffi_str(dst.data, dst.len) end return _M lua-resty-core-0.1.31/lib/ngx/base64.md000066400000000000000000000075611474236722600174450ustar00rootroot00000000000000Name ==== `ngx.base64` - urlsafe base64 encode/decode functions OpenResty/ngx\_lua. Table of Contents ================= * [Name](#name) * [Status](#status) * [Synopsis](#synopsis) * [Methods](#methods) * [encode\_base64url](#encode_base64url) * [decode\_base64url](#decode_base64url) * [Community](#community) * [English Mailing List](#english-mailing-list) * [Chinese Mailing List](#chinese-mailing-list) * [Bugs and Patches](#bugs-and-patches) * [Author](#author) * [Copyright and License](#copyright-and-license) * [See Also](#see-also) Status ====== This Lua module is production ready. Synopsis ======== ```lua local b64 = require("ngx.base64") local res, err res = b64.encode_base64url("foo") res, err = b64.decode_base64url(res) if not res then -- invalid input ngx.log(ngx.ERR, err) end assert(res == "foo") ``` [Back to TOC](#table-of-contents) Methods ======= encode\_base64url ----------------- **syntax:** *encoded = base64.encode_base64url(input)* **context:** *any* Encode `input` using base64url rules. Returns the encoded string. [Back to TOC](#table-of-contents) decode\_base64url ----------------- **syntax:** *decoded, err = base64.decode_base64url(input)* **context:** *any* Decode `input` using base64url rules. Returns the decoded string. If the `input` is not a valid base64url encoded string, `decoded `will be `nil` and `err` will be a string describing the error. [Back to TOC](#table-of-contents) Community ========= [Back to TOC](#table-of-contents) English Mailing List -------------------- The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. [Back to TOC](#table-of-contents) Chinese Mailing List -------------------- The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. [Back to TOC](#table-of-contents) Bugs and Patches ================ Please report bugs or submit patches by 1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), 1. or posting to the [OpenResty community](#community). [Back to TOC](#table-of-contents) Author ====== Datong Sun <datong@openresty.com> (dndx), OpenResty Inc. [Back to TOC](#table-of-contents) Copyright and License ===================== This module is licensed under the BSD license. Copyright (C) 2017, by Yichun "agentzh" Zhang, OpenResty Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * 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. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [Back to TOC](#table-of-contents) See Also ======== * the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. * the ngx_lua module: https://github.com/openresty/lua-nginx-module * OpenResty: https://openresty.org [Back to TOC](#table-of-contents) lua-resty-core-0.1.31/lib/ngx/errlog.lua000066400000000000000000000104721474236722600200270ustar00rootroot00000000000000-- Copyright (C) Yichun Zhang (agentzh) local base = require "resty.core.base" base.allows_subsystem('http', 'stream') local ffi = require 'ffi' local ffi_string = ffi.string local get_string_buf = base.get_string_buf local get_size_ptr = base.get_size_ptr local C = ffi.C local new_tab = base.new_tab local ffi_new = ffi.new local charpp = ffi_new("char *[1]") local intp = ffi.new("int[1]") local num_value = ffi_new("double[1]") local get_request = base.get_request local tonumber = tonumber local type = type local error = error local subsystem = ngx.config.subsystem local ngx_lua_ffi_errlog_set_filter_level local ngx_lua_ffi_errlog_get_msg local ngx_lua_ffi_errlog_get_sys_filter_level local ngx_lua_ffi_raw_log local _M = { version = base.version } if subsystem == 'http' then ffi.cdef[[ int ngx_http_lua_ffi_errlog_set_filter_level(int level, unsigned char *err, size_t *errlen); int ngx_http_lua_ffi_errlog_get_msg(char **log, int *loglevel, unsigned char *err, size_t *errlen, double *log_time); int ngx_http_lua_ffi_errlog_get_sys_filter_level(ngx_http_request_t *r); int ngx_http_lua_ffi_raw_log(ngx_http_request_t *r, int level, const unsigned char *s, size_t s_len); ]] ngx_lua_ffi_errlog_set_filter_level = C.ngx_http_lua_ffi_errlog_set_filter_level ngx_lua_ffi_errlog_get_msg = C.ngx_http_lua_ffi_errlog_get_msg ngx_lua_ffi_errlog_get_sys_filter_level = C.ngx_http_lua_ffi_errlog_get_sys_filter_level ngx_lua_ffi_raw_log = C.ngx_http_lua_ffi_raw_log elseif subsystem == 'stream' then ffi.cdef[[ int ngx_stream_lua_ffi_errlog_set_filter_level(int level, unsigned char *err, size_t *errlen); int ngx_stream_lua_ffi_errlog_get_msg(char **log, int *loglevel, unsigned char *err, size_t *errlen, double *log_time); int ngx_stream_lua_ffi_errlog_get_sys_filter_level(ngx_stream_lua_request_t *r); int ngx_stream_lua_ffi_raw_log(ngx_stream_lua_request_t *r, int level, const unsigned char *s, size_t s_len); ]] ngx_lua_ffi_errlog_set_filter_level = C.ngx_stream_lua_ffi_errlog_set_filter_level ngx_lua_ffi_errlog_get_msg = C.ngx_stream_lua_ffi_errlog_get_msg ngx_lua_ffi_errlog_get_sys_filter_level = C.ngx_stream_lua_ffi_errlog_get_sys_filter_level ngx_lua_ffi_raw_log = C.ngx_stream_lua_ffi_raw_log end local ERR_BUF_SIZE = 128 local FFI_ERROR = base.FFI_ERROR function _M.set_filter_level(level) if not level then return nil, [[missing "level" argument]] end local err = get_string_buf(ERR_BUF_SIZE) local errlen = get_size_ptr() errlen[0] = ERR_BUF_SIZE local rc = ngx_lua_ffi_errlog_set_filter_level(level, err, errlen) if rc == FFI_ERROR then return nil, ffi_string(err, errlen[0]) end return true end function _M.get_logs(max, logs) local err = get_string_buf(ERR_BUF_SIZE) local errlen = get_size_ptr() errlen[0] = ERR_BUF_SIZE local log = charpp local loglevel = intp local log_time = num_value max = max or 10 if not logs then logs = new_tab(max * 3 + 1, 0) end local count = 0 for i = 1, max do local loglen = ngx_lua_ffi_errlog_get_msg(log, loglevel, err, errlen, log_time) if loglen == FFI_ERROR then return nil, ffi_string(err, errlen[0]) end if loglen > 0 then logs[count + 1] = loglevel[0] logs[count + 2] = log_time[0] logs[count + 3] = ffi_string(log[0], loglen) count = count + 3 end if loglen < 0 then -- no error log logs[count + 1] = nil break end if i == max then -- last one logs[count + 1] = nil break end end return logs end function _M.get_sys_filter_level() local r = get_request() return tonumber(ngx_lua_ffi_errlog_get_sys_filter_level(r)) end function _M.raw_log(level, msg) if type(level) ~= "number" then error("bad argument #1 to 'raw_log' (must be a number)", 2) end if type(msg) ~= "string" then error("bad argument #2 to 'raw_log' (must be a string)", 2) end local r = get_request() local rc = ngx_lua_ffi_raw_log(r, level, msg, #msg) if rc == FFI_ERROR then error("bad log level", 2) end end return _M lua-resty-core-0.1.31/lib/ngx/errlog.md000066400000000000000000000312521474236722600176450ustar00rootroot00000000000000Name ==== `ngx.errlog` - manage nginx error log data in Lua for OpenResty/ngx_lua. Table of Contents ================= * [Name](#name) * [Status](#status) * [Synopsis](#synopsis) * [Capturing nginx error logs with specified log filtering level](#capturing-nginx-error-logs-with-specified-log-filtering-level) * [Methods](#methods) * [set_filter_level](#set_filter_level) * [get_logs](#get_logs) * [get_sys_filter_level](#get_sys_filter_level) * [raw_log](#raw_log) * [Community](#community) * [English Mailing List](#english-mailing-list) * [Chinese Mailing List](#chinese-mailing-list) * [Bugs and Patches](#bugs-and-patches) * [Author](#author) * [Copyright and License](#copyright-and-license) * [See Also](#see-also) Status ====== This Lua module is production ready. Synopsis ======== Capturing nginx error logs with specified log filtering level ------------------------------------------------------------- ```nginx error_log logs/error.log info; http { # enable capturing error logs lua_capture_error_log 32m; init_by_lua_block { local errlog = require "ngx.errlog" local status, err = errlog.set_filter_level(ngx.WARN) if not status then ngx.log(ngx.ERR, err) return end ngx.log(ngx.WARN, "set error filter level: WARN") } server { # ... location = /t { content_by_lua_block { local errlog = require "ngx.errlog" ngx.log(ngx.INFO, "test1") ngx.log(ngx.WARN, "test2") ngx.log(ngx.ERR, "test3") local logs, err = errlog.get_logs(10) if not logs then ngx.say("FAILED ", err) return end for i = 1, #logs, 3 do ngx.say("level: ", logs[i], " time: ", logs[i + 1], " data: ", logs[i + 2]) end } } } } ``` The example location above produces a response like this: ``` level: 5 time: 1498546995.304 data: 2017/06/27 15:03:15 [warn] 46877#0: [lua] init_by_lua:8: set error filter level: WARN level: 5 time: 1498546999.178 data: 2017/06/27 15:03:19 [warn] 46879#0: *1 [lua] test.lua:5: test2, client: 127.0.0.1, server: localhost, ...... level: 4 time: 1498546999.178 data: 2017/06/27 15:03:19 [error] 46879#0: *1 [lua] test.lua:6: test3, client: 127.0.0.1, server: localhost, ...... ``` [Back to TOC](#table-of-contents) Methods ======= set_filter_level ----------------- **syntax:** *status, err = log_module.set_filter_level(log_level)* **context:** *init_by_lua** Specifies the filter log level, only to capture and buffer the error logs with a log level no lower than the specified level. If we don't call this API, all of the error logs will be captured by default. In case of error, `nil` will be returned as well as a string describing the error. This API should always work with directive [lua_capture_error_log](https://github.com/openresty/lua-nginx-module#lua_capture_error_log). See [Nginx log level constants](https://github.com/openresty/lua-nginx-module#nginx-log-level-constants) for all nginx log levels. For example, ```lua init_by_lua_block { local errlog = require "ngx.errlog" errlog.set_filter_level(ngx.WARN) } ``` *NOTE:* The debugging logs since when OpenResty or NGINX is not built with `--with-debug`, all the debug level logs are suppressed regardless. [Back to TOC](#table-of-contents) get_logs -------- **syntax:** *res, err = log_module.get_logs(max?, res?)* **context:** *any* Fetches the captured nginx error log messages if any in the global data buffer specified by `ngx_lua`'s [lua_capture_error_log](https://github.com/openresty/lua-nginx-module#lua_capture_error_log) directive. Upon return, this Lua function also *removes* those messages from that global capturing buffer to make room for future new error log data. In case of error, `nil` will be returned as well as a string describing the error. The optional `max` argument is a number that when specified, will prevent `errlog.get_logs` from adding more than `max` messages to the `res` array. ```lua for i = 1, 20 do ngx.log(ngx.ERR, "test") end local errlog = require "ngx.errlog" local res = errlog.get_logs(10) -- the number of messages in the `res` table is 10 and the `res` table -- has 30 elements. ``` The resulting table has the following structure: ```lua { level1, time1, msg1, level2, time2, msg2, ... } ``` The `levelX` values are constants defined below: https://github.com/openresty/lua-nginx-module/#nginx-log-level-constants The `timeX` values are UNIX timestamps in seconds with millisecond precision. The sub-second part is presented as the decimal part. The time format is exactly the same as the value returned by [ngx.now](https://github.com/openresty/lua-nginx-module/#ngxnow). It is also subject to NGINX core's time caching. The `msgX` values are the error log message texts. So to traverse this array, the user can use a loop like this: ```lua for i = 1, #res, 3 do local level = res[i] if not level then break end local time = res[i + 1] local msg = res[i + 2] -- handle the current message with log level in `level`, -- log time in `time`, and log message body in `msg`. end ``` Specifying `max <= 0` disables this behavior, meaning that the number of results won't be limited. The optional 2th argument `res` can be a user-supplied Lua table to hold the result instead of creating a brand new table. This can avoid unnecessary table dynamic allocations on hot Lua code paths. It is used like this: ```lua local errlog = require "ngx.errlog" local new_tab = require "table.new" local buffer = new_tab(100 * 3, 0) -- for 100 messages local errlog = require "ngx.errlog" local res, err = errlog.get_logs(0, buffer) if res then -- res is the same table as `buffer` for i = 1, #res, 3 do local level = res[i] if not level then break end local time = res[i + 1] local msg = res[i + 2] ... end end ``` When provided with a `res` table, `errlog.get_logs` won't clear the table for performance reasons, but will rather insert a trailing `nil` value after the last table element. When the trailing `nil` is not enough for your purpose, you should clear the table yourself before feeding it into the `errlog.get_logs` function. [Back to TOC](#table-of-contents) get_sys_filter_level -------------------- **syntax:** *log_level = log_module.get_sys_filter_level()* **context:** *any* Return the nginx core's error log filter level (defined via the [error_log](http://nginx.org/r/error_log) configuration directive in `nginx.conf`) as an integer value matching the nginx error log level constants documented below: https://github.com/openresty/lua-nginx-module/#nginx-log-level-constants For example: ```lua local errlog = require "ngx.errlog" local log_level = errlog.get_sys_filter_level() -- Now the filter level is always one level higher than system default log level on priority local status, err = errlog.set_filter_level(log_level - 1) if not status then ngx.log(ngx.ERR, err) return end ``` [Back to TOC](#table-of-contents) raw_log ------- **syntax:** *log_module.raw_log(log_level, msg)* **context:** *any* Log `msg` to the error logs with the given logging level. Just like the [ngx.log](https://github.com/openresty/lua-nginx-module#ngxlog) API, the `log_level` argument can take constants like `ngx.ERR` and `ngx.WARN`. Check out [Nginx log level constants for details.](https://github.com/openresty/lua-nginx-module#nginx-log-level-constants) However, unlike the `ngx.log` API which accepts variadic arguments, this function only accepts a single string as its second argument `msg`. This function differs from `ngx.log` in the way that it will not prefix the written logs with any sort of debug information (such as the caller's file and line number). For example, while `ngx.log` would produce ``` 2017/07/09 19:36:25 [notice] 25932#0: *1 [lua] content_by_lua(nginx.conf:51):5: hello world, client: 127.0.0.1, server: localhost, request: "GET /log HTTP/1.1", host: "localhost" ``` from ```lua ngx.log(ngx.NOTICE, "hello world") ``` the `errlog.raw_log()` call produces ``` 2017/07/09 19:36:25 [notice] 25932#0: *1 hello world, client: 127.0.0.1, server: localhost, request: "GET /log HTTP/1.1", host: "localhost" ``` from ```lua local errlog = require "ngx.errlog" errlog.raw_log(ngx.NOTICE, "hello world") ``` This function is best suited when the format and/or stack level of the debug information proposed by `ngx.log` is not desired. A good example of this would be a custom logging function which prefixes each log with a namespace in an application: ``` 1. local function my_log(lvl, ...) 2. ngx.log(lvl, "[prefix] ", ...) 3. end 4. 5. my_log(ngx.ERR, "error") ``` Here, the produced log would indicate that this error was logged at line `2.`, when in reality, we wish the investigator of that log to realize it was logged at line `5.` right away. For such use cases (or other formatting reasons), one may use `raw_log` to create a logging utility that supports such requirements. Here is a suggested implementation: ```lua local errlog = require "ngx.errlog" local function my_log(lvl, ...) -- log to error logs with our custom prefix, stack level -- and separator local n = select("#", ...) local t = { ... } local info = debug.getinfo(2, "Sl") local prefix = string.format("(%s):%d:", info.short_src, info.currentline) local buf = { prefix } for i = 1, n do buf[i + 1] = tostring(t[i]) end local msg = table.concat(buf, " ") errlog.raw_log(lvl, msg) -- line 19. end local function my_function() -- do something and log my_log(ngx.ERR, "hello from", "raw_log:", true) -- line 25. end my_function() ``` This utility function will produce the following log, explicitly stating that the error was logged on line `25.`: ``` 2017/07/09 20:03:07 [error] 26795#0: *2 (/path/to/file.lua):25: hello from raw_log: true, context: ngx.timer ``` As a reminder to the reader, one must be wary of the cost of string concatenation on the Lua land, and should prefer the combined use of a buffer table and `table.concat` to avoid unnecessary GC pressure. [Back to TOC](#table-of-contents) Community ========= [Back to TOC](#table-of-contents) English Mailing List -------------------- The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. [Back to TOC](#table-of-contents) Chinese Mailing List -------------------- The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. [Back to TOC](#table-of-contents) Bugs and Patches ================ Please report bugs or submit patches by 1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), 1. or posting to the [OpenResty community](#community). [Back to TOC](#table-of-contents) Author ====== Yuansheng Wang <membphis@gmail.com> (membphis), OpenResty Inc. [Back to TOC](#table-of-contents) Copyright and License ===================== This module is licensed under the BSD license. Copyright (C) 2017, by Yichun "agentzh" Zhang, OpenResty Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * 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. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [Back to TOC](#table-of-contents) See Also ======== * the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. * the ngx_lua module: https://github.com/openresty/lua-nginx-module * OpenResty: https://openresty.org [Back to TOC](#table-of-contents) lua-resty-core-0.1.31/lib/ngx/ocsp.lua000066400000000000000000000100721474236722600174750ustar00rootroot00000000000000-- Copyright (C) Yichun Zhang (agentzh) local base = require "resty.core.base" base.allows_subsystem('http') local ffi = require "ffi" local C = ffi.C local ffi_new = ffi.new local ffi_str = ffi.string local get_request = base.get_request local error = error local tonumber = tonumber local errmsg = base.get_errmsg_ptr() local get_string_buf = base.get_string_buf local get_string_buf_size = base.get_string_buf_size local get_size_ptr = base.get_size_ptr local FFI_DECLINED = base.FFI_DECLINED local FFI_OK = base.FFI_OK local FFI_BUSY = base.FFI_BUSY ffi.cdef[[ int ngx_http_lua_ffi_ssl_get_ocsp_responder_from_der_chain( const char *chain_data, size_t chain_len, char *out, size_t *out_size, char **err); int ngx_http_lua_ffi_ssl_create_ocsp_request(const char *chain_data, size_t chain_len, unsigned char *out, size_t *out_size, char **err); int ngx_http_lua_ffi_ssl_validate_ocsp_response(const unsigned char *resp, size_t resp_len, const char *chain_data, size_t chain_len, unsigned char *errbuf, size_t *errbuf_size, long *valid); int ngx_http_lua_ffi_ssl_set_ocsp_status_resp(ngx_http_request_t *r, const unsigned char *resp, size_t resp_len, char **err); ]] local _M = { version = base.version } function _M.get_ocsp_responder_from_der_chain(certs, maxlen) local buf_size = maxlen if not buf_size then buf_size = get_string_buf_size() end local buf = get_string_buf(buf_size) local sizep = get_size_ptr() sizep[0] = buf_size local rc = C.ngx_http_lua_ffi_ssl_get_ocsp_responder_from_der_chain(certs, #certs, buf, sizep, errmsg) if rc == FFI_DECLINED then return nil end if rc == FFI_OK then return ffi_str(buf, sizep[0]) end if rc == FFI_BUSY then return ffi_str(buf, sizep[0]), "truncated" end return nil, ffi_str(errmsg[0]) end function _M.create_ocsp_request(certs, maxlen) local buf_size = maxlen if not buf_size then buf_size = get_string_buf_size() end local buf = get_string_buf(buf_size) local sizep = get_size_ptr() sizep[0] = buf_size local rc = C.ngx_http_lua_ffi_ssl_create_ocsp_request(certs, #certs, buf, sizep, errmsg) if rc == FFI_OK then return ffi_str(buf, sizep[0]) end if rc == FFI_BUSY then return nil, ffi_str(errmsg[0]) .. ": " .. tonumber(sizep[0]) .. " > " .. buf_size end return nil, ffi_str(errmsg[0]) end local next_update_p = ffi_new("long[1]") function _M.validate_ocsp_response(resp, chain, max_errmsg_len) local errbuf_size = max_errmsg_len if not errbuf_size then errbuf_size = get_string_buf_size() end local errbuf = get_string_buf(errbuf_size) local sizep = get_size_ptr() sizep[0] = errbuf_size next_update_p[0] = 0 local rc = C.ngx_http_lua_ffi_ssl_validate_ocsp_response(resp, #resp, chain, #chain, errbuf, sizep, next_update_p) if rc == FFI_OK then local next_update = tonumber(next_update_p[0]) if next_update == 0 then next_update = nil end return true, next_update end -- rc == FFI_ERROR return nil, ffi_str(errbuf, sizep[0]) end function _M.set_ocsp_status_resp(ocsp_resp) local r = get_request() if not r then error("no request found") end local rc = C.ngx_http_lua_ffi_ssl_set_ocsp_status_resp(r, ocsp_resp, #ocsp_resp, errmsg) if rc == FFI_DECLINED then -- no client status req return true, "no status req" end if rc == FFI_OK then return true end -- rc == FFI_ERROR return nil, ffi_str(errmsg[0]) end return _M lua-resty-core-0.1.31/lib/ngx/ocsp.md000066400000000000000000000245761474236722600173320ustar00rootroot00000000000000Name ==== ngx.ocsp - Lua API for implementing OCSP stapling in ssl_certificate_by_lua* Table of Contents ================= * [Name](#name) * [Status](#status) * [Synopsis](#synopsis) * [Description](#description) * [Methods](#methods) * [get_ocsp_responder_from_der_chain](#get_ocsp_responder_from_der_chain) * [create_ocsp_request](#create_ocsp_request) * [validate_ocsp_response](#validate_ocsp_response) * [set_ocsp_status_resp](#set_ocsp_status_resp) * [Community](#community) * [English Mailing List](#english-mailing-list) * [Chinese Mailing List](#chinese-mailing-list) * [Bugs and Patches](#bugs-and-patches) * [Author](#author) * [Copyright and License](#copyright-and-license) * [See Also](#see-also) Status ====== This Lua module is production ready. Synopsis ======== ```nginx # Note: you do not need the following line if you are using # OpenResty 1.9.7.2+. lua_package_path "/path/to/lua-resty-core/lib/?.lua;;"; server { listen 443 ssl; server_name test.com; # useless placeholders: just to shut up NGINX configuration # loader errors: ssl_certificate /path/to/fallback.crt; ssl_certificate_key /path/to/fallback.key; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ocsp = require "ngx.ocsp" local http = require "resty.http.simple" -- assuming the user already defines the my_load_certificate_chain() -- herself. local pem_cert_chain = assert(my_load_certificate_chain()) local der_cert_chain, err = ssl.cert_pem_to_der(pem_cert_chain) if not der_cert_chain then ngx.log(ngx.ERR, "failed to convert certificate chain ", "from PEM to DER: ", err) return ngx.exit(ngx.ERROR) end local ocsp_url, err = ocsp.get_ocsp_responder_from_der_chain(der_cert_chain) if not ocsp_url then ngx.log(ngx.ERR, "failed to get OCSP responder: ", err) return ngx.exit(ngx.ERROR) end print("ocsp_url: ", ocsp_url) -- use cosocket-based HTTP client libraries like lua-resty-http-simple -- to send the request (url + ocsp_req as POST params or URL args) to -- CA's OCSP server. assuming the server returns the OCSP response -- in the Lua variable, resp. local schema, host, port, ocsp_uri, err = parse_url(ocsp_url) local ocsp_req, err = ocsp.create_ocsp_request(der_cert_chain) if not ocsp_req then ngx.log(ngx.ERR, "failed to create OCSP request: ", err) return ngx.exit(ngx.ERROR) end local res, err = http.request(host, port, { path = ocsp_uri, headers = { Host = host, ["Content-Type"] = "application/ocsp-request" }, timeout = 10000, -- 10 sec method = "POST", body = ocsp_req, maxsize = 102400, -- 100KB }) if not res then ngx.log(ngx.ERR, "OCSP responder query failed: ", err) return ngx.exit(ngx.ERROR) end local http_status = res.status if http_status ~= 200 then ngx.log(ngx.ERR, "OCSP responder returns bad HTTP status code ", http_status) return ngx.exit(ngx.ERROR) end local ocsp_resp = res.body if ocsp_resp and #ocsp_resp > 0 then local ok, err = ocsp.validate_ocsp_response(ocsp_resp, der_cert_chain) if not ok then ngx.log(ngx.ERR, "failed to validate OCSP response: ", err) return ngx.exit(ngx.ERROR) end -- set the OCSP stapling ok, err = ocsp.set_ocsp_status_resp(ocsp_resp) if not ok then ngx.log(ngx.ERR, "failed to set ocsp status resp: ", err) return ngx.exit(ngx.ERROR) end end } location / { root html; } } ``` Description =========== This Lua module provides API to perform OCSP queries, OCSP response validations, and OCSP stapling planting. Usually, this module is used together with the [ngx.ssl](ssl.md) module in the context of [ssl_certificate_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_certificate_by_lua_block) (of the [ngx_lua](https://github.com/openresty/lua-nginx-module#readme) module). To load the `ngx.ocsp` module in Lua, just write ```lua local ocsp = require "ngx.ocsp" ``` [Back to TOC](#table-of-contents) Methods ======= get_ocsp_responder_from_der_chain --------------------------------- **syntax:** *ocsp_url, err = ocsp.get_ocsp_responder_from_der_chain(der_cert_chain, max_len)* **context:** *any* Extracts the OCSP responder URL (like `"http://test.com/ocsp/"`) from the SSL server certificate chain in the DER format. Usually the SSL server certificate chain is originally formatted in PEM. You can use the Lua API provided by the [ngx.ssl](ssl.md) module to do the PEM to DER conversion. The optional `max_len` argument specifies the maximum length of OCSP URL allowed. This determines the buffer size; so do not specify an unnecessarily large value here. It defaults to the internal string buffer size used throughout this `lua-resty-core` library (usually default to 4KB). In case of failures, returns `nil` and a string describing the error. [Back to TOC](#table-of-contents) create_ocsp_request ------------------- **syntax:** *ocsp_req, err = ocsp.create_ocsp_request(der_cert_chain, max_len)* **context:** *any* Builds an OCSP request from the SSL server certificate chain in the DER format, which can be used to send to the OCSP server for validation. The optional `max_len` argument specifies the maximum length of the OCSP request allowed. This value determines the size of the internal buffer allocated, so do not specify an unnecessarily large value here. It defaults to the internal string buffer size used throughout this `lua-resty-core` library (usually defaults to 4KB). In case of failures, returns `nil` and a string describing the error. The raw OCSP response data can be used as the request body directly if the POST method is used for the OCSP request. But for GET requests, you need to do base64 encoding and then URL encoding on the data yourself before appending it to the OCSP URL obtained by the [get_ocsp_responder_from_der_chain](#get_ocsp_responder_from_der_chain) function. [Back to TOC](#table-of-contents) validate_ocsp_response ---------------------- **syntax:** *ok, err = ocsp.validate_ocsp_response(ocsp_resp, der_cert_chain, max_err_msg_len)* **context:** *any* Validates the raw OCSP response data specified by the `ocsp_resp` argument using the SSL server certificate chain in DER format as specified in the `der_cert_chain` argument. Returns true when the validation is successful. In case of failures, returns `nil` and a string describing the failure. The maximum length of the error string is controlled by the optional `max_err_msg` argument (which defaults to the default internal string buffer size used throughout this `lua-resty-core` library, usually being 4KB). [Back to TOC](#table-of-contents) set_ocsp_status_resp -------------------- **syntax:** *ok, err = ocsp.set_ocsp_status_resp(ocsp_resp)* **context:** *ssl_certificate_by_lua** Sets the OCSP response as the OCSP stapling for the current SSL connection. Returns `true` in case of successes. If the SSL client does not send a "status request" at all, then this method still returns `true` but also with a string as the warning `"no status req"`. In case of failures, returns `nil` and a string describing the error. The OCSP response is returned from CA's OCSP server. See the [create_ocsp_request](#create_ocsp_request) function for how to create an OCSP request and also [validate_ocsp_response](#validate_ocsp_response) for how to validate the OCSP response. [Back to TOC](#table-of-contents) Community ========= [Back to TOC](#table-of-contents) English Mailing List -------------------- The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. [Back to TOC](#table-of-contents) Chinese Mailing List -------------------- The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. [Back to TOC](#table-of-contents) Bugs and Patches ================ Please report bugs or submit patches by 1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), 1. or posting to the [OpenResty community](#community). [Back to TOC](#table-of-contents) Author ====== Yichun Zhang <agentzh@gmail.com> (agentzh), OpenResty Inc. [Back to TOC](#table-of-contents) Copyright and License ===================== This module is licensed under the BSD license. Copyright (C) 2015-2017, by Yichun "agentzh" Zhang, OpenResty Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * 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. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [Back to TOC](#table-of-contents) See Also ======== * the ngx_lua module: https://github.com/openresty/lua-nginx-module * the [ngx.ssl](ssl.md) module. * the [ssl_certificate_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_certificate_by_lua_block) directive. * the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. * OpenResty: https://openresty.org [Back to TOC](#table-of-contents) lua-resty-core-0.1.31/lib/ngx/pipe.lua000066400000000000000000000462171474236722600175000ustar00rootroot00000000000000-- Copyright (C) by OpenResty Inc. local base = require "resty.core.base" base.allows_subsystem("http") require "resty.core.phase" -- for ngx.get_phase local assert = assert local error = error local ipairs = ipairs local tonumber = tonumber local tostring = tostring local type = type local str_find = string.find local table_concat = table.concat local ffi = require "ffi" local C = ffi.C local ffi_new = ffi.new local ffi_str = ffi.string local ngx_phase = ngx.get_phase local get_string_buf = base.get_string_buf local get_size_ptr = base.get_size_ptr local get_request = base.get_request local FFI_AGAIN = base.FFI_AGAIN local FFI_BAD_CONTEXT = base.FFI_BAD_CONTEXT local FFI_DECLINED = base.FFI_DECLINED local FFI_ERROR = base.FFI_ERROR local FFI_NO_REQ_CTX = base.FFI_NO_REQ_CTX local FFI_OK = base.FFI_OK local co_yield = coroutine._yield ffi.cdef[[ typedef int ngx_pid_t; typedef uintptr_t ngx_msec_t; typedef unsigned char u_char; typedef struct ngx_http_lua_pipe_s ngx_http_lua_pipe_t; typedef struct { ngx_pid_t _pid; ngx_msec_t write_timeout; ngx_msec_t stdout_read_timeout; ngx_msec_t stderr_read_timeout; ngx_msec_t wait_timeout; ngx_http_lua_pipe_t *pipe; } ngx_http_lua_ffi_pipe_proc_t; int ngx_http_lua_ffi_pipe_spawn(ngx_http_request_t *r, ngx_http_lua_ffi_pipe_proc_t *proc, const char *file, const char **argv, int merge_stderr, size_t buffer_size, const char **environ, u_char *errbuf, size_t *errbuf_size); int ngx_http_lua_ffi_pipe_proc_read(ngx_http_request_t *r, ngx_http_lua_ffi_pipe_proc_t *proc, int from_stderr, int reader_type, size_t length, u_char **buf, size_t *buf_size, u_char *errbuf, size_t *errbuf_size); int ngx_http_lua_ffi_pipe_get_read_result(ngx_http_request_t *r, ngx_http_lua_ffi_pipe_proc_t *proc, int from_stderr, u_char **buf, size_t *buf_size, u_char *errbuf, size_t *errbuf_size); ssize_t ngx_http_lua_ffi_pipe_proc_write(ngx_http_request_t *r, ngx_http_lua_ffi_pipe_proc_t *proc, const u_char *data, size_t len, u_char *errbuf, size_t *errbuf_size); ssize_t ngx_http_lua_ffi_pipe_get_write_result(ngx_http_request_t *r, ngx_http_lua_ffi_pipe_proc_t *proc, u_char *errbuf, size_t *errbuf_size); int ngx_http_lua_ffi_pipe_proc_shutdown_stdin( ngx_http_lua_ffi_pipe_proc_t *proc, u_char *errbuf, size_t *errbuf_size); int ngx_http_lua_ffi_pipe_proc_shutdown_stdout( ngx_http_lua_ffi_pipe_proc_t *proc, u_char *errbuf, size_t *errbuf_size); int ngx_http_lua_ffi_pipe_proc_shutdown_stderr( ngx_http_lua_ffi_pipe_proc_t *proc, u_char *errbuf, size_t *errbuf_size); int ngx_http_lua_ffi_pipe_proc_wait(ngx_http_request_t *r, ngx_http_lua_ffi_pipe_proc_t *proc, char **reason, int *status, u_char *errbuf, size_t *errbuf_size); int ngx_http_lua_ffi_pipe_proc_kill(ngx_http_lua_ffi_pipe_proc_t *proc, int signal, u_char *errbuf, size_t *errbuf_size); void ngx_http_lua_ffi_pipe_proc_destroy(ngx_http_lua_ffi_pipe_proc_t *proc); ]] if not pcall(function() return C.ngx_http_lua_ffi_pipe_spawn end) then error("pipe API is not supported due to either a platform issue " .. "or lack of the HAVE_SOCKET_CLOEXEC_PATCH patch", 2) end local _M = { version = base.version } local ERR_BUF_SIZE = 256 local VALUE_BUF_SIZE = 512 local PIPE_READ_ALL = 0 local PIPE_READ_BYTES = 1 local PIPE_READ_LINE = 2 local PIPE_READ_ANY = 3 local proc_set_timeouts do local MAX_TIMEOUT = 0xffffffff function proc_set_timeouts(proc, write_timeout, stdout_read_timeout, stderr_read_timeout, wait_timeout) -- the implementation below is straightforward but could not be JIT -- compiled by the latest LuaJIT. When called in loops, LuaJIT will try -- to unroll it, and fall back to interpreter after it reaches the -- unroll limit. --[[ local function set_timeout(proc, attr, timeout) if timeout then if timeout > MAX_TIMEOUT then error("bad timeout value", 3) end proc[attr] = timeout end end set_timeout(...) ]] if write_timeout then if write_timeout < 0 or MAX_TIMEOUT < write_timeout then error("bad write_timeout option", 3) end proc.write_timeout = write_timeout end if stdout_read_timeout then if stdout_read_timeout < 0 or MAX_TIMEOUT < stdout_read_timeout then error("bad stdout_read_timeout option", 3) end proc.stdout_read_timeout = stdout_read_timeout end if stderr_read_timeout then if stderr_read_timeout < 0 or MAX_TIMEOUT < stderr_read_timeout then error("bad stderr_read_timeout option", 3) end proc.stderr_read_timeout = stderr_read_timeout end if wait_timeout then if wait_timeout < 0 or MAX_TIMEOUT < wait_timeout then error("bad wait_timeout option", 3) end proc.wait_timeout = wait_timeout end end end local function check_proc_instance(proc) if type(proc) ~= "cdata" then error("not a process instance", 3) end end local proc_read do local value_buf = ffi_new("char[?]", VALUE_BUF_SIZE) local buf = ffi_new("char *[1]") local buf_size = ffi_new("size_t[1]") function proc_read(proc, stderr, reader_type, len) check_proc_instance(proc) local r = get_request() if not r then error("no request found") end buf[0] = value_buf buf_size[0] = VALUE_BUF_SIZE local errbuf = get_string_buf(ERR_BUF_SIZE) local errbuf_size = get_size_ptr() errbuf_size[0] = ERR_BUF_SIZE local rc = C.ngx_http_lua_ffi_pipe_proc_read(r, proc, stderr, reader_type, len, buf, buf_size, errbuf, errbuf_size) if rc == FFI_NO_REQ_CTX then error("no request ctx found") end if rc == FFI_BAD_CONTEXT then error(ffi_str(errbuf, errbuf_size[0]), 2) end while true do if rc == FFI_ERROR then return nil, ffi_str(errbuf, errbuf_size[0]) end if rc == FFI_OK then local p = buf[0] if p ~= value_buf then p = ffi_new("char[?]", buf_size[0]) buf[0] = p C.ngx_http_lua_ffi_pipe_get_read_result(r, proc, stderr, buf, buf_size, errbuf, errbuf_size) assert(p == buf[0]) end return ffi_str(p, buf_size[0]) end if rc == FFI_DECLINED then local err = ffi_str(errbuf, errbuf_size[0]) local p = buf[0] if p ~= value_buf then p = ffi_new("char[?]", buf_size[0]) buf[0] = p C.ngx_http_lua_ffi_pipe_get_read_result(r, proc, stderr, buf, buf_size, errbuf, errbuf_size) assert(p == buf[0]) end local partial = ffi_str(p, buf_size[0]) return nil, err, partial end assert(rc == FFI_AGAIN) co_yield() buf[0] = value_buf buf_size[0] = VALUE_BUF_SIZE errbuf = get_string_buf(ERR_BUF_SIZE) errbuf_size = get_size_ptr() errbuf_size[0] = ERR_BUF_SIZE rc = C.ngx_http_lua_ffi_pipe_get_read_result(r, proc, stderr, buf, buf_size, errbuf, errbuf_size) end end end local function proc_write(proc, data) check_proc_instance(proc) local r = get_request() if not r then error("no request found", 2) end local data_type = type(data) if data_type ~= "string" then if data_type == "table" then data = table_concat(data, "") elseif data_type == "number" then data = tostring(data) else error("bad data arg: string, number, or table expected, got " .. data_type, 2) end end local errbuf = get_string_buf(ERR_BUF_SIZE) local errbuf_size = get_size_ptr() errbuf_size[0] = ERR_BUF_SIZE local rc = C.ngx_http_lua_ffi_pipe_proc_write(r, proc, data, #data, errbuf, errbuf_size) if rc == FFI_NO_REQ_CTX then error("no request ctx found", 2) end if rc == FFI_BAD_CONTEXT then error(ffi_str(errbuf, errbuf_size[0]), 2) end while true do if rc == FFI_ERROR then return nil, ffi_str(errbuf, errbuf_size[0]) end if rc >= 0 then -- rc holds the bytes sent return tonumber(rc) end assert(rc == FFI_AGAIN) co_yield() errbuf = get_string_buf(ERR_BUF_SIZE) errbuf_size = get_size_ptr() errbuf_size[0] = ERR_BUF_SIZE rc = C.ngx_http_lua_ffi_pipe_get_write_result(r, proc, errbuf, errbuf_size) end end local function proc_shutdown(proc, direction) check_proc_instance(proc) local rc local errbuf = get_string_buf(ERR_BUF_SIZE) local errbuf_size = get_size_ptr() errbuf_size[0] = ERR_BUF_SIZE if direction == "stdin" then rc = C.ngx_http_lua_ffi_pipe_proc_shutdown_stdin(proc, errbuf, errbuf_size) elseif direction == "stdout" then rc = C.ngx_http_lua_ffi_pipe_proc_shutdown_stdout(proc, errbuf, errbuf_size) elseif direction == "stderr" then rc = C.ngx_http_lua_ffi_pipe_proc_shutdown_stderr(proc, errbuf, errbuf_size) else error("bad shutdown arg: " .. direction, 2) end if rc == FFI_ERROR then return nil, ffi_str(errbuf, errbuf_size[0]) end return true end local proc_wait do local reason = ffi_new("char *[1]") local status = ffi_new("int[1]") function proc_wait(proc) check_proc_instance(proc) local r = get_request() if not r then error("no request found", 2) end local errbuf = get_string_buf(ERR_BUF_SIZE) local errbuf_size = get_size_ptr() errbuf_size[0] = ERR_BUF_SIZE local rc = C.ngx_http_lua_ffi_pipe_proc_wait(r, proc, reason, status, errbuf, errbuf_size) if rc == FFI_NO_REQ_CTX then error("no request ctx found", 2) end if rc == FFI_BAD_CONTEXT then error(ffi_str(errbuf, errbuf_size[0]), 2) end if rc == FFI_ERROR then return nil, ffi_str(errbuf, errbuf_size[0]) end if rc == FFI_OK then return true, ffi_str(reason[0]), tonumber(status[0]) end if rc == FFI_DECLINED then return false, ffi_str(reason[0]), tonumber(status[0]) end local ok, exit_reason, exit_status ok, exit_reason, exit_status = co_yield() return ok, exit_reason, exit_status end end local function proc_kill(proc, signal) check_proc_instance(proc) if type(signal) ~= "number" then error("bad signal arg: number expected, got " .. tostring(signal), 2) end local errbuf = get_string_buf(ERR_BUF_SIZE) local errbuf_size = get_size_ptr() errbuf_size[0] = ERR_BUF_SIZE local rc = C.ngx_http_lua_ffi_pipe_proc_kill(proc, signal, errbuf, errbuf_size) if rc == FFI_ERROR then return nil, ffi_str(errbuf, errbuf_size[0]) end return true end local mt = { __gc = C.ngx_http_lua_ffi_pipe_proc_destroy, __index = { pid = function (proc) return proc._pid end, set_timeouts = function (proc, write_timeout, stdout_read_timeout, stderr_read_timeout, wait_timeout) proc_set_timeouts(proc, write_timeout, stdout_read_timeout, stderr_read_timeout, wait_timeout) end, stdout_read_all = function (proc) local data, err, partial = proc_read(proc, 0, PIPE_READ_ALL, 0) return data, err, partial end, stdout_read_bytes = function (proc, len) if len <= 0 then if len < 0 then error("bad len argument", 2) end return "" end local data, err, partial = proc_read(proc, 0, PIPE_READ_BYTES, len) return data, err, partial end, stdout_read_line = function (proc) local data, err, partial = proc_read(proc, 0, PIPE_READ_LINE, 0) return data, err, partial end, stdout_read_any = function (proc, max) if type(max) ~= "number" then max = tonumber(max) end if not max or max <= 0 then error("bad max argument", 2) end local data, err, partial = proc_read(proc, 0, PIPE_READ_ANY, max) return data, err, partial end, stderr_read_all = function (proc) local data, err, partial = proc_read(proc, 1, PIPE_READ_ALL, 0) return data, err, partial end, stderr_read_bytes = function (proc, len) if len <= 0 then if len < 0 then error("bad len argument", 2) end return "" end local data, err, partial = proc_read(proc, 1, PIPE_READ_BYTES, len) return data, err, partial end, stderr_read_line = function (proc) local data, err, partial = proc_read(proc, 1, PIPE_READ_LINE, 0) return data, err, partial end, stderr_read_any = function (proc, max) if type(max) ~= "number" then max = tonumber(max) end if not max or max <= 0 then error("bad max argument", 2) end local data, err, partial = proc_read(proc, 1, PIPE_READ_ANY, max) return data, err, partial end, write = proc_write, shutdown = proc_shutdown, wait = proc_wait, kill = proc_kill, } } local Proc = ffi.metatype("ngx_http_lua_ffi_pipe_proc_t", mt) local pipe_spawn do local sh_exe = "/bin/sh" local opt_c = "-c" local shell_args = ffi_new("const char* [?]", 4) shell_args[0] = sh_exe shell_args[1] = opt_c shell_args[3] = nil local write_timeout = 10000 local stdout_read_timeout = 10000 local stderr_read_timeout = 10000 local wait_timeout = 10000 -- reference shell cmd's constant strings here to prevent them from getting -- collected by the Lua GC. _M._gc_ref_c_opt = opt_c function pipe_spawn(args, opts) if ngx_phase() == "init" then error("API disabled in the current context", 2) end local exe local proc_args local proc_envs local args_type = type(args) if args_type == "table" then local nargs = 0 for i, arg in ipairs(args) do nargs = nargs + 1 if type(arg) ~= "string" then args[i] = tostring(arg) end end if nargs == 0 then error("bad args arg: non-empty table expected", 2) end exe = args[1] proc_args = ffi_new("const char* [?]", nargs + 1, args) proc_args[nargs] = nil elseif args_type == "string" then exe = sh_exe shell_args[2] = args proc_args = shell_args else error("bad args arg: table expected, got " .. args_type, 2) end local merge_stderr = 0 local buffer_size = 4096 local proc = Proc() if opts then merge_stderr = opts.merge_stderr and 1 or 0 if opts.buffer_size then buffer_size = tonumber(opts.buffer_size) if not buffer_size or buffer_size < 1 then error("bad buffer_size option", 2) end end if opts.environ then local environ = opts.environ local environ_type = type(environ) if environ_type ~= "table" then error("bad environ option: table expected, got " .. environ_type, 2) end local nenv = 0 for i, env in ipairs(environ) do nenv = nenv + 1 local env_type = type(env) if env_type ~= "string" then error("bad value at index " .. i .. " of environ " .. "option: string expected, got " .. env_type, 2) end if not str_find(env, "=", 2, true) then error("bad value at index " .. i .. " of environ " .. "option: 'name=[value]' format expected, got '" .. env .. "'", 2) end end if nenv > 0 then proc_envs = ffi_new("const char* [?]", nenv + 1, environ) proc_envs[nenv] = nil end end proc_set_timeouts(proc, opts.write_timeout or write_timeout, opts.stdout_read_timeout or stdout_read_timeout, opts.stderr_read_timeout or stderr_read_timeout, opts.wait_timeout or wait_timeout) else proc_set_timeouts(proc, write_timeout, stdout_read_timeout, stderr_read_timeout, wait_timeout) end local errbuf = get_string_buf(ERR_BUF_SIZE) local errbuf_size = get_size_ptr() local r = get_request() errbuf_size[0] = ERR_BUF_SIZE local rc = C.ngx_http_lua_ffi_pipe_spawn(r, proc, exe, proc_args, merge_stderr, buffer_size, proc_envs, errbuf, errbuf_size) if rc == FFI_ERROR then return nil, ffi_str(errbuf, errbuf_size[0]) end return proc end end -- do _M.spawn = pipe_spawn return _M lua-resty-core-0.1.31/lib/ngx/pipe.md000066400000000000000000000450361474236722600173150ustar00rootroot00000000000000Name ==== `ngx.pipe` - spawn and communicate with OS processes via stdin/stdout/stderr in a non-blocking fashion. Table of Contents ================= * [Name](#name) * [Status](#status) * [Synopsis](#synopsis) * [Description](#description) * [Methods](#methods) * [spawn](#spawn) * [set_timeouts](#set_timeouts) * [wait](#wait) * [pid](#pid) * [kill](#kill) * [shutdown](#shutdown) * [write](#write) * [stderr_read_all](#stderr_read_all) * [stdout_read_all](#stdout_read_all) * [stderr_read_line](#stderr_read_line) * [stdout_read_line](#stdout_read_line) * [stderr_read_bytes](#stderr_read_bytes) * [stdout_read_bytes](#stdout_read_bytes) * [stderr_read_any](#stderr_read_any) * [stdout_read_any](#stdout_read_any) * [Community](#community) * [English Mailing List](#english-mailing-list) * [Chinese Mailing List](#chinese-mailing-list) * [Bugs and Patches](#bugs-and-patches) * [Copyright and License](#copyright-and-license) * [See Also](#see-also) Status ====== This Lua module is production ready. Synopsis ======== ```nginx location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local select = select local function count_char(...) local proc = ngx_pipe.spawn({'wc', '-c'}) local n = select('#', ...) for i = 1, n do local arg = select(i, ...) local bytes, err = proc:write(arg) if not bytes then ngx.say(err) return end end local ok, err = proc:shutdown('stdin') if not ok then ngx.say(err) return end local data, err = proc:stdout_read_line() if not data then ngx.say(err) return end ngx.say(data) end count_char(("1234"):rep(2048)) } } ``` This example counts characters (bytes) directly fed by OpenResty to the UNIX command `wc`. You could not do this with either `io.popen` or `os.execute` because `wc` will not output the result until its stdin is closed. [Back to TOC](#table-of-contents) Description =========== This module does not support non-POSIX operating systems like Windows yet. If you are not using the Nginx core shipped with OpenResty, you will need to apply the `socket_cloexec` patch to the standard Nginx core. Under the hood, this module uses `fork` and `execvp` with the user-specified command, and communicate with such spawned processes via the POSIX `pipe` API, which contributes to the name of this module. A signal handler for `SIGCHLD` is registered so that we can receive a notification once the spawned processes exited. We combine the above implementation with Nginx's event mechanism and OpenResty's Lua coroutine scheduler, in order to ensure communication with the spawned processes is non-blocking. The communication APIs do not work in phases which do not support yielding, such as `init_worker_by_lua*` or `log_by_lua*`, because there is no way to yield the current light thread to avoid blocking the OS thread when communicating with processes in those phases. [Back to TOC](#table-of-contents) Methods ======= spawn ----- **syntax:** *proc, err = pipe_module.spawn(args, opts?)* **context:** *all phases except init_by_lua** Creates and returns a new sub-process instance we can communicate with later. For example: ```lua local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn({"sh", "-c", "sleep 0.1 && exit 2"}) if not proc then ngx.say(err) return end ``` In case of failure, this function returns `nil` and a string describing the error. The sub-process will be killed via `SIGKILL` if it is still alive when the instance is collected by the garbage collector. Note that `args` should either be a single level array-like Lua table with string values, or just a single string. Some more examples: ```lua local proc, err = ngx_pipe.spawn({"ls", "-l"}) local proc, err = ngx_pipe.spawn({"perl", "-e", "print 'hello, wolrd'"}) ``` If `args` is specified as a string, it will be executed by the operating system shell, just like `os.execute`. The above example could thus be rewritten as: ```lua local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn("sleep 0.1 && exit 2") if not proc then ngx.say(err) return end ``` In the shell mode, you should be very careful about shell injection attacks when interpolating variables into command string, especially variables from untrusted sources. Please make sure that you escape those variables while assembling the command string. For this reason, it is highly recommended to use the multi-arguments form (`args` as a table) to specify each command-line argument explicitly. Since by default, Nginx does not pass along the `PATH` system environment variable, you will need to configure the `env PATH` directive if you wish for it to be respected during the searching of sub-processes: ```nginx env PATH; ... content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({'ls'}) } ``` The optional table argument `opts` can be used to control the behavior of spawned processes. For instance: ```lua local opts = { merge_stderr = true, buffer_size = 256, environ = {"PATH=/tmp/bin", "CWD=/tmp/work"} } local proc, err = ngx_pipe.spawn({"sh", "-c", ">&2 echo data"}, opts) if not proc then ngx.say(err) return end ``` The following options are supported: * `merge_stderr`: when set to `true`, the output to stderr will be redirected to stdout in the spawned process. This is similar to doing `2>&1` in a shell. * `buffer_size`: specifies the buffer size used by reading operations, in bytes. The default buffer size is `4096`. * `environ`: specifies environment variables for the spawned process. The value must be a single-level, array-like Lua table with string values. If the current platform does not support this option, `nil` plus a string `"environ option not supported"` will be returned. * `write_timeout`: specifies the write timeout threshold, in milliseconds. The default threshold is `10000`. If the threshold is `0`, the write operation will never time out. * `stdout_read_timeout`: specifies the stdout read timeout threshold, in milliseconds. The default threshold is `10000`. If the threshold is `0`, the stdout read operation will never time out. * `stderr_read_timeout`: specifies the stderr read timeout threshold, in milliseconds. The default threshold is `10000`. If the threshold is `0`, the stderr read operation will never time out. * `wait_timeout`: specifies the wait timeout threshold, in milliseconds. The default threshold is `10000`. If the threshold is `0`, the wait operation will never time out. [Back to TOC](#table-of-contents) set_timeouts ------------ **syntax:** *proc:set_timeouts(write_timeout?, stdout_read_timeout?, stderr_read_timeout?, wait_timeout?)* Respectively sets: the write timeout threshold, stdout read timeout threshold, stderr read timeout threshold, and wait timeout threshold. All timeouts are in milliseconds. The default threshold for each timeout is 10 seconds. If the specified timeout argument is `nil`, the corresponding timeout threshold will not be changed. For example: ```lua local proc, err = ngx_pipe.spawn({"sleep", "10s"}) -- only change the wait_timeout to 0.1 second. proc:set_timeouts(nil, nil, nil, 100) -- only change the send_timeout to 0.1 second. proc:set_timeouts(100) ``` If the specified timeout argument is `0`, the corresponding operation will never time out. [Back to TOC](#table-of-contents) wait ---- **syntax:** *ok, reason, status = proc:wait()* **context:** *phases that support yielding* Waits until the current sub-process exits. It is possible to control how long to wait via [set_timeouts](#set_timeouts). The default timeout is 10 seconds. If process exited with status code zero, the `ok` return value will be `true`. If process exited abnormally, the `ok` return value will be `false`. The second return value, `reason`, will be a string. Its values may be: * `exit`: the process exited by calling `exit(3)`, `_exit(2)`, or by returning from `main()`. In this case, `status` will be the exit code. * `signal`: the process was terminated by a signal. In this case, `status` will be the signal number. Note that only one light thread can wait on a process at a time. If another light thread tries to wait on a process, the return values will be `nil` and the error string `"pipe busy waiting"`. If a thread tries to wait an exited process, the return values will be `nil` and the error string `"exited"`. [Back to TOC](#table-of-contents) pid --- **syntax:** *pid = proc:pid()* Returns the pid number of the sub-process. [Back to TOC](#table-of-contents) kill ---- **syntax:** *ok, err = proc:kill(signum)* Sends a signal to the sub-process. Note that the `signum` argument should be signal's numerical value. If the specified `signum` is not a number, an error will be thrown. You should use [lua-resty-signal's signum() function](https://github.com/openresty/lua-resty-signal#signum) to convert signal names to signal numbers in order to ensure portability of your application. In case of success, this method returns `true`. Otherwise, it returns `nil` and a string describing the error. Killing an exited sub-process will return `nil` and the error string `"exited"`. Sending an invalid signal to the process will return `nil` and the error string `"invalid signal"`. [Back to TOC](#table-of-contents) shutdown -------- **syntax:** *ok, err = proc:shutdown(direction)* Closes the specified direction of the current sub-process. The `direction` argument should be one of these three values: `stdin`, `stdout` and `stderr`. In case of success, this method returns `true`. Otherwise, it returns `nil` and a string describing the error. If the `merge_stderr` option is specified in [spawn](#spawn), closing the `stderr` direction will return `nil` and the error string `"merged to stdout"`. Shutting down a direction when a light thread is waiting on it (such as during reading or writing) will abort the light thread and return `true`. Shutting down directions of an exited process will return `nil` and the error string `"closed"`. It is fine to shut down the same direction of the same stream multiple times; no side effects are to be expected. [Back to TOC](#table-of-contents) write ----- **syntax:** *nbytes, err = proc:write(data)* **context:** *phases that support yielding* Writes data to the current sub-process's stdin stream. The `data` argument can be a string or a single level array-like Lua table with string values. This method is a synchronous and non-blocking operation that will not return until *all* the data has been flushed to the sub-process's stdin buffer, or an error occurs. In case of success, it returns the total number of bytes that have been sent. Otherwise, it returns `nil` and a string describing the error. The timeout threshold of this `write` operation can be controlled by the [set_timeouts](#set_timeouts) method. The default timeout threshold is 10 seconds. When a timeout occurs, the data may be partially written into the sub-process's stdin buffer and read by the sub-process. Only one light thread is allowed to write to the sub-process at a time. If another light thread tries to write to it, this method will return `nil` and the error string `"pipe busy writing"`. If the `write` operation is aborted by the [shutdown](#shutdown) method, it will return `nil` and the error string `"aborted"`. Writing to an exited sub-process will return `nil` and the error string `"closed"`. [Back to TOC](#table-of-contents) stderr_read_all --------------- **syntax:** *data, err, partial = proc:stderr_read_all()* **context:** *phases that support yielding* Reads all data from the current sub-process's stderr stream until it is closed. This method is a synchronous and non-blocking operation, just like the [write](#write) method. The timeout threshold of this reading operation can be controlled by [set_timeouts](#set_timeouts). The default timeout is 10 seconds. In case of success, it returns the data received. Otherwise, it returns three values: `nil`, a string describing the error, and, optionally, the partial data received so far. When `merge_stderr` is specified in [spawn](#spawn), calling `stderr_read_all` will return `nil` and the error string `"merged to stdout"`. Only one light thread is allowed to read from a sub-process's stderr or stdout stream at a time. If another thread tries to read from the same stream, this method will return `nil` and the error string `"pipe busy reading"`. If the reading operation is aborted by the [shutdown](#shutdown) method, it will return `nil` and the error string `"aborted"`. Streams for stdout and stderr are separated, so at most two light threads may be reading from a sub-process at a time (one for each stream). The same way, a light thread may read from a stream while another light thread is writing to the sub-process stdin stream. Reading from an exited process's stream will return `nil` and the error string `"closed"`. [Back to TOC](#table-of-contents) stdout_read_all --------------- **syntax:** *data, err, partial = proc:stdout_read_all()* **context:** *phases that support yielding* Similar to the [stderr_read_all](#stderr_read_all) method, but reading from the stdout stream of the sub-process. [Back to TOC](#table-of-contents) stderr_read_line ---------------- **syntax:** *data, err, partial = proc:stderr_read_line()* **context:** *phases that support yielding* Reads from stderr like [stderr_read_all](#stderr_read_all), but only reads a single line of data. When `merge_stderr` is specified in [spawn](#spawn), calling `stderr_read_line` will return `nil` plus the error string `"merged to stdout"`. When the data stream is truncated without a new-line character, it returns 3 values: `nil`, the error string `"closed"`, and the partial data received so far. The line should be terminated by a `Line Feed` (LF) character (ASCII 10), optionally preceded by a `Carriage Return` (CR) character (ASCII 13). The CR and LF characters are not included in the returned line data. [Back to TOC](#table-of-contents) stdout_read_line ---------------- **syntax:** *data, err, partial = proc:stdout_read_line()* **context:** *phases that support yielding* Similar to [stderr_read_line](#stderr_read_line), but reading from the stdout stream of the sub-process. [Back to TOC](#table-of-contents) stderr_read_bytes ----------------- **syntax:** *data, err, partial = proc:stderr_read_bytes(len)* **context:** *phases that support yielding* Reads from stderr like [stderr_read_all](#stderr_read_all), but only reads the specified number of bytes. If `merge_stderr` is specified in [spawn](#spawn), calling `stderr_read_bytes` will return `nil` plus the error string `"merged to stdout"`. If the data stream is truncated (fewer bytes of data available than requested), this method returns 3 values: `nil`, the error string `"closed"`, and the partial data string received so far. [Back to TOC](#table-of-contents) stdout_read_bytes ----------------- **syntax:** *data, err, partial = proc:stdout_read_bytes(len)* **context:** *phases that support yielding* Similar to [stderr_read_bytes](#stderr_read_bytes), but reading from the stdout stream of the sub-process. [Back to TOC](#table-of-contents) stderr_read_any --------------- **syntax:** *data, err = proc:stderr_read_any(max)* **context:** *phases that support yielding* Reads from stderr like [stderr_read_all](#stderr_read_all), but returns immediately when any amount of data is received. At most `max` bytes are received. If `merge_stderr` is specified in [spawn](#spawn), calling `stderr_read_any` will return `nil` plus the error string `"merged to stdout"`. If the received data is more than `max` bytes, this method will return with exactly `max` bytes of data. The remaining data in the underlying receive buffer can be fetched with a subsequent reading operation. [Back to TOC](#table-of-contents) stdout_read_any --------------- **syntax:** *data, err = proc:stdout_read_any(max)* **context:** *phases that support yielding* Similar to [stderr_read_any](#stderr_read_any), but reading from the stdout stream of the sub-process. [Back to TOC](#table-of-contents) Community ========= [Back to TOC](#table-of-contents) English Mailing List -------------------- The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. [Back to TOC](#table-of-contents) Chinese Mailing List -------------------- The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. [Back to TOC](#table-of-contents) Bugs and Patches ================ Please report bugs or submit patches by 1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), 1. or posting to the [OpenResty community](#community). [Back to TOC](#table-of-contents) Copyright and License ===================== This module is licensed under the BSD license. Copyright (C) 2018, by OpenResty Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * 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. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [Back to TOC](#table-of-contents) See Also ======== * the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. * the ngx_lua module: https://github.com/openresty/lua-nginx-module * OpenResty: https://openresty.org [Back to TOC](#table-of-contents) lua-resty-core-0.1.31/lib/ngx/process.lua000066400000000000000000000057101474236722600202120ustar00rootroot00000000000000-- Copyright (C) Yichun Zhang (agentzh) local base = require "resty.core.base" base.allows_subsystem('http', 'stream') local ffi = require 'ffi' local errmsg = base.get_errmsg_ptr() local FFI_ERROR = base.FFI_ERROR local ffi_str = ffi.string local tonumber = tonumber local subsystem = ngx.config.subsystem if subsystem == 'http' then require "resty.core.phase" -- for ngx.get_phase end local ngx_phase = ngx.get_phase local process_type_names = { [0 ] = "single", [1 ] = "master", [2 ] = "signaller", [3 ] = "worker", [4 ] = "helper", [99] = "privileged agent", } local C = ffi.C local _M = { version = base.version } local ngx_lua_ffi_enable_privileged_agent local ngx_lua_ffi_get_process_type local ngx_lua_ffi_process_signal_graceful_exit local ngx_lua_ffi_master_pid if subsystem == 'http' then ffi.cdef[[ int ngx_http_lua_ffi_enable_privileged_agent(char **err, unsigned int connections); int ngx_http_lua_ffi_get_process_type(void); void ngx_http_lua_ffi_process_signal_graceful_exit(void); int ngx_http_lua_ffi_master_pid(void); ]] ngx_lua_ffi_enable_privileged_agent = C.ngx_http_lua_ffi_enable_privileged_agent ngx_lua_ffi_get_process_type = C.ngx_http_lua_ffi_get_process_type ngx_lua_ffi_process_signal_graceful_exit = C.ngx_http_lua_ffi_process_signal_graceful_exit ngx_lua_ffi_master_pid = C.ngx_http_lua_ffi_master_pid else ffi.cdef[[ int ngx_stream_lua_ffi_enable_privileged_agent(char **err, unsigned int connections); int ngx_stream_lua_ffi_get_process_type(void); void ngx_stream_lua_ffi_process_signal_graceful_exit(void); int ngx_stream_lua_ffi_master_pid(void); ]] ngx_lua_ffi_enable_privileged_agent = C.ngx_stream_lua_ffi_enable_privileged_agent ngx_lua_ffi_get_process_type = C.ngx_stream_lua_ffi_get_process_type ngx_lua_ffi_process_signal_graceful_exit = C.ngx_stream_lua_ffi_process_signal_graceful_exit ngx_lua_ffi_master_pid = C.ngx_stream_lua_ffi_master_pid end function _M.type() local typ = ngx_lua_ffi_get_process_type() return process_type_names[tonumber(typ)] end function _M.enable_privileged_agent(connections) if ngx_phase() ~= "init" then return nil, "API disabled in the current context" end connections = connections or 512 if type(connections) ~= "number" or connections < 0 then return nil, "bad 'connections' argument: " .. "number expected and greater than 0" end local rc = ngx_lua_ffi_enable_privileged_agent(errmsg, connections) if rc == FFI_ERROR then return nil, ffi_str(errmsg[0]) end return true end function _M.signal_graceful_exit() ngx_lua_ffi_process_signal_graceful_exit() end function _M.get_master_pid() local pid = ngx_lua_ffi_master_pid() if pid == FFI_ERROR then return nil end return tonumber(pid) end return _M lua-resty-core-0.1.31/lib/ngx/process.md000066400000000000000000000161631474236722600200350ustar00rootroot00000000000000Name ==== `ngx.process` - manage the nginx processes for OpenResty/ngx_lua. Table of Contents ================= * [Name](#name) * [Status](#status) * [Synopsis](#synopsis) * [Functions](#functions) * [type](#type) * [enable_privileged_agent](#enable_privileged_agent) * [signal_graceful_exit](#signal_graceful_exit) * [get_master_pid](#get_master_pid) * [Community](#community) * [English Mailing List](#english-mailing-list) * [Chinese Mailing List](#chinese-mailing-list) * [Bugs and Patches](#bugs-and-patches) * [Author](#author) * [Copyright and License](#copyright-and-license) * [See Also](#see-also) Status ====== This Lua module is production ready. Synopsis ======== Enables privileged agent process, gets process type, and then gets the master process PID: ```nginx # http config init_by_lua_block { local process = require "ngx.process" -- enables privileged agent process local ok, err = process.enable_privileged_agent() if not ok then ngx.log(ngx.ERR, "enables privileged agent failed error:", err) end -- output process type ngx.log(ngx.INFO, "process type: ", process.type()) } init_worker_by_lua_block { local process = require "ngx.process" ngx.log(ngx.INFO, "process type: ", process.type()) } server { # ... location = /t { content_by_lua_block { local process = require "ngx.process" ngx.say("process type: ", process.type()) ngx.say("master process pid: ", process.get_master_pid() or "-") } } } ``` The example config above produces an output to `error.log` when server starts: ``` [lua] init_by_lua:11: process type: master [lua] init_worker_by_lua:3: process type: privileged agent [lua] init_worker_by_lua:3: process type: worker ``` The example location above produces the following response body: ``` process type: worker master process pid: 8261 ``` [Back to TOC](#table-of-contents) Functions ========= type ---- **syntax:** *type_name = process_module.type()* **context:** *any* Returns the type of the current Nginx process. Depending on the calling context and current process, the type can be one of: * `master`: returned when this function is called from within the master process * `worker`: returned when this function is called from within a worker process * `single`: returned when Nginx is running in the single process mode * `signaller`: returned when Nginx is running as a signaller process * `privileged agent`: returned when this funtion is called from within a privileged agent process For example: ```lua local process = require "ngx.process" ngx.say("process type:", process.type()) -- RESPONSE: worker ``` [Back to TOC](#table-of-contents) enable_privileged_agent ----------------------- **syntax:** *ok, err = process_module.enable_privileged_agent(connections)* **context:** *init_by_lua** Enables the privileged agent process in Nginx. The privileged agent process does not listen on any virtual server ports like those worker processes. And it uses the same system account as the nginx master process, which is usually a privileged account like `root`. The `init_worker_by_lua*` directive handler still runs in the privileged agent process. And one can use the [type](#type) function provided by this module to check if the current process is a privileged agent. The argument connections sets the maximum number of simultaneous connections that can be opened by privileged agent process. In case of failures, returns `nil` and a string describing the error. [Back to TOC](#table-of-contents) signal_graceful_exit -------------------- **syntax:** *process_module.signal_graceful_exit()* **context:** *any* Signals the *current* nginx (worker) process to quit gracefully, i.e., after all the timers have expired (in time or expired prematurely). Note that this API function simply sets the nginx global C variable `ngx_quit` to signal the nginx event loop directly. No UNIX signals or IPC are involved here. WARNING: the official NGINX core does not perform the graceful exiting procedure when the [master_process](http://nginx.org/r/master_process) directive is turned `off`. The OpenResty's NGINX core has a [custom patch](https://github.com/openresty/openresty/blob/master/patches/nginx-1.11.2-single_process_graceful_exit.patch) applied, which fixes this issue. [Back to TOC](#table-of-contents) get_master_pid -------------- **syntax:** *pid = process_module.get_master_pid()* **context:** *any* Returns a number value for the nginx master process's process ID (or PID). This function requires NGINX 1.13.8+ cores to work properly. Otherwise it returns `nil`. This feature first appeared in lua-resty-core v0.1.14. [Back to TOC](#table-of-contents) Community ========= [Back to TOC](#table-of-contents) English Mailing List -------------------- The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. [Back to TOC](#table-of-contents) Chinese Mailing List -------------------- The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. [Back to TOC](#table-of-contents) Bugs and Patches ================ Please report bugs or submit patches by 1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), 1. or posting to the [OpenResty community](#community). [Back to TOC](#table-of-contents) Author ====== Yuansheng Wang <membphis@gmail.com> (membphis), OpenResty Inc. [Back to TOC](#table-of-contents) Copyright and License ===================== This module is licensed under the BSD license. Copyright (C) 2017, by Yichun "agentzh" Zhang, OpenResty Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * 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. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [Back to TOC](#table-of-contents) See Also ======== * the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. * the ngx_lua module: https://github.com/openresty/lua-nginx-module * OpenResty: https://openresty.org [Back to TOC](#table-of-contents) lua-resty-core-0.1.31/lib/ngx/re.lua000066400000000000000000000170611474236722600171440ustar00rootroot00000000000000-- I hereby assign copyright in this code to the lua-resty-core project, -- to be licensed under the same terms as the rest of the code. local base = require "resty.core.base" local ffi = require 'ffi' local bit = require "bit" local core_regex = require "resty.core.regex" if core_regex.no_pcre then error("no support for 'ngx.re' module: OpenResty was " .. "compiled without PCRE support", 3) end local C = ffi.C local ffi_str = ffi.string local sub = string.sub local error = error local type = type local band = bit.band local new_tab = base.new_tab local tostring = tostring local math_max = math.max local math_min = math.min local is_regex_cache_empty = core_regex.is_regex_cache_empty local re_match_compile = core_regex.re_match_compile local destroy_compiled_regex = core_regex.destroy_compiled_regex local get_string_buf = base.get_string_buf local get_size_ptr = base.get_size_ptr local FFI_OK = base.FFI_OK local subsystem = ngx.config.subsystem local MAX_ERR_MSG_LEN = 128 local FLAG_DFA = 0x02 local PCRE_ERROR_NOMATCH = -1 local DEFAULT_SPLIT_RES_SIZE = 4 local split_ctx = new_tab(0, 1) local ngx_lua_ffi_set_jit_stack_size local ngx_lua_ffi_exec_regex if subsystem == 'http' then ffi.cdef[[ int ngx_http_lua_ffi_set_jit_stack_size(int size, unsigned char *errstr, size_t *errstr_size); ]] ngx_lua_ffi_exec_regex = C.ngx_http_lua_ffi_exec_regex ngx_lua_ffi_set_jit_stack_size = C.ngx_http_lua_ffi_set_jit_stack_size elseif subsystem == 'stream' then ffi.cdef[[ int ngx_stream_lua_ffi_set_jit_stack_size(int size, unsigned char *errstr, size_t *errstr_size); ]] ngx_lua_ffi_exec_regex = C.ngx_stream_lua_ffi_exec_regex ngx_lua_ffi_set_jit_stack_size = C.ngx_stream_lua_ffi_set_jit_stack_size end local _M = { version = base.version } local function re_split_helper(subj, compiled, compile_once, flags, ctx) local rc do local pos = math_max(ctx.pos, 0) rc = ngx_lua_ffi_exec_regex(compiled, flags, subj, #subj, pos) end if rc == PCRE_ERROR_NOMATCH then return nil, nil, nil end if rc < 0 then if not compile_once then destroy_compiled_regex(compiled) end return nil, nil, nil, "pcre_exec() failed: " .. rc end if rc == 0 then if band(flags, FLAG_DFA) == 0 then if not compile_once then destroy_compiled_regex(compiled) end return nil, nil, nil, "capture size too small" end rc = 1 end local caps = compiled.captures local ncaps = compiled.ncaptures local from = caps[0] local to = caps[1] if from < 0 or to < 0 then return nil, nil, nil end if from == to then -- empty match, skip to next char ctx.pos = to + 1 else ctx.pos = to end -- convert to Lua string indexes from = from + 1 to = to + 1 -- retrieve the first sub-match capture if any if ncaps > 0 and rc > 1 then return from, to, sub(subj, caps[2] + 1, caps[3]) end return from, to end function _M.split(subj, regex, opts, ctx, max, res) -- we need to cast this to strings to avoid exceptions when they are -- something else. -- needed because of further calls to string.sub in this function. subj = tostring(subj) if not ctx then ctx = split_ctx ctx.pos = 1 -- set or reset upvalue field elseif not ctx.pos then -- ctx provided by user but missing pos field ctx.pos = 1 end max = max or 0 if not res then -- limit the initial arr_n size of res to a reasonable value -- 0 < narr <= DEFAULT_SPLIT_RES_SIZE local narr = DEFAULT_SPLIT_RES_SIZE if max > 0 then -- the user specified a valid max limiter if max > 0 narr = math_min(narr, max) end res = new_tab(narr, 0) elseif type(res) ~= "table" then error("res is not a table", 2) end local len = #subj if ctx.pos > len then res[1] = nil return res end -- compile regex local compiled, compile_once, flags = re_match_compile(regex, opts) if compiled == nil then -- compiled_once holds the error string return nil, compile_once end local sub_idx = ctx.pos local res_idx = 0 local last_empty_match -- update to split_helper PCRE indexes ctx.pos = sub_idx - 1 -- splitting: with and without a max limiter if max > 0 then local count = 1 while count < max do local from, to, capture, err = re_split_helper(subj, compiled, compile_once, flags, ctx) if err then return nil, err end if not from then break end if last_empty_match then sub_idx = last_empty_match end if from == to then last_empty_match = from end if from > sub_idx or not last_empty_match then count = count + 1 res_idx = res_idx + 1 res[res_idx] = sub(subj, sub_idx, from - 1) if capture then res_idx = res_idx + 1 res[res_idx] = capture end sub_idx = to if sub_idx > len then break end end end else while true do local from, to, capture, err = re_split_helper(subj, compiled, compile_once, flags, ctx) if err then return nil, err end if not from then break end if last_empty_match then sub_idx = last_empty_match end if from == to then last_empty_match = from end if from > sub_idx or not last_empty_match then res_idx = res_idx + 1 res[res_idx] = sub(subj, sub_idx, from - 1) if capture then res_idx = res_idx + 1 res[res_idx] = capture end sub_idx = to if sub_idx > len then break end end end end if not compile_once then destroy_compiled_regex(compiled) end -- trailing nil for non-cleared res tables -- delete empty trailing ones (without max) if max <= 0 and sub_idx > len then for ety_idx = res_idx, 1, -1 do if res[ety_idx] ~= "" then res_idx = ety_idx break end res[ety_idx] = nil end else res_idx = res_idx + 1 res[res_idx] = sub(subj, sub_idx) end res[res_idx + 1] = nil return res end function _M.opt(option, value) if option == "jit_stack_size" then if not is_regex_cache_empty() then error("changing jit stack size is not allowed when some " .. "regexs have already been compiled and cached", 2) end local errbuf = get_string_buf(MAX_ERR_MSG_LEN) local sizep = get_size_ptr() sizep[0] = MAX_ERR_MSG_LEN local rc = ngx_lua_ffi_set_jit_stack_size(value, errbuf, sizep) if rc == FFI_OK then return end error(ffi_str(errbuf, sizep[0]), 2) end error("unrecognized option name", 2) end return _M lua-resty-core-0.1.31/lib/ngx/re.md000066400000000000000000000164201474236722600167610ustar00rootroot00000000000000Name ==== ngx.re - Lua API for convenience utilities for `ngx.re`. Table of Contents ================= * [Name](#name) * [Status](#status) * [Synopsis](#synopsis) * [Description](#description) * [Methods](#methods) * [split](#split) * [opt](#opt) * [Community](#community) * [English Mailing List](#english-mailing-list) * [Chinese Mailing List](#chinese-mailing-list) * [Bugs and Patches](#bugs-and-patches) * [Author](#author) * [Copyright and License](#copyright-and-license) * [See Also](#see-also) Status ====== This Lua module is production ready. Synopsis ======== ```lua local ngx_re = require "ngx.re" -- split local res, err = ngx_re.split("a,b,c,d", ",") --> res is now {"a", "b", "c", "d"} -- opt ngx_re.opt("jit_stack_size", 128 * 1024) --> the PCRE jit stack can now handle more complex regular expressions ``` [Back to TOC](#table-of-contents) Description =========== This Lua module provides a Lua API which implements convenience utilities for the `ngx.re` API. [Back to TOC](#table-of-contents) Methods ======= All the methods of this module are static (or module-level). That is, you do not need an object (or instance) to call these methods. [Back to TOC](#table-of-contents) split ----- **syntax:** *res, err = ngx_re.split(subject, regex, options?, ctx?, max?, res?)* Splits the `subject` string using the Perl compatible regular expression `regex` with the optional `options`. This function returns a Lua (array) table (with integer keys) containing the split values. In case of error, `nil` will be returned as well as a string describing the error. When `regex` contains a sub-match capturing group, and when such a match is found, the first submatch capture will be inserted in between each split value, like so: ```lua local ngx_re = require "ngx.re" local res, err = ngx_re.split("a,b,c,d", "(,)") -- res is now {"a", ",", "b", ",", "c", ",", "d"} ``` When `regex` is empty string `""`, the `subject` will be split into chars, like so: ```lua local ngx_re = require "ngx.re" local res, err = ngx_re.split("abcd", "") -- res is now {"a", "b", "c", "d"} ``` The optional `ctx` table argument can be a Lua table holding an optional `pos` field. When the `pos` field in the `ctx` table argument is specified, `ngx_re.split` will start splitting the `subject` from that index: ```lua local ngx_re = require "ngx.re" local res, err = ngx_re.split("a,b,c,d", ",", nil, {pos = 5}) -- res is now {"c", "d"} ``` The optional `max` argument is a number that when specified, will prevent `ngx_re.split` from adding more than `max` matches to the `res` array: ```lua local ngx_re = require "ngx.re" local res, err = ngx_re.split("a,b,c,d", ",", nil, nil, 3) -- res is now {"a", "b", "c,d"} ``` Specifying `max <= 0` disables this behavior, meaning that the number of results won't be limited. The optional 6th argument `res` can be a table that `ngx_re.split` will re-use to hold the results instead of creating a new one, which can improve performance in hot code paths. It is used like so: ```lua local ngx_re = require "ngx.re" local my_table = {"hello world"} local res, err = ngx_re.split("a,b,c,d", ",", nil, nil, nil, my_table) -- res/my_table is now {"a", "b", "c", "d"} ``` When provided with a `res` table, `ngx_re.split` won't clear the table for performance reasons, but will rather insert a trailing `nil` value when the split is completed: ```lua local ngx_re = require "ngx.re" local my_table = {"W", "X", "Y", "Z"} local res, err = ngx_re.split("a,b", ",", nil, nil, nil, my_table) -- res/my_table is now {"a", "b", nil, "Z"} ``` When the trailing `nil` is not enough for your purpose, you should clear the table yourself before feeding it into the `split` function. [Back to TOC](#table-of-contents) opt ----- **syntax:** *ngx_re.opt(option, value)* Allows changing of regex settings. Currently, it can only change the `jit_stack_size` of the PCRE engine, like so: ```nginx init_by_lua_block { require "ngx.re".opt("jit_stack_size", 200 * 1024) } server { location /re { content_by_lua_block { -- full regex and string are taken from https://github.com/JuliaLang/julia/issues/8278 local very_long_string = [[71.163.72.113 - - [30/Jul/2014:16:40:55 -0700] ...]] local very_complicated_regex = [[([\d\.]+) ([\w.-]+) ([\w.-]+) (\[.+\]) ...]] local from, to, err = ngx.re.find(very_long_string, very_complicated_regex, "jo") -- with the regular jit_stack_size, we would get the error 'pcre_exec() failed: -27' -- instead, we get a match ngx.print(from .. "-" .. to) -- prints '1-1563' } } } ``` The `jit_stack_size` cannot be set to a value lower than PCRE's default of 32K. This method requires the PCRE library enabled in Nginx. This feature was first introduced in the `v0.1.12` release. [Back to TOC](#table-of-contents) Community ========= [Back to TOC](#table-of-contents) English Mailing List -------------------- The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. [Back to TOC](#table-of-contents) Chinese Mailing List -------------------- The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. [Back to TOC](#table-of-contents) Bugs and Patches ================ Please report bugs or submit patches by 1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), 1. or posting to the [OpenResty community](#community). [Back to TOC](#table-of-contents) Author ====== Thibault Charbonnier - ([@thibaultcha](https://github.com/thibaultcha)) [Back to TOC](#table-of-contents) Copyright and License ===================== This module is licensed under the BSD license. Copyright (C) 2016-2017, by Yichun "agentzh" Zhang, OpenResty Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * 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. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [Back to TOC](#table-of-contents) See Also ======== * the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. * the ngx_lua module: https://github.com/openresty/lua-nginx-module * OpenResty: https://openresty.org [Back to TOC](#table-of-contents) lua-resty-core-0.1.31/lib/ngx/req.lua000066400000000000000000000005241474236722600173210ustar00rootroot00000000000000-- Copyright (C) by OpenResty Inc. local base = require "resty.core.base" base.allows_subsystem("http") local core_request = require "resty.core.request" local set_req_header = core_request.set_req_header local _M = { version = base.version } function _M.add_header(key, value) set_req_header(key, value, false) end return _M lua-resty-core-0.1.31/lib/ngx/req.md000066400000000000000000000105251474236722600171420ustar00rootroot00000000000000Name ==== ngx.req - Lua API for HTTP request handling. Table of Contents ================= * [Name](#name) * [Status](#status) * [Synopsis](#synopsis) * [Description](#description) * [Methods](#methods) * [add_header](#add_header) * [Community](#community) * [English Mailing List](#english-mailing-list) * [Chinese Mailing List](#chinese-mailing-list) * [Bugs and Patches](#bugs-and-patches) * [Copyright and License](#copyright-and-license) * [See Also](#see-also) Status ====== This Lua module is production ready. Synopsis ======== ```lua local ngx_req = require "ngx.req" -- add_header ngx_req.add_header("Foo", "bar") ngx_req.add_header("Foo", "baz") --> there will be two new headers in the HTTP request: --> Foo: bar and Foo: baz ``` [Back to TOC](#table-of-contents) Description =========== This module provides a Lua API to handle HTTP requests. [Back to TOC](#table-of-contents) Methods ======= All methods provided by this module are static (or module-level). That is, you do not need an object (or instance) to call these methods. [Back to TOC](#table-of-contents) add_header ---------- **syntax:** *ngx_req.add_header(header_name, header_value)* **context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua** This method adds the specified header and its value to the current request. It works similarly as [ngx.req.set_header](https://github.com/openresty/lua-nginx-module#ngxreqset_header), with the exception that when the header already exists, the specified value(s) will be appended instead of overriden. The first argument `header_name` must be a non-empty string. When the specified `header_name` is a builtin header (e.g. `User-Agent`), this method will override its values. The `header_value` argument can either be a string or a non-empty, array-like table. A `nil` or empty table value will cause this function to throw an error. This feature was first introduced in the `v0.1.18` release. [Back to TOC](#table-of-contents) Community ========= [Back to TOC](#table-of-contents) English Mailing List -------------------- The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. [Back to TOC](#table-of-contents) Chinese Mailing List -------------------- The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. [Back to TOC](#table-of-contents) Bugs and Patches ================ Please report bugs or submit patches by 1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), 1. or posting to the [OpenResty community](#community). [Back to TOC](#table-of-contents) Copyright and License ===================== This module is licensed under the BSD license. Copyright (C) 2016-2019, by Yichun "agentzh" Zhang, OpenResty Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * 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. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [Back to TOC](#table-of-contents) See Also ======== * library [lua-resty-core](https://github.com/openresty/lua-resty-core) * the ngx_lua module: https://github.com/openresty/lua-nginx-module * OpenResty: https://openresty.org [Back to TOC](#table-of-contents) lua-resty-core-0.1.31/lib/ngx/resp.lua000066400000000000000000000021161474236722600175020ustar00rootroot00000000000000-- Copyright (C) Yichun Zhang. All rights reserved. local ffi = require "ffi" local C = ffi.C local base = require "resty.core.base" base.allows_subsystem('http') local FFI_BAD_CONTEXT = base.FFI_BAD_CONTEXT local core_response = require "resty.core.response" local set_resp_header = core_response.set_resp_header local get_request = base.get_request ffi.cdef[[ int ngx_http_lua_ffi_set_resp_status_and_reason(ngx_http_request_t *r, int status, const char *reason, size_t reason_len); ]] local _M = { version = base.version } function _M.add_header(key, value) set_resp_header(nil, key, value, true) end function _M.set_status(status, reason) local r = get_request() if not r then error("no request found") end if type(status) ~= 'number' then status = tonumber(status) end local rc = C.ngx_http_lua_ffi_set_resp_status_and_reason(r, status, reason, #reason) if rc == FFI_BAD_CONTEXT then error("API disabled in the current context", 2) end end return _M lua-resty-core-0.1.31/lib/ngx/resp.md000066400000000000000000000107621474236722600173270ustar00rootroot00000000000000Name ==== ngx.resp - Lua API for HTTP response handling. Table of Contents ================= * [Name](#name) * [Status](#status) * [Synopsis](#synopsis) * [Description](#description) * [Methods](#methods) * [add_header](#add_header) * [set_status](#set_status) * [Community](#community) * [English Mailing List](#english-mailing-list) * [Chinese Mailing List](#chinese-mailing-list) * [Bugs and Patches](#bugs-and-patches) * [Copyright and License](#copyright-and-license) * [See Also](#see-also) Status ====== This Lua module is production ready. Synopsis ======== ```lua local ngx_resp = require "ngx.resp" -- add_header ngx_resp.add_header("Foo", "bar") ngx_resp.add_header("Foo", "baz") --> there will be two new headers in HTTP response: --> Foo: bar and Foo: baz ngx_resp.set(531, "user defined error") --> the response line will be: 531 user defiend error ``` [Back to TOC](#table-of-contents) Description =========== This Lua module provides Lua API which could be used to handle HTTP response. [Back to TOC](#table-of-contents) Methods ======= All the methods of this module are static (or module-level). That is, you do not need an object (or instance) to call these methods. [Back to TOC](#table-of-contents) add_header ---------- **syntax:** *ngx_resp.add_header(header_name, header_value)* This function adds specified header with corresponding value to the response of current request. The `header_value` could be either a string or a table. The `ngx.resp.add_header` works mostly like: * [ngx.header.HEADER](https://github.com/openresty/lua-nginx-module#ngxheaderheader) * Nginx's [add_header](http://nginx.org/en/docs/http/ngx_http_headers_module.html#add_header) directive. However, unlike `ngx.header.HEADER`, this method appends new header to the old one instead of overriding it. Unlike `add_header` directive, this method will override the builtin header instead of appending it. [Back to TOC](#table-of-contents) set_status ---------- **syntax:** *ngx_resp.status(status, reason?)* Unlike `ngx.status` which only sets the status, this function sets the response status with an optional reason. The `reason` should be a string. [Back to TOC](#table-of-contents) Community ========= [Back to TOC](#table-of-contents) English Mailing List -------------------- The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. [Back to TOC](#table-of-contents) Chinese Mailing List -------------------- The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. [Back to TOC](#table-of-contents) Bugs and Patches ================ Please report bugs or submit patches by 1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), 1. or posting to the [OpenResty community](#community). [Back to TOC](#table-of-contents) Copyright and License ===================== This module is licensed under the BSD license. Copyright (C) 2018, by Yichun "agentzh" Zhang, OpenResty Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * 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. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [Back to TOC](#table-of-contents) See Also ======== * the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. * the ngx_lua module: https://github.com/openresty/lua-nginx-module * OpenResty: https://openresty.org [Back to TOC](#table-of-contents) lua-resty-core-0.1.31/lib/ngx/semaphore.lua000066400000000000000000000117561474236722600205260ustar00rootroot00000000000000-- Copyright (C) Yichun Zhang (agentzh) -- Copyright (C) cuiweixie -- I hereby assign copyright in this code to the lua-resty-core project, -- to be licensed under the same terms as the rest of the code. local base = require "resty.core.base" base.allows_subsystem('http', 'stream') local ffi = require 'ffi' local FFI_OK = base.FFI_OK local FFI_ERROR = base.FFI_ERROR local FFI_DECLINED = base.FFI_DECLINED local ffi_new = ffi.new local ffi_str = ffi.string local ffi_gc = ffi.gc local C = ffi.C local type = type local error = error local tonumber = tonumber local get_request = base.get_request local get_string_buf = base.get_string_buf local get_size_ptr = base.get_size_ptr local setmetatable = setmetatable local co_yield = coroutine._yield local ERR_BUF_SIZE = 128 local subsystem = ngx.config.subsystem local errmsg = base.get_errmsg_ptr() local psem local ngx_lua_ffi_sema_new local ngx_lua_ffi_sema_post local ngx_lua_ffi_sema_count local ngx_lua_ffi_sema_wait local ngx_lua_ffi_sema_gc if subsystem == 'http' then ffi.cdef[[ struct ngx_http_lua_sema_s; typedef struct ngx_http_lua_sema_s ngx_http_lua_sema_t; int ngx_http_lua_ffi_sema_new(ngx_http_lua_sema_t **psem, int n, char **errmsg); int ngx_http_lua_ffi_sema_post(ngx_http_lua_sema_t *sem, int n); int ngx_http_lua_ffi_sema_count(ngx_http_lua_sema_t *sem); int ngx_http_lua_ffi_sema_wait(ngx_http_request_t *r, ngx_http_lua_sema_t *sem, int wait_ms, unsigned char *errstr, size_t *errlen); void ngx_http_lua_ffi_sema_gc(ngx_http_lua_sema_t *sem); ]] psem = ffi_new("ngx_http_lua_sema_t *[1]") ngx_lua_ffi_sema_new = C.ngx_http_lua_ffi_sema_new ngx_lua_ffi_sema_post = C.ngx_http_lua_ffi_sema_post ngx_lua_ffi_sema_count = C.ngx_http_lua_ffi_sema_count ngx_lua_ffi_sema_wait = C.ngx_http_lua_ffi_sema_wait ngx_lua_ffi_sema_gc = C.ngx_http_lua_ffi_sema_gc elseif subsystem == 'stream' then ffi.cdef[[ struct ngx_stream_lua_sema_s; typedef struct ngx_stream_lua_sema_s ngx_stream_lua_sema_t; int ngx_stream_lua_ffi_sema_new(ngx_stream_lua_sema_t **psem, int n, char **errmsg); int ngx_stream_lua_ffi_sema_post(ngx_stream_lua_sema_t *sem, int n); int ngx_stream_lua_ffi_sema_count(ngx_stream_lua_sema_t *sem); int ngx_stream_lua_ffi_sema_wait(ngx_stream_lua_request_t *r, ngx_stream_lua_sema_t *sem, int wait_ms, unsigned char *errstr, size_t *errlen); void ngx_stream_lua_ffi_sema_gc(ngx_stream_lua_sema_t *sem); ]] psem = ffi_new("ngx_stream_lua_sema_t *[1]") ngx_lua_ffi_sema_new = C.ngx_stream_lua_ffi_sema_new ngx_lua_ffi_sema_post = C.ngx_stream_lua_ffi_sema_post ngx_lua_ffi_sema_count = C.ngx_stream_lua_ffi_sema_count ngx_lua_ffi_sema_wait = C.ngx_stream_lua_ffi_sema_wait ngx_lua_ffi_sema_gc = C.ngx_stream_lua_ffi_sema_gc end local _M = { version = base.version } local mt = { __index = _M } function _M.new(n) n = tonumber(n) or 0 if n < 0 then error("no negative number", 2) end local ret = ngx_lua_ffi_sema_new(psem, n, errmsg) if ret == FFI_ERROR then return nil, ffi_str(errmsg[0]) end local sem = psem[0] ffi_gc(sem, ngx_lua_ffi_sema_gc) return setmetatable({ sem = sem }, mt) end function _M.wait(self, seconds) if type(self) ~= "table" or type(self.sem) ~= "cdata" then error("not a semaphore instance", 2) end local r = get_request() if not r then error("no request found") end local milliseconds = tonumber(seconds) * 1000 if milliseconds < 0 then error("no negative number", 2) end local cdata_sem = self.sem local err = get_string_buf(ERR_BUF_SIZE) local errlen = get_size_ptr() errlen[0] = ERR_BUF_SIZE local ret = ngx_lua_ffi_sema_wait(r, cdata_sem, milliseconds, err, errlen) if ret == FFI_ERROR then return nil, ffi_str(err, errlen[0]) end if ret == FFI_OK then return true end if ret == FFI_DECLINED then return nil, "timeout" end -- Note: we cannot use the tail-call form here since we -- might need the current function call's activation -- record to hold the reference to our semaphore object -- to prevent it from getting GC'd prematurely. local ok ok, err = co_yield() return ok, err end function _M.post(self, n) if type(self) ~= "table" or type(self.sem) ~= "cdata" then error("not a semaphore instance", 2) end local cdata_sem = self.sem local num = n and tonumber(n) or 1 if num < 1 then error("positive number required", 2) end -- always return NGX_OK ngx_lua_ffi_sema_post(cdata_sem, num) return true end function _M.count(self) if type(self) ~= "table" or type(self.sem) ~= "cdata" then error("not a semaphore instance", 2) end return ngx_lua_ffi_sema_count(self.sem) end return _M lua-resty-core-0.1.31/lib/ngx/semaphore.md000066400000000000000000000256251474236722600203450ustar00rootroot00000000000000Name ==== ngx.semaphore - light thread semaphore for OpenResty/ngx_lua. Table of Contents ================= * [Name](#name) * [Status](#status) * [Synopsis](#synopsis) * [Synchronizing threads in the same context](#synchronizing-threads-in-the-same-context) * [Synchronizing threads in different contexts](#synchronizing-threads-in-different-contexts) * [Description](#description) * [Methods](#methods) * [new](#new) * [post](#post) * [wait](#wait) * [count](#count) * [Community](#community) * [English Mailing List](#english-mailing-list) * [Chinese Mailing List](#chinese-mailing-list) * [Bugs and Patches](#bugs-and-patches) * [Author](#author) * [Copyright and License](#copyright-and-license) * [See Also](#see-also) Status ====== This Lua module is production ready. Synopsis ======== Synchronizing threads in the same context ----------------------------------------- ```nginx location = /t { content_by_lua_block { local semaphore = require "ngx.semaphore" local sema = semaphore.new() local function handler() ngx.say("sub thread: waiting on sema...") local ok, err = sema:wait(1) -- wait for a second at most if not ok then ngx.say("sub thread: failed to wait on sema: ", err) else ngx.say("sub thread: waited successfully.") end end local co = ngx.thread.spawn(handler) ngx.say("main thread: sleeping for a little while...") ngx.sleep(0.1) -- wait a bit ngx.say("main thread: posting to sema...") sema:post(1) ngx.say("main thread: end.") } } ``` The example location above produces a response output like this: ``` sub thread: waiting on sema... main thread: sleeping for a little while... main thread: posting to sema... main thread: end. sub thread: waited successfully. ``` [Back to TOC](#table-of-contents) Synchronizing threads in different contexts ------------------------------------------- ```nginx location = /t { content_by_lua_block { local semaphore = require "ngx.semaphore" local sema = semaphore.new() local outputs = {} local i = 1 local function out(s) outputs[i] = s i = i + 1 end local function handler() out("timer thread: sleeping for a little while...") ngx.sleep(0.1) -- wait a bit out("timer thread: posting on sema...") sema:post(1) end assert(ngx.timer.at(0, handler)) out("main thread: waiting on sema...") local ok, err = sema:wait(1) -- wait for a second at most if not ok then out("main thread: failed to wait on sema: ", err) else out("main thread: waited successfully.") end out("main thread: end.") ngx.say(table.concat(outputs, "\n")) } } ``` The example location above produces a response body like this ``` main thread: waiting on sema... timer thread: sleeping for a little while... timer thread: posting on sema... main thread: waited successfully. main thread: end. ``` The same applies to different request contexts as long as these requests are served by the same nginx worker process. [Back to TOC](#table-of-contents) Description =========== This module provides an efficient semaphore API for the OpenResty/ngx_lua module. With semaphores, "light threads" (created by [ngx.thread.spawn](https://github.com/openresty/lua-nginx-module#ngxthreadspawn), [ngx.timer.at](https://github.com/openresty/lua-nginx-module#ngxtimerat), and etc.) can synchronize among each other very efficiently without constant polling and sleeping. "Light threads" in different contexts (like in different requests) can share the same semaphore instance as long as these "light threads" reside in the same NGINX worker process and the [lua_code_cache](https://github.com/openresty/lua-nginx-module#lua_code_cache) directive is turned on (which is the default). For inter-process "light thread" synchronization, it is recommended to use the [lua-resty-lock](https://github.com/openresty/lua-resty-lock) library instead (which is a bit less efficient than this semaphore API though). This semaphore API has a pure userland implementation which does not involve any system calls nor block any operating system threads. It works closely with the event model of NGINX without introducing any extra delay. Like other APIs provided by this `lua-resty-core` library, the LuaJIT FFI feature is required. [Back to TOC](#table-of-contents) Methods ======= [Back to TOC](#table-of-contents) new --- **syntax:** *sema, err = semaphore_module.new(n?)* **context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Creates and returns a new semaphore instance that has `n` (default to `0`) resources. For example, ```lua local semaphore = require "ngx.semaphore" local sema, err = semaphore.new() if not sema then ngx.say("create semaphore failed: ", err) end ``` Often the semaphore object created is shared on the NGINX worker process by mounting in a custom Lua module, as documented below: https://github.com/openresty/lua-nginx-module#data-sharing-within-an-nginx-worker [Back to TOC](#table-of-contents) post -------- **syntax:** *sema:post(n?)* **context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Releases `n` (default to `1`) "resources" to the semaphore instance. This will not yield the current running "light thread". At most `n` "light threads" will be waken up when the current running "light thread" later yields (or terminates). ```lua -- typically, we get the semaphore instance from upvalue or globally shared data -- See https://github.com/openresty/lua-nginx-module#data-sharing-within-an-nginx-worker local semaphore = require "ngx.semaphore" local sema = semaphore.new() sema:post(2) -- releases 2 resources ``` [Back to TOC](#table-of-contents) wait ---- **syntax:** *ok, err = sema:wait(timeout)* **context:** *rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.** Requests a resource from the semaphore instance. Returns `true` immediately when there is resources available for the current running "light thread". Otherwise the current "light thread" will enter the waiting queue and yield execution. The current "light thread" will be automatically waken up and the `wait` function call will return `true` when there is resources available for it, or return `nil` and a string describing the error in case of failure (like `"timeout"`). The `timeout` argument specifies the maximum time this function call should wait for (in seconds). When the `timeout` argument is 0, it means "no wait", that is, when there is no readily available "resources" for the current running "light thread", this `wait` function call returns immediately `nil` and the error string `"timeout"`. You can specify millisecond precision in the timeout value by using floating point numbers like 0.001 (which means 1ms). "Light threads" created by different contexts (like request handlers) can wait on the same semaphore instance without problem. See [Synopsis](#synopsis) for code examples. [Back to TOC](#table-of-contents) count -------- **syntax:** *count = sema:count()* **context:** *init_by_lua*, init_worker_by_lua*, set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua*, ngx.timer.** Returns the number of resources readily available in the `sema` semaphore instance (if any). When the returned number is negative, it means the number of "light threads" waiting on this semaphore. Consider the following example, ```lua local semaphore = require "ngx.semaphore" local sema = semaphore.new(0) ngx.say("count: ", sema:count()) -- count: 0 local function handler(id) local ok, err = sema:wait(1) if not ok then ngx.say("err: ", err) else ngx.say("wait success") end end local co1 = ngx.thread.spawn(handler) local co2 = ngx.thread.spawn(handler) ngx.say("count: ", sema:count()) -- count: -2 sema:post(1) ngx.say("count: ", sema:count()) -- count: -1 sema:post(2) ngx.say("count: ", sema:count()) -- count: 1 ``` [Back to TOC](#table-of-contents) Community ========= [Back to TOC](#table-of-contents) English Mailing List -------------------- The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. [Back to TOC](#table-of-contents) Chinese Mailing List -------------------- The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. [Back to TOC](#table-of-contents) Bugs and Patches ================ Please report bugs or submit patches by 1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), 1. or posting to the [OpenResty community](#community). [Back to TOC](#table-of-contents) Author ====== Weixie Cui, Kugou Inc. [Back to TOC](#table-of-contents) Copyright and License ===================== This module is licensed under the BSD license. Copyright (C) 2015-2017, by Yichun "agentzh" Zhang, OpenResty Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * 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. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [Back to TOC](#table-of-contents) See Also ======== * the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. * the ngx_lua module: https://github.com/openresty/lua-nginx-module * OpenResty: https://openresty.org [Back to TOC](#table-of-contents) lua-resty-core-0.1.31/lib/ngx/ssl.lua000066400000000000000000000425621474236722600173430ustar00rootroot00000000000000-- Copyright (C) Yichun Zhang (agentzh) local base = require "resty.core.base" base.allows_subsystem('http', 'stream') local ffi = require "ffi" local C = ffi.C local ffi_str = ffi.string local ffi_gc = ffi.gc local get_request = base.get_request local error = error local tonumber = tonumber local errmsg = base.get_errmsg_ptr() local get_string_buf = base.get_string_buf local get_size_ptr = base.get_size_ptr local FFI_DECLINED = base.FFI_DECLINED local FFI_OK = base.FFI_OK local subsystem = ngx.config.subsystem local ngx_lua_ffi_ssl_set_der_certificate local ngx_lua_ffi_ssl_clear_certs local ngx_lua_ffi_ssl_set_der_private_key local ngx_lua_ffi_ssl_raw_server_addr local ngx_lua_ffi_ssl_server_port local ngx_lua_ffi_ssl_server_name local ngx_lua_ffi_ssl_raw_client_addr local ngx_lua_ffi_cert_pem_to_der local ngx_lua_ffi_priv_key_pem_to_der local ngx_lua_ffi_ssl_get_tls1_version local ngx_lua_ffi_parse_pem_cert local ngx_lua_ffi_parse_pem_priv_key local ngx_lua_ffi_parse_der_cert local ngx_lua_ffi_parse_der_priv_key local ngx_lua_ffi_set_cert local ngx_lua_ffi_set_priv_key local ngx_lua_ffi_free_cert local ngx_lua_ffi_free_priv_key local ngx_lua_ffi_ssl_verify_client local ngx_lua_ffi_ssl_client_random local ngx_lua_ffi_ssl_export_keying_material local ngx_lua_ffi_ssl_export_keying_material_early local ngx_lua_ffi_get_req_ssl_pointer if subsystem == 'http' then ffi.cdef[[ int ngx_http_lua_ffi_ssl_set_der_certificate(ngx_http_request_t *r, const char *data, size_t len, char **err); int ngx_http_lua_ffi_ssl_clear_certs(ngx_http_request_t *r, char **err); int ngx_http_lua_ffi_ssl_set_der_private_key(ngx_http_request_t *r, const char *data, size_t len, char **err); int ngx_http_lua_ffi_ssl_raw_server_addr(ngx_http_request_t *r, char **addr, size_t *addrlen, int *addrtype, char **err); int ngx_http_lua_ffi_ssl_server_port(ngx_http_request_t *r, unsigned short *server_port, char **err); int ngx_http_lua_ffi_ssl_server_name(ngx_http_request_t *r, char **name, size_t *namelen, char **err); int ngx_http_lua_ffi_ssl_raw_client_addr(ngx_http_request_t *r, char **addr, size_t *addrlen, int *addrtype, char **err); int ngx_http_lua_ffi_cert_pem_to_der(const unsigned char *pem, size_t pem_len, unsigned char *der, char **err); int ngx_http_lua_ffi_priv_key_pem_to_der(const unsigned char *pem, size_t pem_len, const unsigned char *passphrase, unsigned char *der, char **err); int ngx_http_lua_ffi_ssl_get_tls1_version(ngx_http_request_t *r, char **err); void *ngx_http_lua_ffi_parse_pem_cert(const unsigned char *pem, size_t pem_len, char **err); void *ngx_http_lua_ffi_parse_pem_priv_key(const unsigned char *pem, size_t pem_len, char **err); void *ngx_http_lua_ffi_parse_der_cert(const char *data, size_t len, char **err); void *ngx_http_lua_ffi_parse_der_priv_key(const char *data, size_t len, char **err) ; void *ngx_http_lua_ffi_get_req_ssl_pointer(void *r); int ngx_http_lua_ffi_set_cert(void *r, void *cdata, char **err); int ngx_http_lua_ffi_set_priv_key(void *r, void *cdata, char **err); void ngx_http_lua_ffi_free_cert(void *cdata); void ngx_http_lua_ffi_free_priv_key(void *cdata); int ngx_http_lua_ffi_ssl_verify_client(void *r, void *client_certs, void *trusted_certs, int depth, char **err); int ngx_http_lua_ffi_ssl_client_random(ngx_http_request_t *r, const unsigned char *out, size_t *outlen, char **err); int ngx_http_lua_ffi_ssl_export_keying_material(void *r, unsigned char *out, size_t out_size, const char *label, size_t llen, const unsigned char *ctx, size_t ctxlen, int use_ctx, char **err); int ngx_http_lua_ffi_ssl_export_keying_material_early(void *r, unsigned char *out, size_t out_size, const char *label, size_t llen, const unsigned char *ctx, size_t ctxlen, char **err); ]] ngx_lua_ffi_ssl_set_der_certificate = C.ngx_http_lua_ffi_ssl_set_der_certificate ngx_lua_ffi_ssl_clear_certs = C.ngx_http_lua_ffi_ssl_clear_certs ngx_lua_ffi_ssl_set_der_private_key = C.ngx_http_lua_ffi_ssl_set_der_private_key ngx_lua_ffi_ssl_raw_server_addr = C.ngx_http_lua_ffi_ssl_raw_server_addr ngx_lua_ffi_ssl_server_port = C.ngx_http_lua_ffi_ssl_server_port ngx_lua_ffi_ssl_server_name = C.ngx_http_lua_ffi_ssl_server_name ngx_lua_ffi_ssl_raw_client_addr = C.ngx_http_lua_ffi_ssl_raw_client_addr ngx_lua_ffi_cert_pem_to_der = C.ngx_http_lua_ffi_cert_pem_to_der ngx_lua_ffi_priv_key_pem_to_der = C.ngx_http_lua_ffi_priv_key_pem_to_der ngx_lua_ffi_ssl_get_tls1_version = C.ngx_http_lua_ffi_ssl_get_tls1_version ngx_lua_ffi_parse_pem_cert = C.ngx_http_lua_ffi_parse_pem_cert ngx_lua_ffi_parse_pem_priv_key = C.ngx_http_lua_ffi_parse_pem_priv_key ngx_lua_ffi_parse_der_cert = C.ngx_http_lua_ffi_parse_der_cert ngx_lua_ffi_parse_der_priv_key = C.ngx_http_lua_ffi_parse_der_priv_key ngx_lua_ffi_set_cert = C.ngx_http_lua_ffi_set_cert ngx_lua_ffi_set_priv_key = C.ngx_http_lua_ffi_set_priv_key ngx_lua_ffi_free_cert = C.ngx_http_lua_ffi_free_cert ngx_lua_ffi_free_priv_key = C.ngx_http_lua_ffi_free_priv_key ngx_lua_ffi_ssl_verify_client = C.ngx_http_lua_ffi_ssl_verify_client ngx_lua_ffi_ssl_client_random = C.ngx_http_lua_ffi_ssl_client_random ngx_lua_ffi_ssl_export_keying_material = C.ngx_http_lua_ffi_ssl_export_keying_material ngx_lua_ffi_ssl_export_keying_material_early = C.ngx_http_lua_ffi_ssl_export_keying_material_early ngx_lua_ffi_get_req_ssl_pointer = C.ngx_http_lua_ffi_get_req_ssl_pointer elseif subsystem == 'stream' then ffi.cdef[[ int ngx_stream_lua_ffi_ssl_set_der_certificate(ngx_stream_lua_request_t *r, const char *data, size_t len, char **err); int ngx_stream_lua_ffi_ssl_clear_certs(ngx_stream_lua_request_t *r, char **err); int ngx_stream_lua_ffi_ssl_set_der_private_key(ngx_stream_lua_request_t *r, const char *data, size_t len, char **err); int ngx_stream_lua_ffi_ssl_raw_server_addr(ngx_stream_lua_request_t *r, char **addr, size_t *addrlen, int *addrtype, char **err); int ngx_stream_lua_ffi_ssl_server_port(ngx_stream_lua_request_t *r, unsigned short *server_port, char **err); int ngx_stream_lua_ffi_ssl_server_name(ngx_stream_lua_request_t *r, char **name, size_t *namelen, char **err); int ngx_stream_lua_ffi_ssl_raw_client_addr(ngx_stream_lua_request_t *r, char **addr, size_t *addrlen, int *addrtype, char **err); int ngx_stream_lua_ffi_cert_pem_to_der(const unsigned char *pem, size_t pem_len, unsigned char *der, char **err); int ngx_stream_lua_ffi_priv_key_pem_to_der(const unsigned char *pem, size_t pem_len, const unsigned char *passphrase, unsigned char *der, char **err); int ngx_stream_lua_ffi_ssl_get_tls1_version(ngx_stream_lua_request_t *r, char **err); void *ngx_stream_lua_ffi_parse_pem_cert(const unsigned char *pem, size_t pem_len, char **err); void *ngx_stream_lua_ffi_parse_der_cert(const unsigned char *der, size_t der_len, char **err); void *ngx_stream_lua_ffi_parse_pem_priv_key(const unsigned char *pem, size_t pem_len, char **err); void *ngx_stream_lua_ffi_parse_der_priv_key(const unsigned char *der, size_t der_len, char **err); int ngx_stream_lua_ffi_set_cert(void *r, void *cdata, char **err); int ngx_stream_lua_ffi_set_priv_key(void *r, void *cdata, char **err); void ngx_stream_lua_ffi_free_cert(void *cdata); void ngx_stream_lua_ffi_free_priv_key(void *cdata); int ngx_stream_lua_ffi_ssl_verify_client(void *r, void *client_certs, void *trusted_certs, int depth, char **err); int ngx_stream_lua_ffi_ssl_client_random(ngx_stream_lua_request_t *r, unsigned char *out, size_t *outlen, char **err); ]] ngx_lua_ffi_ssl_set_der_certificate = C.ngx_stream_lua_ffi_ssl_set_der_certificate ngx_lua_ffi_ssl_clear_certs = C.ngx_stream_lua_ffi_ssl_clear_certs ngx_lua_ffi_ssl_set_der_private_key = C.ngx_stream_lua_ffi_ssl_set_der_private_key ngx_lua_ffi_ssl_raw_server_addr = C.ngx_stream_lua_ffi_ssl_raw_server_addr ngx_lua_ffi_ssl_server_port = C.ngx_stream_lua_ffi_ssl_server_port ngx_lua_ffi_ssl_server_name = C.ngx_stream_lua_ffi_ssl_server_name ngx_lua_ffi_ssl_raw_client_addr = C.ngx_stream_lua_ffi_ssl_raw_client_addr ngx_lua_ffi_cert_pem_to_der = C.ngx_stream_lua_ffi_cert_pem_to_der ngx_lua_ffi_priv_key_pem_to_der = C.ngx_stream_lua_ffi_priv_key_pem_to_der ngx_lua_ffi_ssl_get_tls1_version = C.ngx_stream_lua_ffi_ssl_get_tls1_version ngx_lua_ffi_parse_pem_cert = C.ngx_stream_lua_ffi_parse_pem_cert ngx_lua_ffi_parse_der_cert = C.ngx_stream_lua_ffi_parse_der_cert ngx_lua_ffi_parse_pem_priv_key = C.ngx_stream_lua_ffi_parse_pem_priv_key ngx_lua_ffi_parse_der_priv_key = C.ngx_stream_lua_ffi_parse_der_priv_key ngx_lua_ffi_set_cert = C.ngx_stream_lua_ffi_set_cert ngx_lua_ffi_set_priv_key = C.ngx_stream_lua_ffi_set_priv_key ngx_lua_ffi_free_cert = C.ngx_stream_lua_ffi_free_cert ngx_lua_ffi_free_priv_key = C.ngx_stream_lua_ffi_free_priv_key ngx_lua_ffi_ssl_verify_client = C.ngx_stream_lua_ffi_ssl_verify_client ngx_lua_ffi_ssl_client_random = C.ngx_stream_lua_ffi_ssl_client_random end local _M = { version = base.version } local charpp = ffi.new("char*[1]") local intp = ffi.new("int[1]") local ushortp = ffi.new("unsigned short[1]") function _M.clear_certs() local r = get_request() if not r then error("no request found") end local rc = ngx_lua_ffi_ssl_clear_certs(r, errmsg) if rc == FFI_OK then return true end return nil, ffi_str(errmsg[0]) end function _M.set_der_cert(data) local r = get_request() if not r then error("no request found") end local rc = ngx_lua_ffi_ssl_set_der_certificate(r, data, #data, errmsg) if rc == FFI_OK then return true end return nil, ffi_str(errmsg[0]) end function _M.set_der_priv_key(data) local r = get_request() if not r then error("no request found") end local rc = ngx_lua_ffi_ssl_set_der_private_key(r, data, #data, errmsg) if rc == FFI_OK then return true end return nil, ffi_str(errmsg[0]) end local addr_types = { [0] = "unix", [1] = "inet", [2] = "inet6", } function _M.raw_server_addr() local r = get_request() if not r then error("no request found") end local sizep = get_size_ptr() local rc = ngx_lua_ffi_ssl_raw_server_addr(r, charpp, sizep, intp, errmsg) if rc == FFI_OK then local typ = addr_types[intp[0]] if not typ then return nil, nil, "unknown address type: " .. intp[0] end return ffi_str(charpp[0], sizep[0]), typ end return nil, nil, ffi_str(errmsg[0]) end function _M.server_port() local r = get_request() if not r then error("no request found") end local rc = ngx_lua_ffi_ssl_server_port(r, ushortp, errmsg) if rc == FFI_OK then return ushortp[0] end return nil, ffi_str(errmsg[0]) end function _M.server_name() local r = get_request() if not r then error("no request found") end local sizep = get_size_ptr() local rc = ngx_lua_ffi_ssl_server_name(r, charpp, sizep, errmsg) if rc == FFI_OK then return ffi_str(charpp[0], sizep[0]) end if rc == FFI_DECLINED then return nil end return nil, ffi_str(errmsg[0]) end function _M.raw_client_addr() local r = get_request() if not r then error("no request found") end local sizep = get_size_ptr() local rc = ngx_lua_ffi_ssl_raw_client_addr(r, charpp, sizep, intp, errmsg) if rc == FFI_OK then local typ = addr_types[intp[0]] if not typ then return nil, nil, "unknown address type: " .. intp[0] end return ffi_str(charpp[0], sizep[0]), typ end return nil, nil, ffi_str(errmsg[0]) end function _M.cert_pem_to_der(pem) local outbuf = get_string_buf(#pem) local sz = ngx_lua_ffi_cert_pem_to_der(pem, #pem, outbuf, errmsg) if sz > 0 then return ffi_str(outbuf, sz) end return nil, ffi_str(errmsg[0]) end function _M.priv_key_pem_to_der(pem, passphrase) local outbuf = get_string_buf(#pem) local sz = ngx_lua_ffi_priv_key_pem_to_der(pem, #pem, passphrase, outbuf, errmsg) if sz > 0 then return ffi_str(outbuf, sz) end return nil, ffi_str(errmsg[0]) end local function get_tls1_version() local r = get_request() if not r then error("no request found") end local ver = ngx_lua_ffi_ssl_get_tls1_version(r, errmsg) ver = tonumber(ver) if ver >= 0 then return ver end -- rc == FFI_ERROR return nil, ffi_str(errmsg[0]) end _M.get_tls1_version = get_tls1_version function _M.parse_pem_cert(pem) local cert = ngx_lua_ffi_parse_pem_cert(pem, #pem, errmsg) if cert ~= nil then return ffi_gc(cert, ngx_lua_ffi_free_cert) end return nil, ffi_str(errmsg[0]) end function _M.parse_pem_priv_key(pem) local pkey = ngx_lua_ffi_parse_pem_priv_key(pem, #pem, errmsg) if pkey ~= nil then return ffi_gc(pkey, ngx_lua_ffi_free_priv_key) end return nil, ffi_str(errmsg[0]) end function _M.parse_der_cert(der) local cert = ngx_lua_ffi_parse_der_cert(der, #der, errmsg) if cert ~= nil then return ffi_gc(cert, ngx_lua_ffi_free_cert) end return nil, ffi_str(errmsg[0]) end function _M.parse_der_priv_key(der) local pkey = ngx_lua_ffi_parse_der_priv_key(der, #der, errmsg) if pkey ~= nil then return ffi_gc(pkey, ngx_lua_ffi_free_priv_key) end return nil, ffi_str(errmsg[0]) end function _M.set_cert(cert) local r = get_request() if not r then error("no request found") end local rc = ngx_lua_ffi_set_cert(r, cert, errmsg) if rc == FFI_OK then return true end return nil, ffi_str(errmsg[0]) end function _M.set_priv_key(priv_key) local r = get_request() if not r then error("no request found") end local rc = ngx_lua_ffi_set_priv_key(r, priv_key, errmsg) if rc == FFI_OK then return true end return nil, ffi_str(errmsg[0]) end function _M.verify_client(client_certs, depth, trusted_certs) local r = get_request() if not r then error("no request found") end if not depth then depth = -1 end local rc = ngx_lua_ffi_ssl_verify_client(r, client_certs, trusted_certs, depth, errmsg) if rc == FFI_OK then return true end return nil, ffi_str(errmsg[0]) end function _M.export_keying_material(length, label, context) local r = get_request() if not r then error("no request found") end local outbuf = get_string_buf(length) local use_context = context and 1 or 0 local context_len = context and #context or 0 local rc = ngx_lua_ffi_ssl_export_keying_material(r, outbuf, length, label, #label, context, context_len, use_context, errmsg) if rc == FFI_OK then return ffi_str(outbuf, length) end if rc == FFI_DECLINED then return nil end return nil, ffi_str(errmsg[0]) end function _M.export_keying_material_early(length, label, context) local r = get_request() if not r then error("no request found") end local outbuf = get_string_buf(length) local context_len = context and #context or 0 local rc = ngx_lua_ffi_ssl_export_keying_material_early(r, outbuf, length, label, #label, context, context_len, errmsg) if rc == FFI_OK then return ffi_str(outbuf, length) end if rc == FFI_DECLINED then return nil end return nil, ffi_str(errmsg[0]) end function _M.get_req_ssl_pointer() local r = get_request() if not r then error("no request found") end local ssl = ngx_lua_ffi_get_req_ssl_pointer(r) if ssl == nil then return nil, "no ssl object" end return ssl end do _M.SSL3_VERSION = 0x0300 _M.TLS1_VERSION = 0x0301 _M.TLS1_1_VERSION = 0x0302 _M.TLS1_2_VERSION = 0x0303 _M.TLS1_3_VERSION = 0x0304 local map = { [_M.SSL3_VERSION] = "SSLv3", [_M.TLS1_VERSION] = "TLSv1", [_M.TLS1_1_VERSION] = "TLSv1.1", [_M.TLS1_2_VERSION] = "TLSv1.2", [_M.TLS1_3_VERSION] = "TLSv1.3", } function _M.get_tls1_version_str() local ver, err = get_tls1_version() if not ver then return nil, err end local ver_str = map[ver] if not ver_str then return nil, "unknown version" end return ver_str end end function _M.get_client_random(outlen) local r = get_request() if not r then error("no request found") end if outlen == nil then outlen = 32 end local out = get_string_buf(outlen) local sizep = get_size_ptr() sizep[0] = outlen local rc = ngx_lua_ffi_ssl_client_random(r, out, sizep, errmsg) if rc == FFI_OK then if outlen == 0 then return tonumber(sizep[0]) end return ffi_str(out, sizep[0]) end return nil, ffi_str(errmsg[0]) end return _M lua-resty-core-0.1.31/lib/ngx/ssl.md000066400000000000000000000601721474236722600171570ustar00rootroot00000000000000Name ==== ngx.ssl - Lua API for controlling NGINX downstream SSL handshakes Table of Contents ================= * [Name](#name) * [Status](#status) * [Synopsis](#synopsis) * [Description](#description) * [Methods](#methods) * [clear_certs](#clear_certs) * [cert_pem_to_der](#cert_pem_to_der) * [set_der_cert](#set_der_cert) * [priv_key_pem_to_der](#priv_key_pem_to_der) * [set_der_priv_key](#set_der_priv_key) * [server_name](#server_name) * [server_port](#server_port) * [raw_server_addr](#raw_server_addr) * [export_keying_material](#export_keying_material) * [export_keying_material_early](#export_keying_material_early) * [raw_client_addr](#raw_client_addr) * [get_tls1_version](#get_tls1_version) * [get_tls1_version_str](#get_tls1_version_str) * [parse_pem_cert](#parse_pem_cert) * [parse_pem_priv_key](#parse_pem_priv_key) * [parse_der_cert](#parse_der_cert) * [parse_der_priv_key](#parse_der_priv_key) * [set_cert](#set_cert) * [set_priv_key](#set_priv_key) * [verify_client](#verify_client) * [get_client_random](#get_client_random) * [get_req_ssl_pointer](#get_req_ssl_pointer) * [Community](#community) * [English Mailing List](#english-mailing-list) * [Chinese Mailing List](#chinese-mailing-list) * [Bugs and Patches](#bugs-and-patches) * [Author](#author) * [Copyright and License](#copyright-and-license) * [See Also](#see-also) Status ====== This Lua module is production ready. Synopsis ======== ```nginx # Note: you do not need the following line if you are using # OpenResty 1.9.7.2+. lua_package_path "/path/to/lua-resty-core/lib/?.lua;;"; server { listen 443 ssl; server_name test.com; # useless placeholders: just to shut up NGINX configuration # loader errors: ssl_certificate /path/to/fallback.crt; ssl_certificate_key /path/to/fallback.key; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" -- clear the fallback certificates and private keys -- set by the ssl_certificate and ssl_certificate_key -- directives above: local ok, err = ssl.clear_certs() if not ok then ngx.log(ngx.ERR, "failed to clear existing (fallback) certificates") return ngx.exit(ngx.ERROR) end -- assuming the user already defines the my_load_certificate_chain() -- herself. local pem_cert_chain = assert(my_load_certificate_chain()) local der_cert_chain, err = ssl.cert_pem_to_der(pem_cert_chain) if not der_cert_chain then ngx.log(ngx.ERR, "failed to convert certificate chain ", "from PEM to DER: ", err) return ngx.exit(ngx.ERROR) end local ok, err = ssl.set_der_cert(der_cert_chain) if not ok then ngx.log(ngx.ERR, "failed to set DER cert: ", err) return ngx.exit(ngx.ERROR) end -- assuming the user already defines the my_load_private_key() -- function herself. local pem_pkey = assert(my_load_private_key()) local passphrase = "password" -- or nil local der_pkey, err = ssl.priv_key_pem_to_der(pem_pkey, passphrase) if not der_pkey then ngx.log(ngx.ERR, "failed to convert private key ", "from PEM to DER: ", err) return ngx.exit(ngx.ERROR) end local ok, err = ssl.set_der_priv_key(der_pkey) if not ok then ngx.log(ngx.ERR, "failed to set DER private key: ", err) return ngx.exit(ngx.ERROR) end } location / { root html; } } ``` Description =========== This Lua module provides API functions to control the SSL handshake process in contexts like [ssl_certificate_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_certificate_by_lua_block) (of the [ngx_lua](https://github.com/openresty/lua-nginx-module#readme) module). For web servers serving many (like millions of) https sites, it is often desired to lazily load and cache the SSL certificate chain and private key data for the https sites actually being served by a particular server. This Lua module provides API to support such use cases in the context of the [ssl_certificate_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_certificate_by_lua_block) directive. To load the `ngx.ssl` module in Lua, just write ```lua local ssl = require "ngx.ssl" ``` [Back to TOC](#table-of-contents) Methods ======= clear_certs ----------- **syntax:** *ok, err = ssl.clear_certs()* **context:** *ssl_certificate_by_lua** Clears any existing SSL certificates and/or private keys set on the current SSL connection. Returns `true` on success, or a `nil` value and a string describing the error otherwise. [Back to TOC](#table-of-contents) cert_pem_to_der --------------- **syntax:** *der_cert_chain, err = ssl.cert_pem_to_der(pem_cert_chain)* **context:** *any* Converts the PEM-formatted SSL certificate chain data into the DER format (for later uses in the [set_der_cert](#set_der_cert) function, for example). In case of failures, returns `nil` and a string describing the error. It is known that the `openssl` command-line utility may not convert the whole SSL certificate chain from PEM to DER correctly. So always use this Lua function to do the conversion. You can always use libraries like [lua-resty-lrucache](https://github.com/openresty/lua-resty-lrucache#readme) and/or ngx_lua APIs like [lua_shared_dict](https://github.com/openresty/lua-nginx-module#lua_shared_dict) to do the caching of the DER-formatted results, for example. This function can be called in any context. [Back to TOC](#table-of-contents) set_der_cert ------------ **syntax:** *ok, err = ssl.set_der_cert(der_cert_chain)* **context:** *ssl_certificate_by_lua** Sets the DER-formatted SSL certificate chain data for the current SSL connection. Note that the DER data is directly in the Lua string argument. *No* external file names are supported here. Returns `true` on success, or a `nil` value and a string describing the error otherwise. Note that, the SSL certificate chain is usually encoded in the PEM format. So you need to use the [cert_pem_to_der](#cert_pem_to_der) function to do the conversion first. [Back to TOC](#table-of-contents) priv_key_pem_to_der ------------------- **syntax:** *der_priv_key, err = ssl.priv_key_pem_to_der(pem_priv_key, passphrase)* **context:** *any* Converts the PEM-formatted SSL private key data into the DER format (for later uses in the [set_der_priv_key](#set_der_priv_key) function, for example). The `passphrase` is the passphrase for `pem_priv_key` if the private key is password protected. In case of failures, returns `nil` and a string describing the error. Alternatively, you can do the PEM to DER conversion *offline* with the `openssl` command-line utility, like below ```bash openssl rsa -in key.pem -outform DER -out key.der ``` This function can be called in any context. [Back to TOC](#table-of-contents) set_der_priv_key ---------------- **syntax:** *ok, err = ssl.set_der_priv_key(der_priv_key)* **context:** *ssl_certificate_by_lua** Sets the DER-formatted prviate key for the current SSL connection. Returns `true` on success, or a `nil` value and a string describing the error otherwise. Usually, the private keys are encoded in the PEM format. You can either use the [priv_key_pem_to_der](#priv_key_pem_to_der) function to do the PEM to DER conversion or just use the `openssl` command-line utility offline, like below ```bash openssl rsa -in key.pem -outform DER -out key.der ``` [Back to TOC](#table-of-contents) server_name ----------- **syntax:** *name, err = ssl.server_name()* **context:** *any* Returns the TLS SNI (Server Name Indication) name set by the client. Returns `nil` when the client does not set it. In case of failures, it returns `nil` *and* a string describing the error. Usually we use this SNI name as the domain name (like `www.openresty.org`) to identify the current web site while loading the corresponding SSL certificate chain and private key for the site. Please note that not all https clients set the SNI name, so when the SNI name is missing from the client handshake request, we use the server IP address accessed by the client to identify the site. See the [raw_server_addr](#raw_server_addr) method for more details. This function can be called in any context where downstream https is used. [Back to TOC](#table-of-contents) server_port ----------- **syntax:** port, err = ssl.server_port() **context:** *any* Returns the server port. Returns `nil` when server dont have a port. In case of failures, it returns `nil` *and* a string describing the error. This function can be called in any context where downstream https is used. [Back to TOC](#table-of-contents) raw_server_addr --------------- **syntax:** *addr_data, addr_type, err = ssl.raw_server_addr()* **context:** *any* Returns the raw server address actually accessed by the client in the current SSL connection. The first two return values are strings representing the address data and the address type, respectively. The address values are interpreted differently according to the address type values: * `unix` : The address data is a file path for the UNIX domain socket. * `inet` : The address data is a binary IPv4 address of 4 bytes long. * `inet6` : The address data is a binary IPv6 address of 16 bytes long. Returns two `nil` values and a Lua string describing the error. The following code snippet shows how to print out the UNIX domain socket address and the IPv4 address as human-readable strings: ```lua local ssl = require "ngx.ssl" local byte = string.byte local addr, addrtyp, err = ssl.raw_server_addr() if not addr then ngx.log(ngx.ERR, "failed to fetch raw server addr: ", err) return end if addrtyp == "inet" then -- IPv4 ip = string.format("%d.%d.%d.%d", byte(addr, 1), byte(addr, 2), byte(addr, 3), byte(addr, 4)) print("Using IPv4 address: ", ip) elseif addrtyp == "unix" then -- UNIX print("Using unix socket file ", addr) else -- IPv6 -- leave as an exercise for the readers end ``` This function can be called in any context where downstream https is used. [Back to TOC](#table-of-contents) export_keying_material ---------------------- **syntax:** *key, err = ssl.export_keying_material(length, label, context)* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** Return a key derived from the SSL master secret. As described in RFC8446 section 7.5 this function returns key material that is derived from the SSL master secret and can be used on the application level. The returned key material is of the given length. Label is mandatory and requires a special format that is described in RFC5705 section 4. Context is optional but note that in TLSv1.2 and below a zero length context is treated differently from no context at all, and will result in different keying material being returned. In TLSv1.3 a zero length context is that same as no context at all and will result in the same keying material being returned. The following code snippet shows how to derive a new key that can be used on the application level. ```lua local ssl = require "ngx.ssl" local key_length = 16 local label = "EXPERIMENTAL my label" local context = "\x00\x01\x02\x03" local key, err = ssl.export_keying_material(key_length, label, context) if not key then ngx.log(ngx.ERR, "failed to derive key ", err) return end -- use key... end ``` This function can be called in any context where downstream https is used. [Back to TOC](#table-of-contents) export_keying_material_early ---------------------------- **syntax:** *key, err = ssl.export_keying_material_early(length, label, context)* context: *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*, log_by_lua** Returns a key derived from the SSL early exporter master secret. As described in RFC8446 section 7.5 this function returns key material that is derived from the SSL early exporter master secret and can be used on the application level. The returned key material is of the given length. Label is mandatory and requires a special format that is described in RFC5705 section 4. This function is only usable with TLSv1.3, and derives keying material using the early_exporter_master_secret (as defined in the TLS 1.3 RFC). For the client, the early_exporter_master_secret is only available when the client attempts to send 0-RTT data. For the server, it is only available when the server accepts 0-RTT data. The following code snippet shows how to derive a new key that can be used on the application level. ```lua local ssl = require "ngx.ssl" local key_length = 16 local label = "EXPERIMENTAL my label" local context = "\x00\x01\x02\x03" local key, err = ssl.export_keying_material_early(key_length, label, context) if not key then ngx.log(ngx.ERR, "failed to derive key ", err) return end -- use key... end ``` This function can be called in any context where downstream https TLS1.3 is used. [Back to TOC](#table-of-contents) raw_client_addr --------------- **syntax:** *addr_data, addr_type, err = ssl.raw_client_addr()* **context:** *any* Returns the raw client address of the current SSL connection. The first two return values are strings representing the address data and the address type, respectively. The address values are interpreted differently according to the address type values: * `unix` : The address data is a file path for the UNIX domain socket. * `inet` : The address data is a binary IPv4 address of 4 bytes long. * `inet6` : The address data is a binary IPv6 address of 16 bytes long. Returns two `nil` values and a Lua string describing the error. The following code snippet shows how to print out the UNIX domain socket address and the IPv4 address as human-readable strings: ```lua local ssl = require "ngx.ssl" local byte = string.byte local addr, addrtyp, err = ssl.raw_client_addr() if not addr then ngx.log(ngx.ERR, "failed to fetch raw client addr: ", err) return end if addrtyp == "inet" then -- IPv4 ip = string.format("%d.%d.%d.%d", byte(addr, 1), byte(addr, 2), byte(addr, 3), byte(addr, 4)) print("Client IPv4 address: ", ip) elseif addrtyp == "unix" then -- UNIX print("Client unix socket file ", addr) else -- IPv6 -- leave as an exercise for the readers end ``` This function can be called in any context where downstream https is used. This function was first introduced in lua-resty-core 0.1.14. [Back to TOC](#table-of-contents) get_tls1_version ---------------- **syntax:** *ver, err = ssl.get_tls1_version()* **context:** *any* Returns the TLS 1.x version number used by the current SSL connection. Returns `nil` and a string describing the error otherwise. Typical return values are: * `0x0300`(SSLv3) * `0x0301`(TLSv1) * `0x0302`(TLSv1.1) * `0x0303`(TLSv1.2) * `0x0304`(TLSv1.3) This function can be called in any context where downstream https is used. [Back to TOC](#table-of-contents) get_tls1_version_str -------------------- **syntax:** *ver, err = ssl.get_tls1_version_str()* **context:** *any* Returns the TLS 1.x version string used by the current SSL connection. Returns `nil` and a string describing the error otherwise. If the TLS 1.x version number used by the current SSL connection is not recognized, the return values will be `nil` and the string "unknown version". Typical return values are: * `SSLv3` * `TLSv1` * `TLSv1.1` * `TLSv1.2` * `TLSv1.3` This function can be called in any context where downstream https is used. [Back to TOC](#table-of-contents) parse_pem_cert -------------- **syntax:** *cert_chain, err = ssl.parse_pem_cert(pem_cert_chain)* **context:** *any* Converts the PEM-formated SSL certificate chain data into an opaque cdata pointer (for later uses in the [set_cert](#set_cert) function, for example). In case of failures, returns `nil` and a string describing the error. You can always use libraries like [lua-resty-lrucache](https://github.com/openresty/lua-resty-lrucache#readme) to cache the cdata result. This function can be called in any context. This function was first added in version `0.1.7`. [Back to TOC](#table-of-contents) parse_pem_priv_key ------------------ **syntax:** *priv_key, err = ssl.parse_pem_priv_key(pem_priv_key)* **context:** *any* Converts the PEM-formatted SSL private key data into an opaque cdata pointer (for later uses in the [set_priv_key](#set_priv_key) function, for example). In case of failures, returns `nil` and a string describing the error. This function can be called in any context. This function was first added in version `0.1.7`. [Back to TOC](#table-of-contents) parse_der_cert -------------- **syntax:** *cert_chain, err = ssl.parse_der_cert(der_cert_chain)* **context:** *any* Converts the DER-formated SSL certificate chain data into an opaque cdata pointer (for later uses in the [set_cert](#set_cert) function, for example). In case of failures, returns `nil` and a string describing the error. You can always use libraries like [lua-resty-lrucache](https://github.com/openresty/lua-resty-lrucache#readme) to cache the cdata result. This function can be called in any context. [Back to TOC](#table-of-contents) parse_der_priv_key ------------------ **syntax:** *priv_key, err = ssl.parse_der_priv_key(der_priv_key)* **context:** *any* Converts the DER-formatted SSL private key data into an opaque cdata pointer (for later uses in the [set_priv_key](#set_priv_key) function, for example). In case of failures, returns `nil` and a string describing the error. This function can be called in any context. [Back to TOC](#table-of-contents) set_cert -------- **syntax:** *ok, err = ssl.set_cert(cert_chain)* **context:** *ssl_certificate_by_lua** Sets the SSL certificate chain opaque pointer returned by the [parse_pem_cert](#parse_pem_cert) or [parse_der_cert](#parse_der_cert)function for the current SSL connection. Returns `true` on success, or a `nil` value and a string describing the error otherwise. Note that this `set_cert` function will run slightly faster, in terms of CPU cycles wasted, than the [set_der_cert](#set_der_cert) variant, since the first function uses opaque cdata pointers which do not require any additional conversion needed to be performed by the SSL library during the SSL handshake. This function was first added in version `0.1.7`. [Back to TOC](#table-of-contents) set_priv_key ------------ **syntax:** *ok, err = ssl.set_priv_key(priv_key)* **context:** *ssl_certificate_by_lua** Sets the SSL private key opaque pointer returned by the [parse_pem_priv_key](#parse_pem_priv_key) or [parse_der_priv_key](#parse_der_priv_key) function for the current SSL connection. Returns `true` on success, or a `nil` value and a string describing the error otherwise. Note that this `set_priv_key` function will run slightly faster, in terms of CPU cycles wasted, than the [set_der_priv_key](#set_der_priv_key) variant, since the first function uses opaque cdata pointers which do not require any additional conversion needed to be performed by the SSL library during the SSL handshake. This function was first added in version `0.1.7`. [Back to TOC](#table-of-contents) verify_client ------------- **syntax:** *ok, err = ssl.verify_client(client_certs?, depth?, trusted_certs?)* **context:** *ssl_certificate_by_lua** Requires a client certificate during TLS handshake. The `client_certs` is the CA certificate chain opaque pointer returned by the [parse_pem_cert](#parse_pem_cert) function for the current SSL connection. The list of certificates will be sent to clients. Also, they will be added to trusted store. If omitted, will not send any CA certificate to clients. The `depth` is the verification depth in the client certificates chain. If omitted, will use the value specified by `ssl_verify_depth`. The `trusted_certs` is same returned by the [parse_pem_cert](#parse_pem_cert) function. They will be added to trusted store. Returns `true` on success, or a `nil` value and a string describing the error otherwise. Note that TLS is not terminated when verification fails. You need to examine Nginx variable `$ssl_client_verify` later to determine next steps. This function was first added in version `0.1.20`. [Back to TOC](#table-of-contents) get_client_random ----------- **syntax:** *client_random = ssl.get_client_random(outlen?)* **context:** *any* Returns the random value sent from the client to the server during the initial SSL/TLS handshake. The `outlen` parameter indicates the maximum length of the client_random value returned. If the `outlen` is zero, this function returns the total length of the client_random value. If omitted, will use the value 32. This function can be called in any context where downstream https is used, but in the context of [ssl_client_hello_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_client_hello_by_lua_block), it can not return the real client_random value, just a string filled with 0. [Back to TOC](#table-of-contents) get_req_ssl_pointer ------------ **syntax:** *ssl_ptr, err = ssl.get_req_ssl_pointer()* **context:** *any* Retrieves the OpenSSL `SSL*` object for the current downstream connection. Returns an FFI pointer on success, or a `nil` value and a string describing the error otherwise. If you need to retain the pointer beyond the current phase then you will need to use OpenSSL's `SSL_up_ref` to increase the reference count. If you do, ensure that your reference is released with `SSL_free`. This function was first added in version `0.1.16`. [Back to TOC](#table-of-contents) Community ========= [Back to TOC](#table-of-contents) English Mailing List -------------------- The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. [Back to TOC](#table-of-contents) Chinese Mailing List -------------------- The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. [Back to TOC](#table-of-contents) Bugs and Patches ================ Please report bugs or submit patches by 1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), 2. or posting to the [OpenResty community](#community). [Back to TOC](#table-of-contents) Author ====== Yichun Zhang <agentzh@gmail.com> (agentzh), OpenResty Inc. [Back to TOC](#table-of-contents) Copyright and License ===================== This module is licensed under the BSD license. Copyright (C) 2015-2017, by Yichun "agentzh" Zhang, OpenResty Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * 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. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [Back to TOC](#table-of-contents) See Also ======== * the ngx_lua module: https://github.com/openresty/lua-nginx-module * the [ngx.ocsp](ocsp.md) module. * the [ssl_certificate_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_certificate_by_lua_block) directive. * the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. * OpenResty: https://openresty.org [Back to TOC](#table-of-contents) lua-resty-core-0.1.31/lib/ngx/ssl/000077500000000000000000000000001474236722600166275ustar00rootroot00000000000000lua-resty-core-0.1.31/lib/ngx/ssl/clienthello.lua000066400000000000000000000136141474236722600216410ustar00rootroot00000000000000-- Copyright (C) Yichun Zhang (agentzh) local base = require "resty.core.base" base.allows_subsystem('http', 'stream') local ffi = require "ffi" local bit = require "bit" local bor = bit.bor local C = ffi.C local ffi_str = ffi.string local get_request = base.get_request local error = error local errmsg = base.get_errmsg_ptr() local get_size_ptr = base.get_size_ptr local FFI_OK = base.FFI_OK local subsystem = ngx.config.subsystem local ngx_phase = ngx.get_phase local byte = string.byte local lshift = bit.lshift local table_insert = table.insert local ngx_lua_ffi_ssl_get_client_hello_server_name local ngx_lua_ffi_ssl_get_client_hello_ext local ngx_lua_ffi_ssl_set_protocols if subsystem == 'http' then ffi.cdef[[ int ngx_http_lua_ffi_ssl_get_client_hello_server_name(ngx_http_request_t *r, const char **name, size_t *namelen, char **err); int ngx_http_lua_ffi_ssl_get_client_hello_ext(ngx_http_request_t *r, unsigned int type, const unsigned char **out, size_t *outlen, char **err); int ngx_http_lua_ffi_ssl_set_protocols(ngx_http_request_t *r, int protocols, char **err); ]] ngx_lua_ffi_ssl_get_client_hello_server_name = C.ngx_http_lua_ffi_ssl_get_client_hello_server_name ngx_lua_ffi_ssl_get_client_hello_ext = C.ngx_http_lua_ffi_ssl_get_client_hello_ext ngx_lua_ffi_ssl_set_protocols = C.ngx_http_lua_ffi_ssl_set_protocols elseif subsystem == 'stream' then ffi.cdef[[ int ngx_stream_lua_ffi_ssl_get_client_hello_server_name( ngx_stream_lua_request_t *r, const char **name, size_t *namelen, char **err); int ngx_stream_lua_ffi_ssl_get_client_hello_ext( ngx_stream_lua_request_t *r, unsigned int type, const unsigned char **out, size_t *outlen, char **err); int ngx_stream_lua_ffi_ssl_set_protocols(ngx_stream_lua_request_t *r, int protocols, char **err); ]] ngx_lua_ffi_ssl_get_client_hello_server_name = C.ngx_stream_lua_ffi_ssl_get_client_hello_server_name ngx_lua_ffi_ssl_get_client_hello_ext = C.ngx_stream_lua_ffi_ssl_get_client_hello_ext ngx_lua_ffi_ssl_set_protocols = C.ngx_stream_lua_ffi_ssl_set_protocols end local _M = { version = base.version } local ccharpp = ffi.new("const char*[1]") local cucharpp = ffi.new("const unsigned char*[1]") -- return server_name, err function _M.get_client_hello_server_name() local r = get_request() if not r then error("no request found") end if ngx_phase() ~= "ssl_client_hello" then error("API disabled in the current context") end local sizep = get_size_ptr() local rc = ngx_lua_ffi_ssl_get_client_hello_server_name(r, ccharpp, sizep, errmsg) if rc == FFI_OK then return ffi_str(ccharpp[0], sizep[0]) end -- NGX_DECLINED: no sni extension if rc == -5 then return nil end return nil, ffi_str(errmsg[0]) end -- return ext, err function _M.get_client_hello_ext(ext_type) local r = get_request() if not r then error("no request found") end if ngx_phase() ~= "ssl_client_hello" then error("API disabled in the current context") end local sizep = get_size_ptr() local rc = ngx_lua_ffi_ssl_get_client_hello_ext(r, ext_type, cucharpp, sizep, errmsg) if rc == FFI_OK then return ffi_str(cucharpp[0], sizep[0]) end -- NGX_DECLINED: no extension if rc == -5 then return nil end return nil, ffi_str(errmsg[0]) end -- tls.handshake.extension.type supported_version local supported_versions_type = 43 local versions_map = { [0x002] = "SSLv2", [0x300] = "SSLv3", [0x301] = "TLSv1", [0x302] = "TLSv1.1", [0x303] = "TLSv1.2", [0x304] = "TLSv1.3", } -- return types, err function _M.get_supported_versions() local r = get_request() if not r then error("no request found") end if ngx_phase() ~= "ssl_client_hello" then error("API disabled in the current context") end local sizep = get_size_ptr() local rc = ngx_lua_ffi_ssl_get_client_hello_ext(r, supported_versions_type, cucharpp, sizep, errmsg) if rc ~= FFI_OK then -- NGX_DECLINED: no extension if rc == -5 then return nil end return nil, ffi_str(errmsg[0]) end local supported_versions_str = ffi_str(cucharpp[0], sizep[0]) local remain_len = #supported_versions_str if remain_len == 0 then return nil end local supported_versions_len = byte(supported_versions_str, 1) remain_len = remain_len - 1 if remain_len ~= supported_versions_len then return nil end local types = {} while remain_len >= 2 do local type_hi = byte(supported_versions_str, remain_len) local type_lo = byte(supported_versions_str, remain_len + 1) local type_id = lshift(type_hi, 8) + type_lo if versions_map[type_id] ~= nil then table_insert(types, versions_map[type_id]) end remain_len = remain_len - 2 end return types end local prot_map = { ["SSLv2"] = 0x0002, ["SSLv3"] = 0x0004, ["TLSv1"] = 0x0008, ["TLSv1.1"] = 0x0010, ["TLSv1.2"] = 0x0020, ["TLSv1.3"] = 0x0040 } -- return ok, err function _M.set_protocols(protocols) local r = get_request() if not r then error("no request found") end if ngx_phase() ~= "ssl_client_hello" then error("API disabled in the current context") end local prots = 0 for _, v in ipairs(protocols) do if not prot_map[v] then return nil, "invalid protocols failed" end prots = bor(prots, prot_map[v]) end local rc = ngx_lua_ffi_ssl_set_protocols(r, prots, errmsg) if rc == FFI_OK then return true end return nil, ffi_str(errmsg[0]) end return _M lua-resty-core-0.1.31/lib/ngx/ssl/clienthello.md000066400000000000000000000222741474236722600214620ustar00rootroot00000000000000Name ==== ngx.ssl.clienthello - Lua API for post-processing SSL client hello message for NGINX downstream SSL connections. Table of Contents ================= * [Name](#name) * [Status](#status) * [Synopsis](#synopsis) * [Description](#description) * [Methods](#methods) * [get_client_hello_server_name](#get_client_hello_server_name) * [get_supported_versions](#get_supported_versions) * [get_client_hello_ext](#get_client_hello_ext) * [set_protocols](#set_protocols) * [Community](#community) * [English Mailing List](#english-mailing-list) * [Chinese Mailing List](#chinese-mailing-list) * [Bugs and Patches](#bugs-and-patches) * [Author](#author) * [Copyright and License](#copyright-and-license) * [See Also](#see-also) Status ====== This Lua module is production ready. Synopsis ======== ```nginx # nginx.conf server { listen 443 ssl; server_name test.com; ssl_certificate /path/to/cert.crt; ssl_certificate_key /path/to/key.key; ssl_client_hello_by_lua_block { local ssl_clt = require "ngx.ssl.clienthello" local host, err = ssl_clt.get_client_hello_server_name() if host == "test.com" then ssl_clt.set_protocols({"TLSv1", "TLSv1.1"}) elseif host == "test2.com" then ssl_clt.set_protocols({"TLSv1.2", "TLSv1.3"}) elseif not host then ngx.log(ngx.ERR, "failed to get the SNI name: ", err) ngx.exit(ngx.ERROR) else ngx.log(ngx.ERR, "unknown SNI name: ", host) ngx.exit(ngx.ERROR) end } ... } server { listen 443 ssl; server_name test2.com; ssl_certificate /path/to/cert.crt; ssl_certificate_key /path/to/key.key; ... } ``` Description =========== This Lua module provides API functions for post-processing SSL client hello message for NGINX downstream connections. It must to be used in the contexts [ssl_client_hello_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_client_hello_by_lua_block). This Lua API is particularly useful for dynamically setting the SSL protocols according to the SNI. It is also useful to do some custom operations according to the per-connection information in the client hello message. For example, one can parse the custom client hello extension and do the corresponding handling in pure Lua. To load the `ngx.ssl.clienthello` module in Lua, just write ```lua local ssl_clt = require "ngx.ssl.clienthello" ``` [Back to TOC](#table-of-contents) Methods ======= get_client_hello_server_name -------------- **syntax:** *host, err = ssl_clt.get_client_hello_server_name()* **context:** *ssl_client_hello_by_lua** Returns the TLS SNI (Server Name Indication) name set by the client. Return `nil` when then the extension does not exist. In case of errors, it returns `nil` and a string describing the error. Note that the SNI name is gotten from the raw extensions of the client hello message associated with the current downstream SSL connection. So this function can only be called in the context of [ssl_client_hello_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_client_hello_by_lua_block). [Back to TOC](#table-of-contents) get_supported_versions -------------- **syntax:** *types, err = ssl_clt.get_supported_versions()* **context:** *ssl_client_hello_by_lua** Returns the table of ssl hello supported versions set by the client. Return `nil` when then the extension does not exist. In case of errors, it returns `nil` and a string describing the error. Note that the types is gotten from the raw extensions of the client hello message associated with the current downstream SSL connection. So this function can only be called in the context of [ssl_client_hello_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_client_hello_by_lua_block). [Back to TOC](#table-of-contents) get_client_hello_ext ---------------------- **syntax:** *ext, err = ssl_clt.get_client_hello_ext(ext_type)* **context:** *ssl_client_hello_by_lua** Returns raw data of arbitrary SSL client hello extension including custom extensions. Returns `nil` if the specified extension type does not exist. In case of errors, it returns `nil` and a string describing the error. Note that the ext is gotten from the raw extensions of the client hello message associated with the current downstream SSL connection. So this function can only be called in the context of [ssl_client_hello_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_client_hello_by_lua_block). Example: Gets server name from raw extension data. The `0` in `ssl_clt.get_client_hello_ext(0)` denotes `TLSEXT_TYPE_server_name`, and the `0` in `byte(ext, 3) ~= 0` denotes `TLSEXT_NAMETYPE_host_name`. ```nginx # nginx.conf server { listen 443 ssl; server_name test.com; ssl_client_hello_by_lua_block { local ssl_clt = require "ngx.ssl.clienthello" local byte = string.byte local ext = ssl_clt.get_client_hello_ext(0) if not ext then print("failed to get_client_hello_ext(0)") ngx.exit(ngx.ERROR) end local total_len = string.len(ext) if total_len <= 2 then print("bad SSL Client Hello Extension") ngx.exit(ngx.ERROR) end local len = byte(ext, 1) * 256 + byte(ext, 2) if len + 2 ~= total_len then print("bad SSL Client Hello Extension") ngx.exit(ngx.ERROR) end if byte(ext, 3) ~= 0 then print("bad SSL Client Hello Extension") ngx.exit(ngx.ERROR) end if total_len <= 5 then print("bad SSL Client Hello Extension") ngx.exit(ngx.ERROR) end len = byte(ext, 4) * 256 + byte(ext, 5) if len + 5 > total_len then print("bad SSL Client Hello Extension") ngx.exit(ngx.ERROR) end local name = string.sub(ext, 6, 6 + len -1) print("read SNI name from Lua: ", name) } ssl_certificate test.crt; ssl_certificate_key test.key; } ``` [Back to TOC](#table-of-contents) set_protocols ---------------------- **syntax:** *ok, err = ssl_clt.set_protocols(protocols)* **context:** *ssl_client_hello_by_lua** Sets the SSL protocols supported by the current downstream SSL connection. Returns `true` on success, or a `nil` value and a string describing the error otherwise. Considering it is meaningless to set ssl protocols after the protocol is determined, so this function may only be called in the context of [ssl_client_hello_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_client_hello_by_lua_block). Example: `ssl_clt.set_protocols({"TLSv1.1", "TLSv1.2", "TLSv1.3"})` [Back to TOC](#table-of-contents) Community ========= [Back to TOC](#table-of-contents) English Mailing List -------------------- The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. [Back to TOC](#table-of-contents) Chinese Mailing List -------------------- The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. [Back to TOC](#table-of-contents) Bugs and Patches ================ Please report bugs or submit patches by 1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), 1. or posting to the [OpenResty community](#community). [Back to TOC](#table-of-contents) Author ====== Zhefeng Chen <chzf\_zju@163.com> (catbro666) [Back to TOC](#table-of-contents) Copyright and License ===================== This module is licensed under the BSD license. Copyright (C) 2016-2017, by Yichun "agentzh" Zhang, OpenResty Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * 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. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [Back to TOC](#table-of-contents) See Also ======== * the ngx_lua module: https://github.com/openresty/lua-nginx-module * the [ssl_client_hello_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_client_hello_by_lua_block) directive. * the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. * OpenResty: https://openresty.org [Back to TOC](#table-of-contents) lua-resty-core-0.1.31/lib/ngx/ssl/session.lua000066400000000000000000000045561474236722600210270ustar00rootroot00000000000000-- Copyright (C) Yichun Zhang (agentzh) local base = require "resty.core.base" base.allows_subsystem('http') local ffi = require "ffi" local C = ffi.C local ffi_str = ffi.string local get_request = base.get_request local error = error local errmsg = base.get_errmsg_ptr() local get_string_buf = base.get_string_buf local FFI_ERROR = base.FFI_ERROR ffi.cdef[[ int ngx_http_lua_ffi_ssl_set_serialized_session(ngx_http_request_t *r, const unsigned char *buf, int len, char **err); int ngx_http_lua_ffi_ssl_get_serialized_session(ngx_http_request_t *r, char *buf, char **err); int ngx_http_lua_ffi_ssl_get_session_id(ngx_http_request_t *r, char *buf, char **err); int ngx_http_lua_ffi_ssl_get_serialized_session_size(ngx_http_request_t *r, char **err); int ngx_http_lua_ffi_ssl_get_session_id_size(ngx_http_request_t *r, char **err); ]] local _M = { version = base.version } -- return session, err function _M.get_serialized_session() local r = get_request() if not r then error("no request found") end local len = C.ngx_http_lua_ffi_ssl_get_serialized_session_size(r, errmsg) if len < 0 then return nil, ffi_str(errmsg[0]) end if len > 4096 then return nil, "session too big to serialize" end local buf = get_string_buf(len) local rc = C.ngx_http_lua_ffi_ssl_get_serialized_session(r, buf, errmsg) if rc == FFI_ERROR then return nil, ffi_str(errmsg[0]) end return ffi_str(buf, len) end -- return session_id, err function _M.get_session_id() local r = get_request() if not r then error("no request found") end local len = C.ngx_http_lua_ffi_ssl_get_session_id_size(r, errmsg) if len < 0 then return nil, ffi_str(errmsg[0]) end local buf = get_string_buf(len) local rc = C.ngx_http_lua_ffi_ssl_get_session_id(r, buf, errmsg) if rc == FFI_ERROR then return nil, ffi_str(errmsg[0]) end return ffi_str(buf, len) end -- return ok, err function _M.set_serialized_session(sess) local r = get_request() if not r then error("no request found") end local rc = C.ngx_http_lua_ffi_ssl_set_serialized_session(r, sess, #sess, errmsg) if rc == FFI_ERROR then return nil, ffi_str(errmsg[0]) end return true end return _M lua-resty-core-0.1.31/lib/ngx/ssl/session.md000066400000000000000000000235051474236722600206410ustar00rootroot00000000000000Name ==== ngx.ssl.session - Lua API for manipulating SSL session data and IDs for NGINX downstream SSL connections. Table of Contents ================= * [Name](#name) * [Status](#status) * [Synopsis](#synopsis) * [Description](#description) * [Methods](#methods) * [get_session_id](#get_session_id) * [get_serialized_session](#get_serialized_session) * [set_serialized_session](#set_serialized_session) * [Community](#community) * [English Mailing List](#english-mailing-list) * [Chinese Mailing List](#chinese-mailing-list) * [Bugs and Patches](#bugs-and-patches) * [Author](#author) * [Copyright and License](#copyright-and-license) * [See Also](#see-also) Status ====== This Lua module is production ready. Synopsis ======== ```nginx # nginx.conf # Note: you do not need the following line if you are using # OpenResty 1.11.2.1+. lua_package_path "/path/to/lua-resty-core/lib/?.lua;;"; ssl_session_fetch_by_lua_block { local ssl_sess = require "ngx.ssl.session" local sess_id, err = ssl_sess.get_session_id() if not sess_id then ngx.log(ngx.ERR, "failed to get session ID: ", err) -- considered a cache miss, and just return... return end -- the user is supposed to implement the my_lookup_ssl_session_by_id -- Lua function used below. She can look up an external memcached -- or redis cluster, for example. And she can also introduce a local -- cache layer at the same time... local sess, err = my_lookup_ssl_session_by_id(sess_id) if not sess then if err then ngx.log(ngx.ERR, "failed to look up the session by ID ", sess_id, ": ", err) return end -- cache miss...just return return end local ok, err = ssl_sess.set_serialized_session(sess) if not ok then ngx.log(ngx.ERR, "failed to set SSL session for ID ", sess_id, ": ", err) -- consider it as a cache miss... return end -- done here, SSL session successfully set and should resume accordingly... } ssl_session_store_by_lua_block { local ssl_sess = require "ngx.ssl.session" local sess_id, err = ssl_sess.get_session_id() if not sess_id then ngx.log(ngx.ERR, "failed to get session ID: ", err) -- just give up return end local sess, err = ssl_sess.get_serialized_session() if not sess then ngx.log(ngx.ERR, "failed to get SSL session from the ", "current connection: ", err) -- just give up return end -- for the best performance, we should avoid creating a closure -- dynamically here on the hot code path. Instead, we should -- put this function in one of our own Lua module files. this -- example is just for demonstration purposes... local function save_it(premature, sess_id, sess) -- the user is supposed to implement the -- my_save_ssl_session_by_id Lua function used below. -- She can save to an external memcached -- or redis cluster, for example. And she can also introduce -- a local cache layer at the same time... local sess, err = my_save_ssl_session_by_id(sess_id, sess) if not sess then if err then ngx.log(ngx.ERR, "failed to save the session by ID ", sess_id, ": ", err) return ngx.exit(ngx.ERROR) end -- cache miss...just return return end end -- create a 0-delay timer here... local ok, err = ngx.timer.at(0, save_it, sess_id, sess) if not ok then ngx.log(ngx.ERR, "failed to create a 0-delay timer: ", err) return end } server { listen 443 ssl; server_name test.com; # well, we could configure ssl_certificate_by_lua* here as well... ssl_certificate /path/to/server-cert.pem; ssl_certificate_key /path/to/server-priv-key.pem; } ``` Description =========== This Lua module provides API functions for manipulating SSL session data and IDs for NGINX downstream connections. It is mostly for the contexts [ssl_session_fetch_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_session_fetch_by_lua_block) and [ssl_session_store_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_session_store_by_lua_block). This Lua API can be used to implement distributed SSL session caching for downstream SSL connections, thus saving a lot of full SSL handshakes which are very expensive. To load the `ngx.ssl.session` module in Lua, just write ```lua local ssl_sess = require "ngx.ssl.session" ``` [Back to TOC](#table-of-contents) Methods ======= get_session_id -------------- **syntax:** *id, err = ssl_sess.get_session_id()* **context:** *ssl_session_fetch_by_lua*, ssl_session_store_by_lua** Fetches the SSL session ID associated with the current downstream SSL connection. The ID is returned as a Lua string. In case of errors, it returns `nil` and a string describing the error. This API function is usually called in the contexts of [ssl_session_store_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_session_store_by_lua_block) and [ssl_session_fetch_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_session_fetch_by_lua_block). [Back to TOC](#table-of-contents) get_serialized_session ---------------------- **syntax:** *session, err = ssl_sess.get_serialized_session()* **context:** *ssl_session_store_by_lua** Returns the serialized form of the SSL session data of the current SSL connection, in a Lua string. This session can be cached in [lua-resty-lrucache](https://github.com/openresty/lua-resty-lrucache), [lua_shared_dict](https://github.com/openresty/lua-nginx-module#lua_shared_dict), and/or external data storage services like `memcached` and `redis`. The SSL session ID returned by the [get_session_id](#get_session_id) function is usually used as the cache key. The returned SSL session data can later be loaded into other SSL connections using the same session ID via the [set_serialized_session](#set_serialized_session) function. In case of errors, it returns `nil` and a string describing the error. This API function is usually called in the context of [ssl_session_store_by_lua*](https://github.com/openresty/lua-nginx-module#ssl_session_store_by_lua_block) where the SSL handshake has just completed. [Back to TOC](#table-of-contents) set_serialized_session ---------------------- **syntax:** *ok, err = ssl_sess.set_serialized_session(session)* **context:** *ssl_session_fetch_by_lua** Sets the serialized SSL session provided as the argument to the current SSL connection. If the SSL session is successfully set, the current SSL connection can resume the session directly without going through the full SSL handshake process (which is very expensive in terms of CPU time). This API is usually used in the context of [ssl_session_fetch_by_lua*](https://github.com/openresty/lua-nginx-module#ssl_session_fetch_by_lua_block) when a cache hit is found with the current SSL session ID. The serialized SSL session used as the argument should be originally returned by the [get_serialized_session](#get_serialized_session) function. [Back to TOC](#table-of-contents) Community ========= [Back to TOC](#table-of-contents) English Mailing List -------------------- The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. [Back to TOC](#table-of-contents) Chinese Mailing List -------------------- The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. [Back to TOC](#table-of-contents) Bugs and Patches ================ Please report bugs or submit patches by 1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), 1. or posting to the [OpenResty community](#community). [Back to TOC](#table-of-contents) Author ====== Yichun Zhang <agentzh@gmail.com> (agentzh), OpenResty Inc. [Back to TOC](#table-of-contents) Copyright and License ===================== This module is licensed under the BSD license. Copyright (C) 2016-2017, by Yichun "agentzh" Zhang, OpenResty Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * 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. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [Back to TOC](#table-of-contents) See Also ======== * the ngx_lua module: https://github.com/openresty/lua-nginx-module * the [ssl_session_fetch_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_session_fetch_by_lua_block) directive. * the [ssl_session_store_by_lua*](https://github.com/openresty/lua-nginx-module/#ssl_session_store_by_lua_block) directive. * the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. * OpenResty: https://openresty.org [Back to TOC](#table-of-contents) lua-resty-core-0.1.31/lib/resty/000077500000000000000000000000001474236722600164005ustar00rootroot00000000000000lua-resty-core-0.1.31/lib/resty/core.lua000066400000000000000000000013061474236722600200330ustar00rootroot00000000000000-- Copyright (C) Yichun Zhang (agentzh) local subsystem = ngx.config.subsystem require "resty.core.var" require "resty.core.worker" require "resty.core.regex" require "resty.core.shdict" require "resty.core.time" require "resty.core.hash" require "resty.core.uri" require "resty.core.exit" require "resty.core.base64" require "resty.core.request" if subsystem == 'http' then require "resty.core.response" require "resty.core.phase" require "resty.core.ndk" require "resty.core.socket" require "resty.core.coroutine" require "resty.core.param" end require "resty.core.misc" require "resty.core.ctx" local base = require "resty.core.base" return { version = base.version } lua-resty-core-0.1.31/lib/resty/core/000077500000000000000000000000001474236722600173305ustar00rootroot00000000000000lua-resty-core-0.1.31/lib/resty/core/base.lua000066400000000000000000000126261474236722600207540ustar00rootroot00000000000000-- Copyright (C) Yichun Zhang (agentzh) local ffi = require 'ffi' local ffi_new = ffi.new local pcall = pcall local error = error local select = select local ceil = math.ceil local subsystem = ngx.config.subsystem local str_buf_size = 4096 local str_buf local size_ptr local FREE_LIST_REF = 0 if subsystem == 'http' then if not ngx.config or not ngx.config.ngx_lua_version or ngx.config.ngx_lua_version ~= 10028 then error("ngx_http_lua_module 0.10.28 required") end elseif subsystem == 'stream' then if not ngx.config or not ngx.config.ngx_lua_version or ngx.config.ngx_lua_version ~= 16 then error("ngx_stream_lua_module 0.0.16 required") end else error("ngx_http_lua_module 0.10.28 or " .. "ngx_stream_lua_module 0.0.16 required") end if string.find(jit.version, " 2.0", 1, true) then ngx.log(ngx.ALERT, "use of lua-resty-core with LuaJIT 2.0 is ", "not recommended; use LuaJIT 2.1+ instead") end local ok, new_tab = pcall(require, "table.new") if not ok then new_tab = function (narr, nrec) return {} end end local clear_tab ok, clear_tab = pcall(require, "table.clear") if not ok then local pairs = pairs clear_tab = function (tab) for k, _ in pairs(tab) do tab[k] = nil end end end -- XXX for now LuaJIT 2.1 cannot compile require() -- so we make the fast code path Lua only in our own -- wrapper so that most of the require() calls in hot -- Lua code paths can be JIT compiled. do local orig_require = require local pkg_loaded = package.loaded -- the key_sentinel is inserted into package.loaded before -- the chunk is executed and replaced if the chunk completes normally. local key_sentinel = pkg_loaded[...] local function my_require(name) local mod = pkg_loaded[name] if mod then if mod == key_sentinel then error("loop or previous error loading module '" .. name .. "'") end return mod end return orig_require(name) end getfenv(0).require = my_require end if not pcall(ffi.typeof, "ngx_str_t") then ffi.cdef[[ typedef struct { size_t len; const unsigned char *data; } ngx_str_t; ]] end if subsystem == 'http' then if not pcall(ffi.typeof, "ngx_http_request_t") then ffi.cdef[[ typedef struct ngx_http_request_s ngx_http_request_t; ]] end if not pcall(ffi.typeof, "ngx_http_lua_ffi_str_t") then ffi.cdef[[ typedef struct { int len; const unsigned char *data; } ngx_http_lua_ffi_str_t; ]] end elseif subsystem == 'stream' then if not pcall(ffi.typeof, "ngx_stream_lua_request_t") then ffi.cdef[[ typedef struct ngx_stream_lua_request_s ngx_stream_lua_request_t; ]] end if not pcall(ffi.typeof, "ngx_stream_lua_ffi_str_t") then ffi.cdef[[ typedef struct { int len; const unsigned char *data; } ngx_stream_lua_ffi_str_t; ]] end else error("unknown subsystem: " .. subsystem) end local c_buf_type = ffi.typeof("char[?]") local _M = new_tab(0, 18) _M.version = "0.1.31" _M.new_tab = new_tab _M.clear_tab = clear_tab local errmsg function _M.get_errmsg_ptr() if not errmsg then errmsg = ffi_new("char *[1]") end return errmsg end if not ngx then error("no existing ngx. table found") end function _M.set_string_buf_size(size) if size <= 0 then return end if str_buf then str_buf = nil end str_buf_size = ceil(size) end function _M.get_string_buf_size() return str_buf_size end function _M.get_size_ptr() if not size_ptr then size_ptr = ffi_new("size_t[1]") end return size_ptr end function _M.get_string_buf(size, must_alloc) -- ngx.log(ngx.ERR, "str buf size: ", str_buf_size) if size > str_buf_size or must_alloc then local buf = ffi_new(c_buf_type, size) return buf end if not str_buf then str_buf = ffi_new(c_buf_type, str_buf_size) end return str_buf end function _M.ref_in_table(tb, key) if key == nil then return -1 end local ref = tb[FREE_LIST_REF] if ref and ref ~= 0 then tb[FREE_LIST_REF] = tb[ref] else ref = #tb + 1 end tb[ref] = key -- print("ref key_id returned ", ref) return ref end function _M.allows_subsystem(...) local total = select("#", ...) for i = 1, total do if select(i, ...) == subsystem then return end end error("unsupported subsystem: " .. subsystem, 2) end _M.FFI_OK = 0 _M.FFI_NO_REQ_CTX = -100 _M.FFI_BAD_CONTEXT = -101 _M.FFI_ERROR = -1 _M.FFI_AGAIN = -2 _M.FFI_BUSY = -3 _M.FFI_DONE = -4 _M.FFI_DECLINED = -5 _M.FFI_ABORT = -6 do local exdata ok, exdata = pcall(require, "thread.exdata") if ok and exdata then function _M.get_request() local r = exdata() if r ~= nil then return r end end else local getfenv = getfenv function _M.get_request() return getfenv(0).__ngx_req end end end return _M lua-resty-core-0.1.31/lib/resty/core/base64.lua000066400000000000000000000072461474236722600211300ustar00rootroot00000000000000-- Copyright (C) Yichun Zhang (agentzh) local ffi = require "ffi" local base = require "resty.core.base" local C = ffi.C local ffi_string = ffi.string local ngx = ngx local type = type local error = error local floor = math.floor local tostring = tostring local get_string_buf = base.get_string_buf local get_size_ptr = base.get_size_ptr local subsystem = ngx.config.subsystem local ngx_lua_ffi_encode_base64 local ngx_lua_ffi_decode_base64 if subsystem == "http" then ffi.cdef[[ size_t ngx_http_lua_ffi_encode_base64(const unsigned char *src, size_t len, unsigned char *dst, int no_padding); int ngx_http_lua_ffi_decode_base64(const unsigned char *src, size_t len, unsigned char *dst, size_t *dlen); int ngx_http_lua_ffi_decode_base64mime(const unsigned char *src, size_t len, unsigned char *dst, size_t *dlen); ]] ngx_lua_ffi_encode_base64 = C.ngx_http_lua_ffi_encode_base64 ngx_lua_ffi_decode_base64 = C.ngx_http_lua_ffi_decode_base64 elseif subsystem == "stream" then ffi.cdef[[ size_t ngx_stream_lua_ffi_encode_base64(const unsigned char *src, size_t len, unsigned char *dst, int no_padding); int ngx_stream_lua_ffi_decode_base64(const unsigned char *src, size_t len, unsigned char *dst, size_t *dlen); ]] ngx_lua_ffi_encode_base64 = C.ngx_stream_lua_ffi_encode_base64 ngx_lua_ffi_decode_base64 = C.ngx_stream_lua_ffi_decode_base64 end local function base64_encoded_length(len, no_padding) return no_padding and floor((len * 8 + 5) / 6) or floor((len + 2) / 3) * 4 end ngx.encode_base64 = function (s, no_padding) if type(s) ~= 'string' then if not s then s = '' else s = tostring(s) end end local slen = #s local no_padding_bool = false; local no_padding_int = 0; if no_padding then if no_padding ~= true then local typ = type(no_padding) error("bad no_padding: boolean expected, got " .. typ, 2) end no_padding_bool = true no_padding_int = 1; end local dlen = base64_encoded_length(slen, no_padding_bool) local dst = get_string_buf(dlen) local r_dlen = ngx_lua_ffi_encode_base64(s, slen, dst, no_padding_int) -- if dlen ~= r_dlen then error("discrepancy in len") end return ffi_string(dst, r_dlen) end local function base64_decoded_length(len) return floor((len + 3) / 4) * 3 end ngx.decode_base64 = function (s) if type(s) ~= 'string' then error("string argument only", 2) end local slen = #s local dlen = base64_decoded_length(slen) -- print("dlen: ", tonumber(dlen)) local dst = get_string_buf(dlen) local pdlen = get_size_ptr() local ok = ngx_lua_ffi_decode_base64(s, slen, dst, pdlen) if ok == 0 then return nil end return ffi_string(dst, pdlen[0]) end ngx.decode_base64mime = function (s) if type(s) ~= 'string' then error("string argument only", 2) end local slen = #s local dlen = base64_decoded_length(slen) local dst = get_string_buf(dlen) local pdlen = get_size_ptr() local ok = C.ngx_http_lua_ffi_decode_base64mime(s, slen, dst, pdlen) if ok == 0 then return nil end return ffi_string(dst, pdlen[0]) end return { version = base.version } lua-resty-core-0.1.31/lib/resty/core/coroutine.lua000066400000000000000000000014011474236722600220360ustar00rootroot00000000000000local base = require "resty.core.base" local get_request = base.get_request do local keys = {'create', 'yield', 'resume', 'status', 'wrap'} local errmsg = base.get_errmsg_ptr() local get_raw_phase = ngx.get_raw_phase for _, key in ipairs(keys) do local std = coroutine['_' .. key] local ours = coroutine['__' .. key] coroutine[key] = function (...) local r = get_request() if r ~= nil then local ctx = get_raw_phase(r, errmsg) if ctx ~= 0x020 and ctx ~= 0x040 then return ours(...) end end return std(...) end end package.loaded.coroutine = coroutine end return { version = base.version } lua-resty-core-0.1.31/lib/resty/core/ctx.lua000066400000000000000000000073241474236722600206370ustar00rootroot00000000000000-- Copyright (C) Yichun Zhang (agentzh) local ffi = require "ffi" local debug = require "debug" local base = require "resty.core.base" local misc = require "resty.core.misc" local C = ffi.C local register_getter = misc.register_ngx_magic_key_getter local register_setter = misc.register_ngx_magic_key_setter local registry = debug.getregistry() local new_tab = base.new_tab local ref_in_table = base.ref_in_table local get_request = base.get_request local FFI_NO_REQ_CTX = base.FFI_NO_REQ_CTX local FFI_OK = base.FFI_OK local error = error local setmetatable = setmetatable local type = type local subsystem = ngx.config.subsystem local ngx_lua_ffi_get_ctx_ref local ngx_lua_ffi_set_ctx_ref if subsystem == "http" then ffi.cdef[[ int ngx_http_lua_ffi_get_ctx_ref(ngx_http_request_t *r, int *in_ssl_phase, int *ssl_ctx_ref); int ngx_http_lua_ffi_set_ctx_ref(ngx_http_request_t *r, int ref); ]] ngx_lua_ffi_get_ctx_ref = C.ngx_http_lua_ffi_get_ctx_ref ngx_lua_ffi_set_ctx_ref = C.ngx_http_lua_ffi_set_ctx_ref elseif subsystem == "stream" then ffi.cdef[[ int ngx_stream_lua_ffi_get_ctx_ref(ngx_stream_lua_request_t *r, int *in_ssl_phase, int *ssl_ctx_ref); int ngx_stream_lua_ffi_set_ctx_ref(ngx_stream_lua_request_t *r, int ref); ]] ngx_lua_ffi_get_ctx_ref = C.ngx_stream_lua_ffi_get_ctx_ref ngx_lua_ffi_set_ctx_ref = C.ngx_stream_lua_ffi_set_ctx_ref end local _M = { _VERSION = base.version } -- use a new ctxs table to make LuaJIT JIT compiler happy to generate more -- efficient machine code. local ctxs = {} registry.ngx_lua_ctx_tables = ctxs local get_ctx_table do local in_ssl_phase = ffi.new("int[1]") local ssl_ctx_ref = ffi.new("int[1]") function get_ctx_table(ctx) local r = get_request() if not r then error("no request found") end local ctx_ref = ngx_lua_ffi_get_ctx_ref(r, in_ssl_phase, ssl_ctx_ref) if ctx_ref == FFI_NO_REQ_CTX then error("no request ctx found") end if ctx_ref < 0 then ctx_ref = ssl_ctx_ref[0] if ctx_ref > 0 and ctxs[ctx_ref] then if in_ssl_phase[0] ~= 0 then return ctxs[ctx_ref] end if not ctx then ctx = new_tab(0, 4) end ctx = setmetatable(ctx, ctxs[ctx_ref]) else if in_ssl_phase[0] ~= 0 then if not ctx then ctx = new_tab(1, 4) end -- to avoid creating another table, we assume the users -- won't overwrite the `__index` key ctx.__index = ctx elseif not ctx then ctx = new_tab(0, 4) end end ctx_ref = ref_in_table(ctxs, ctx) if ngx_lua_ffi_set_ctx_ref(r, ctx_ref) ~= FFI_OK then return nil end return ctx end return ctxs[ctx_ref] end end register_getter("ctx", get_ctx_table) _M.get_ctx_table = get_ctx_table local function set_ctx_table(ctx) local ctx_type = type(ctx) if ctx_type ~= "table" then error("ctx should be a table while getting a " .. ctx_type) end local r = get_request() if not r then error("no request found") end local ctx_ref = ngx_lua_ffi_get_ctx_ref(r, nil, nil) if ctx_ref == FFI_NO_REQ_CTX then error("no request ctx found") end if ctx_ref < 0 then ctx_ref = ref_in_table(ctxs, ctx) ngx_lua_ffi_set_ctx_ref(r, ctx_ref) return end ctxs[ctx_ref] = ctx end register_setter("ctx", set_ctx_table) return _M lua-resty-core-0.1.31/lib/resty/core/exit.lua000066400000000000000000000026451474236722600210130ustar00rootroot00000000000000-- Copyright (C) Yichun Zhang (agentzh) local ffi = require "ffi" local base = require "resty.core.base" local C = ffi.C local ffi_string = ffi.string local ngx = ngx local error = error local get_string_buf = base.get_string_buf local get_size_ptr = base.get_size_ptr local get_request = base.get_request local co_yield = coroutine._yield local subsystem = ngx.config.subsystem local ngx_lua_ffi_exit if subsystem == "http" then ffi.cdef[[ int ngx_http_lua_ffi_exit(ngx_http_request_t *r, int status, unsigned char *err, size_t *errlen); ]] ngx_lua_ffi_exit = C.ngx_http_lua_ffi_exit elseif subsystem == "stream" then ffi.cdef[[ int ngx_stream_lua_ffi_exit(ngx_stream_lua_request_t *r, int status, unsigned char *err, size_t *errlen); ]] ngx_lua_ffi_exit = C.ngx_stream_lua_ffi_exit end local ERR_BUF_SIZE = 128 local FFI_DONE = base.FFI_DONE ngx.exit = function (rc) local err = get_string_buf(ERR_BUF_SIZE) local errlen = get_size_ptr() local r = get_request() if r == nil then error("no request found") end errlen[0] = ERR_BUF_SIZE rc = ngx_lua_ffi_exit(r, rc, err, errlen) if rc == 0 then -- print("yielding...") return co_yield() end if rc == FFI_DONE then return end error(ffi_string(err, errlen[0]), 2) end return { version = base.version } lua-resty-core-0.1.31/lib/resty/core/hash.lua000066400000000000000000000076511474236722600207670ustar00rootroot00000000000000-- Copyright (C) Yichun Zhang (agentzh) local ffi = require "ffi" local base = require "resty.core.base" local C = ffi.C local ffi_new = ffi.new local ffi_string = ffi.string local ngx = ngx local type = type local error = error local tostring = tostring local subsystem = ngx.config.subsystem local ngx_lua_ffi_md5 local ngx_lua_ffi_md5_bin local ngx_lua_ffi_sha1_bin local ngx_lua_ffi_crc32_long local ngx_lua_ffi_crc32_short if subsystem == "http" then ffi.cdef[[ void ngx_http_lua_ffi_md5_bin(const unsigned char *src, size_t len, unsigned char *dst); void ngx_http_lua_ffi_md5(const unsigned char *src, size_t len, unsigned char *dst); int ngx_http_lua_ffi_sha1_bin(const unsigned char *src, size_t len, unsigned char *dst); unsigned int ngx_http_lua_ffi_crc32_long(const unsigned char *src, size_t len); unsigned int ngx_http_lua_ffi_crc32_short(const unsigned char *src, size_t len); ]] ngx_lua_ffi_md5 = C.ngx_http_lua_ffi_md5 ngx_lua_ffi_md5_bin = C.ngx_http_lua_ffi_md5_bin ngx_lua_ffi_sha1_bin = C.ngx_http_lua_ffi_sha1_bin ngx_lua_ffi_crc32_short = C.ngx_http_lua_ffi_crc32_short ngx_lua_ffi_crc32_long = C.ngx_http_lua_ffi_crc32_long elseif subsystem == "stream" then ffi.cdef[[ void ngx_stream_lua_ffi_md5_bin(const unsigned char *src, size_t len, unsigned char *dst); void ngx_stream_lua_ffi_md5(const unsigned char *src, size_t len, unsigned char *dst); int ngx_stream_lua_ffi_sha1_bin(const unsigned char *src, size_t len, unsigned char *dst); unsigned int ngx_stream_lua_ffi_crc32_long(const unsigned char *src, size_t len); unsigned int ngx_stream_lua_ffi_crc32_short(const unsigned char *src, size_t len); ]] ngx_lua_ffi_md5 = C.ngx_stream_lua_ffi_md5 ngx_lua_ffi_md5_bin = C.ngx_stream_lua_ffi_md5_bin ngx_lua_ffi_sha1_bin = C.ngx_stream_lua_ffi_sha1_bin ngx_lua_ffi_crc32_short = C.ngx_stream_lua_ffi_crc32_short ngx_lua_ffi_crc32_long = C.ngx_stream_lua_ffi_crc32_long end local MD5_DIGEST_LEN = 16 local md5_buf = ffi_new("unsigned char[?]", MD5_DIGEST_LEN) ngx.md5_bin = function (s) if type(s) ~= 'string' then if not s then s = '' else s = tostring(s) end end ngx_lua_ffi_md5_bin(s, #s, md5_buf) return ffi_string(md5_buf, MD5_DIGEST_LEN) end local MD5_HEX_DIGEST_LEN = MD5_DIGEST_LEN * 2 local md5_hex_buf = ffi_new("unsigned char[?]", MD5_HEX_DIGEST_LEN) ngx.md5 = function (s) if type(s) ~= 'string' then if not s then s = '' else s = tostring(s) end end ngx_lua_ffi_md5(s, #s, md5_hex_buf) return ffi_string(md5_hex_buf, MD5_HEX_DIGEST_LEN) end local SHA_DIGEST_LEN = 20 local sha_buf = ffi_new("unsigned char[?]", SHA_DIGEST_LEN) ngx.sha1_bin = function (s) if type(s) ~= 'string' then if not s then s = '' else s = tostring(s) end end local ok = ngx_lua_ffi_sha1_bin(s, #s, sha_buf) if ok == 0 then error("SHA-1 support missing in Nginx") end return ffi_string(sha_buf, SHA_DIGEST_LEN) end ngx.crc32_short = function (s) if type(s) ~= "string" then if not s then s = "" else s = tostring(s) end end return ngx_lua_ffi_crc32_short(s, #s) end ngx.crc32_long = function (s) if type(s) ~= "string" then if not s then s = "" else s = tostring(s) end end return ngx_lua_ffi_crc32_long(s, #s) end return { version = base.version } lua-resty-core-0.1.31/lib/resty/core/misc.lua000066400000000000000000000133211474236722600207660ustar00rootroot00000000000000-- Copyright (C) Yichun Zhang (agentzh) local base = require "resty.core.base" local ffi = require "ffi" local os = require "os" local C = ffi.C local ffi_new = ffi.new local ffi_str = ffi.string local ngx = ngx local type = type local error = error local rawget = rawget local rawset = rawset local tonumber = tonumber local setmetatable = setmetatable local FFI_OK = base.FFI_OK local FFI_NO_REQ_CTX = base.FFI_NO_REQ_CTX local FFI_BAD_CONTEXT = base.FFI_BAD_CONTEXT local new_tab = base.new_tab local get_request = base.get_request local get_size_ptr = base.get_size_ptr local get_string_buf = base.get_string_buf local get_string_buf_size = base.get_string_buf_size local subsystem = ngx.config.subsystem local ngx_lua_ffi_get_resp_status local ngx_lua_ffi_get_conf_env local ngx_magic_key_getters local ngx_magic_key_setters local _M = new_tab(0, 3) local ngx_mt = new_tab(0, 2) if subsystem == "http" then ngx_magic_key_getters = new_tab(0, 4) ngx_magic_key_setters = new_tab(0, 2) elseif subsystem == "stream" then ngx_magic_key_getters = new_tab(0, 2) ngx_magic_key_setters = new_tab(0, 1) end local function register_getter(key, func) ngx_magic_key_getters[key] = func end _M.register_ngx_magic_key_getter = register_getter local function register_setter(key, func) ngx_magic_key_setters[key] = func end _M.register_ngx_magic_key_setter = register_setter ngx_mt.__index = function (tb, key) local f = ngx_magic_key_getters[key] if f then return f() end return rawget(tb, key) end ngx_mt.__newindex = function (tb, key, ctx) local f = ngx_magic_key_setters[key] if f then return f(ctx) end return rawset(tb, key, ctx) end setmetatable(ngx, ngx_mt) if subsystem == "http" then ffi.cdef[[ int ngx_http_lua_ffi_get_resp_status(ngx_http_request_t *r); int ngx_http_lua_ffi_set_resp_status(ngx_http_request_t *r, int r); int ngx_http_lua_ffi_is_subrequest(ngx_http_request_t *r); int ngx_http_lua_ffi_headers_sent(ngx_http_request_t *r); int ngx_http_lua_ffi_get_conf_env(const unsigned char *name, unsigned char **env_buf, size_t *name_len); int ngx_http_lua_ffi_req_is_internal(ngx_http_request_t *r); ]] ngx_lua_ffi_get_resp_status = C.ngx_http_lua_ffi_get_resp_status ngx_lua_ffi_get_conf_env = C.ngx_http_lua_ffi_get_conf_env -- ngx.status local function set_status(status) local r = get_request() if not r then error("no request found") end if type(status) ~= 'number' then status = tonumber(status) end local rc = C.ngx_http_lua_ffi_set_resp_status(r, status) if rc == FFI_BAD_CONTEXT then error("API disabled in the current context", 2) end end register_setter("status", set_status) -- ngx.is_subrequest local function is_subreq() local r = get_request() if not r then error("no request found") end local rc = C.ngx_http_lua_ffi_is_subrequest(r) if rc == FFI_BAD_CONTEXT then error("API disabled in the current context", 2) end return rc == 1 end register_getter("is_subrequest", is_subreq) -- ngx.headers_sent local function headers_sent() local r = get_request() if not r then error("no request found") end local rc = C.ngx_http_lua_ffi_headers_sent(r) if rc == FFI_NO_REQ_CTX then error("no request ctx found") end if rc == FFI_BAD_CONTEXT then error("API disabled in the current context", 2) end return rc == 1 end register_getter("headers_sent", headers_sent) -- ngx.req.is_internal function ngx.req.is_internal() local r = get_request() if not r then error("no request found") end local rc = C.ngx_http_lua_ffi_req_is_internal(r) if rc == FFI_BAD_CONTEXT then error("API disabled in the current context") end return rc == 1 end elseif subsystem == "stream" then ffi.cdef[[ int ngx_stream_lua_ffi_get_resp_status(ngx_stream_lua_request_t *r); int ngx_stream_lua_ffi_get_conf_env(const unsigned char *name, unsigned char **env_buf, size_t *name_len); ]] ngx_lua_ffi_get_resp_status = C.ngx_stream_lua_ffi_get_resp_status ngx_lua_ffi_get_conf_env = C.ngx_stream_lua_ffi_get_conf_env end -- ngx.status local function get_status() local r = get_request() if not r then error("no request found") end local rc = ngx_lua_ffi_get_resp_status(r) if rc == FFI_BAD_CONTEXT then error("API disabled in the current context", 2) end return rc end register_getter("status", get_status) do local _getenv = os.getenv local env_ptr = ffi_new("unsigned char *[1]") os.getenv = function (name) local r = get_request() if r then -- past init_by_lua* phase now os.getenv = _getenv env_ptr = nil return os.getenv(name) end local size = get_string_buf_size() env_ptr[0] = get_string_buf(size) local name_len_ptr = get_size_ptr() local rc = ngx_lua_ffi_get_conf_env(name, env_ptr, name_len_ptr) if rc == FFI_OK then return ffi_str(env_ptr[0] + name_len_ptr[0] + 1) end -- FFI_DECLINED local value = _getenv(name) if value ~= nil then return value end return nil end end _M._VERSION = base.version return _M lua-resty-core-0.1.31/lib/resty/core/ndk.lua000066400000000000000000000042031474236722600206060ustar00rootroot00000000000000-- Copyright (C) by OpenResty Inc. local ffi = require 'ffi' local base = require "resty.core.base" base.allows_subsystem('http') local C = ffi.C local ffi_cast = ffi.cast local ffi_new = ffi.new local ffi_str = ffi.string local FFI_OK = base.FFI_OK local new_tab = base.new_tab local get_string_buf = base.get_string_buf local get_request = base.get_request local setmetatable = setmetatable local type = type local tostring = tostring local error = error local _M = { version = base.version } ffi.cdef[[ typedef void * ndk_set_var_value_pt; int ngx_http_lua_ffi_ndk_lookup_directive(const unsigned char *var_data, size_t var_len, ndk_set_var_value_pt *func); int ngx_http_lua_ffi_ndk_set_var_get(ngx_http_request_t *r, ndk_set_var_value_pt func, const unsigned char *arg_data, size_t arg_len, ngx_http_lua_ffi_str_t *value); ]] local func_p = ffi_new("void*[1]") local ffi_str_size = ffi.sizeof("ngx_http_lua_ffi_str_t") local ffi_str_type = ffi.typeof("ngx_http_lua_ffi_str_t*") local function ndk_set_var_get(self, var) if type(var) ~= "string" then var = tostring(var) end if C.ngx_http_lua_ffi_ndk_lookup_directive(var, #var, func_p) ~= FFI_OK then error('ndk.set_var: directive "' .. var .. '" not found or does not use ndk_set_var_value', 2) end local func = func_p[0] return function (arg) local r = get_request() if not r then error("no request found") end if type(arg) ~= "string" then arg = tostring(arg) end local buf = get_string_buf(ffi_str_size) local value = ffi_cast(ffi_str_type, buf) local rc = C.ngx_http_lua_ffi_ndk_set_var_get(r, func, arg, #arg, value) if rc ~= FFI_OK then error("calling directive " .. var .. " failed with code " .. rc, 2) end return ffi_str(value.data, value.len) end end local function ndk_set_var_set() error("not allowed", 2) end if ndk then local mt = new_tab(0, 2) mt.__newindex = ndk_set_var_set mt.__index = ndk_set_var_get ndk.set_var = setmetatable(new_tab(0, 0), mt) end return _M lua-resty-core-0.1.31/lib/resty/core/param.lua000066400000000000000000000045421474236722600211400ustar00rootroot00000000000000-- Copyright (C) Yichun Zhang (agentzh) local ffi = require 'ffi' local base = require "resty.core.base" require "resty.core.phase" -- for ngx.get_phase local C = ffi.C local ffi_str = ffi.string local FFI_AGAIN = base.FFI_AGAIN local FFI_OK = base.FFI_OK local get_request = base.get_request local get_string_buf = base.get_string_buf local getmetatable = getmetatable local ngx = ngx local ngx_phase = ngx.get_phase local _M = { version = base.version } ffi.cdef[[ typedef unsigned char u_char; void ngx_http_lua_ffi_get_setby_param(ngx_http_request_t *r, int idx, u_char **data, size_t *len); int ngx_http_lua_ffi_get_body_filter_param_eof(ngx_http_request_t *r); int ngx_http_lua_ffi_get_body_filter_param_body(ngx_http_request_t *r, u_char **data_p, size_t *len_p); int ngx_http_lua_ffi_copy_body_filter_param_body(ngx_http_request_t *r, u_char *data); ]] local data_p = ffi.new("unsigned char*[1]") local len_p = ffi.new("size_t[1]") local function get_setby_param(r, idx) C.ngx_http_lua_ffi_get_setby_param(r, idx, data_p, len_p) if len_p[0] == 0 then return nil end return ffi_str(data_p[0], len_p[0]) end local function get_body_filter_param(r, idx) if idx == 1 then data_p[0] = nil local rc = C.ngx_http_lua_ffi_get_body_filter_param_body(r, data_p, len_p) if rc == FFI_AGAIN then local buf = get_string_buf(len_p[0]) assert(C.ngx_http_lua_ffi_copy_body_filter_param_body(r, buf) == FFI_OK) return ffi_str(buf, len_p[0]) end if len_p[0] == 0 then return "" end return ffi_str(data_p[0], len_p[0]) elseif idx == 2 then local rc = C.ngx_http_lua_ffi_get_body_filter_param_eof(r) return rc == 1 else return nil end end local function get_param(tb, idx) local r = get_request() if not r then error("no request found") end local phase = ngx_phase() if phase == "set" then return get_setby_param(r, idx) end if phase == "body_filter" then return get_body_filter_param(r, idx) end error("API disabled in the current context") end do local mt = getmetatable(ngx.arg) mt.__index = get_param end return _M lua-resty-core-0.1.31/lib/resty/core/phase.lua000066400000000000000000000027511474236722600211400ustar00rootroot00000000000000local ffi = require 'ffi' local base = require "resty.core.base" local C = ffi.C local FFI_ERROR = base.FFI_ERROR local get_request = base.get_request local error = error local tostring = tostring ffi.cdef[[ int ngx_http_lua_ffi_get_phase(ngx_http_request_t *r, char **err) ]] local errmsg = base.get_errmsg_ptr() local context_names = { [0x0001] = "set", [0x0002] = "rewrite", [0x0004] = "access", [0x0008] = "content", [0x0010] = "log", [0x0020] = "header_filter", [0x0040] = "body_filter", [0x0080] = "timer", [0x0100] = "init_worker", [0x0200] = "balancer", [0x0400] = "ssl_cert", [0x0800] = "ssl_session_store", [0x1000] = "ssl_session_fetch", [0x2000] = "exit_worker", [0x4000] = "ssl_client_hello", [0x8000] = "server_rewrite", } function ngx.get_phase() local r = get_request() -- if we have no request object, assume we are called from the "init" phase if not r then return "init" end local context = C.ngx_http_lua_ffi_get_phase(r, errmsg) if context == FFI_ERROR then -- NGX_ERROR error(errmsg, 2) end local phase = context_names[context] if not phase then error("unknown phase: " .. tostring(context)) end return phase end function ngx.get_raw_phase(r) local context = C.ngx_http_lua_ffi_get_phase(r, errmsg) if context == FFI_ERROR then -- NGX_ERROR error(errmsg, 2) end return context end return { version = base.version } lua-resty-core-0.1.31/lib/resty/core/regex.lua000066400000000000000000001051641474236722600211540ustar00rootroot00000000000000-- Copyright (C) Yichun Zhang (agentzh) local ffi = require 'ffi' local base = require "resty.core.base" local bit = require "bit" local subsystem = ngx.config.subsystem require "resty.core.time" -- for ngx.now used by resty.lrucache if subsystem == 'http' then require "resty.core.phase" -- for ngx.get_phase end local lrucache = require "resty.lrucache" local lrucache_get = lrucache.get local lrucache_set = lrucache.set local ffi_string = ffi.string local ffi_gc = ffi.gc local ffi_copy = ffi.copy local ffi_cast = ffi.cast local C = ffi.C local bor = bit.bor local band = bit.band local lshift = bit.lshift local sub = string.sub local fmt = string.format local byte = string.byte local ngx = ngx local type = type local tostring = tostring local error = error local setmetatable = setmetatable local tonumber = tonumber local get_string_buf = base.get_string_buf local get_string_buf_size = base.get_string_buf_size local new_tab = base.new_tab local ngx_phase = ngx.get_phase local ngx_log = ngx.log local ngx_NOTICE = ngx.NOTICE local _M = { version = base.version } ngx.re = new_tab(0, 5) local pcre_ver_fn if subsystem == 'http' then ffi.cdef[[ const char *ngx_http_lua_ffi_pcre_version(void); ]] pcre_ver_fn = C.ngx_http_lua_ffi_pcre_version elseif subsystem == 'stream' then ffi.cdef[[ const char *ngx_stream_lua_ffi_pcre_version(void); ]] pcre_ver_fn = C.ngx_stream_lua_ffi_pcre_version else error("unsupported subsystem: " .. tostring(subsystem)) end local pcre_ver if not pcall(function() pcre_ver = ffi_string(pcre_ver_fn()) end) then setmetatable(ngx.re, { __index = function(_, key) error("no support for 'ngx.re." .. key .. "': OpenResty was " .. "compiled without PCRE support", 2) end }) _M.no_pcre = true return _M end local MAX_ERR_MSG_LEN = 256 local FLAG_COMPILE_ONCE = 0x01 local FLAG_DFA = 0x02 local FLAG_JIT = 0x04 local FLAG_DUPNAMES = 0x08 local FLAG_NO_UTF8_CHECK = 0x10 local PCRE_CASELESS = 0x0000001 local PCRE_MULTILINE = 0x0000002 local PCRE_DOTALL = 0x0000004 local PCRE_EXTENDED = 0x0000008 local PCRE_ANCHORED = 0x0000010 local PCRE_UTF8 = 0x0000800 local PCRE_DUPNAMES = 0x0080000 local PCRE_JAVASCRIPT_COMPAT = 0x2000000 -- PCRE2_ERROR_NOMATCH uses the same value local PCRE_ERROR_NOMATCH = -1 local regex_match_cache local regex_sub_func_cache = new_tab(0, 4) local regex_sub_str_cache = new_tab(0, 4) local max_regex_cache_size local regex_cache_size = 0 local script_engine local ngx_lua_ffi_max_regex_cache_size local ngx_lua_ffi_destroy_regex local ngx_lua_ffi_compile_regex local ngx_lua_ffi_exec_regex local ngx_lua_ffi_create_script_engine local ngx_lua_ffi_destroy_script_engine local ngx_lua_ffi_init_script_engine local ngx_lua_ffi_compile_replace_template local ngx_lua_ffi_script_eval_len local ngx_lua_ffi_script_eval_data -- PCRE 8.43 on macOS introduced the MAP_JIT option when creating the memory -- region used to store JIT compiled code, which does not survive across -- `fork()`, causing further usage of PCRE JIT compiler to segfault in worker -- processes. -- -- This flag prevents any regex used in the init phase to be JIT compiled or -- cached when running under macOS, even if the user requests so. Caching is -- thus disabled to prevent further calls of same regex in worker to have poor -- performance. -- -- TODO: improve this workaround when PCRE allows for unspecifying the MAP_JIT -- option. local no_jit_in_init local pcre_ver_num local maj, min = string.match(pcre_ver, "^(%d+)%.(%d+)") if maj and min then pcre_ver_num = tonumber(maj .. min) end if jit.os == "OSX" then if pcre_ver_num == nil then -- assume this version is faulty as well no_jit_in_init = true -- PCRE2 is also subject to this issue on macOS elseif pcre_ver_num >= 843 then no_jit_in_init = true end end -- pcre2 if pcre_ver_num > 845 then -- option PCRE_CASELESS = 0x00000008 PCRE_MULTILINE = 0x00000400 PCRE_DOTALL = 0x00000020 PCRE_EXTENDED = 0x00000080 PCRE_ANCHORED = 0x80000000 PCRE_UTF8 = 0x00080000 PCRE_DUPNAMES = 0x00000040 -- In the pcre2, The PCRE_JAVASCRIPT_COMPAT option has been split into -- independent functional options PCRE2_ALT_BSUX, PCRE2_ALLOW_EMPTY_CLASS, -- and PCRE2_MATCH_UNSET_BACKREF. local PCRE2_ALT_BSUX = 0x00000002 local PCRE2_ALLOW_EMPTY_CLASS = 0x00000001 local PCRE2_MATCH_UNSET_BACKREF = 0x00000200 PCRE_JAVASCRIPT_COMPAT = bor(PCRE2_ALT_BSUX, PCRE2_ALLOW_EMPTY_CLASS) PCRE_JAVASCRIPT_COMPAT = bor(PCRE2_MATCH_UNSET_BACKREF, PCRE_JAVASCRIPT_COMPAT) end if subsystem == 'http' then ffi.cdef[[ typedef struct { ngx_str_t value; void *lengths; void *values; } ngx_http_lua_complex_value_t; typedef struct { void *pool; unsigned char *name_table; int name_count; int name_entry_size; int ncaptures; int *captures; void *regex; void *regex_sd; ngx_http_lua_complex_value_t *replace; const char *pattern; } ngx_http_lua_regex_t; ngx_http_lua_regex_t * ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len, int flags, int pcre_opts, unsigned char *errstr, size_t errstr_size); int ngx_http_lua_ffi_exec_regex(ngx_http_lua_regex_t *re, int flags, const unsigned char *s, size_t len, int pos); void ngx_http_lua_ffi_destroy_regex(ngx_http_lua_regex_t *re); int ngx_http_lua_ffi_compile_replace_template(ngx_http_lua_regex_t *re, const unsigned char *replace_data, size_t replace_len); struct ngx_http_lua_script_engine_s; typedef struct ngx_http_lua_script_engine_s *ngx_http_lua_script_engine_t; ngx_http_lua_script_engine_t *ngx_http_lua_ffi_create_script_engine(void); void ngx_http_lua_ffi_init_script_engine(ngx_http_lua_script_engine_t *e, const unsigned char *subj, ngx_http_lua_regex_t *compiled, int count); void ngx_http_lua_ffi_destroy_script_engine( ngx_http_lua_script_engine_t *e); size_t ngx_http_lua_ffi_script_eval_len(ngx_http_lua_script_engine_t *e, ngx_http_lua_complex_value_t *cv); size_t ngx_http_lua_ffi_script_eval_data(ngx_http_lua_script_engine_t *e, ngx_http_lua_complex_value_t *cv, unsigned char *dst); uint32_t ngx_http_lua_ffi_max_regex_cache_size(void); ]] ngx_lua_ffi_max_regex_cache_size = C.ngx_http_lua_ffi_max_regex_cache_size ngx_lua_ffi_destroy_regex = C.ngx_http_lua_ffi_destroy_regex ngx_lua_ffi_compile_regex = C.ngx_http_lua_ffi_compile_regex ngx_lua_ffi_exec_regex = C.ngx_http_lua_ffi_exec_regex ngx_lua_ffi_create_script_engine = C.ngx_http_lua_ffi_create_script_engine ngx_lua_ffi_init_script_engine = C.ngx_http_lua_ffi_init_script_engine ngx_lua_ffi_destroy_script_engine = C.ngx_http_lua_ffi_destroy_script_engine ngx_lua_ffi_compile_replace_template = C.ngx_http_lua_ffi_compile_replace_template ngx_lua_ffi_script_eval_len = C.ngx_http_lua_ffi_script_eval_len ngx_lua_ffi_script_eval_data = C.ngx_http_lua_ffi_script_eval_data elseif subsystem == 'stream' then ffi.cdef[[ typedef struct { ngx_str_t value; void *lengths; void *values; } ngx_stream_lua_complex_value_t; typedef struct { void *pool; unsigned char *name_table; int name_count; int name_entry_size; int ncaptures; int *captures; void *regex; void *regex_sd; ngx_stream_lua_complex_value_t *replace; const char *pattern; } ngx_stream_lua_regex_t; ngx_stream_lua_regex_t * ngx_stream_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len, int flags, int pcre_opts, unsigned char *errstr, size_t errstr_size); int ngx_stream_lua_ffi_exec_regex(ngx_stream_lua_regex_t *re, int flags, const unsigned char *s, size_t len, int pos); void ngx_stream_lua_ffi_destroy_regex(ngx_stream_lua_regex_t *re); int ngx_stream_lua_ffi_compile_replace_template(ngx_stream_lua_regex_t *re, const unsigned char *replace_data, size_t replace_len); struct ngx_stream_lua_script_engine_s; typedef struct ngx_stream_lua_script_engine_s *ngx_stream_lua_script_engine_t; ngx_stream_lua_script_engine_t * ngx_stream_lua_ffi_create_script_engine(void); void ngx_stream_lua_ffi_init_script_engine( ngx_stream_lua_script_engine_t *e, const unsigned char *subj, ngx_stream_lua_regex_t *compiled, int count); void ngx_stream_lua_ffi_destroy_script_engine( ngx_stream_lua_script_engine_t *e); size_t ngx_stream_lua_ffi_script_eval_len( ngx_stream_lua_script_engine_t *e, ngx_stream_lua_complex_value_t *cv); size_t ngx_stream_lua_ffi_script_eval_data( ngx_stream_lua_script_engine_t *e, ngx_stream_lua_complex_value_t *cv, unsigned char *dst); uint32_t ngx_stream_lua_ffi_max_regex_cache_size(void); ]] ngx_lua_ffi_max_regex_cache_size = C.ngx_stream_lua_ffi_max_regex_cache_size ngx_lua_ffi_destroy_regex = C.ngx_stream_lua_ffi_destroy_regex ngx_lua_ffi_compile_regex = C.ngx_stream_lua_ffi_compile_regex ngx_lua_ffi_exec_regex = C.ngx_stream_lua_ffi_exec_regex ngx_lua_ffi_create_script_engine = C.ngx_stream_lua_ffi_create_script_engine ngx_lua_ffi_init_script_engine = C.ngx_stream_lua_ffi_init_script_engine ngx_lua_ffi_destroy_script_engine = C.ngx_stream_lua_ffi_destroy_script_engine ngx_lua_ffi_compile_replace_template = C.ngx_stream_lua_ffi_compile_replace_template ngx_lua_ffi_script_eval_len = C.ngx_stream_lua_ffi_script_eval_len ngx_lua_ffi_script_eval_data = C.ngx_stream_lua_ffi_script_eval_data end local c_str_type = ffi.typeof("const char *") local cached_re_opts = new_tab(0, 4) local buf_grow_ratio = 2 function _M.set_buf_grow_ratio(ratio) buf_grow_ratio = ratio end local function get_max_regex_cache_size() if max_regex_cache_size then return max_regex_cache_size end max_regex_cache_size = ngx_lua_ffi_max_regex_cache_size() return max_regex_cache_size end local regex_cache_is_empty = true function _M.is_regex_cache_empty() return regex_cache_is_empty end local function lrucache_set_wrapper(...) regex_cache_is_empty = false lrucache_set(...) end local parse_regex_opts = function (opts) local t = cached_re_opts[opts] if t then return t[1], t[2] end local flags = 0 local pcre_opts = 0 local len = #opts for i = 1, len do local opt = byte(opts, i) if opt == byte("o") then flags = bor(flags, FLAG_COMPILE_ONCE) elseif opt == byte("j") then flags = bor(flags, FLAG_JIT) elseif opt == byte("i") then pcre_opts = bor(pcre_opts, PCRE_CASELESS) elseif opt == byte("s") then pcre_opts = bor(pcre_opts, PCRE_DOTALL) elseif opt == byte("m") then pcre_opts = bor(pcre_opts, PCRE_MULTILINE) elseif opt == byte("u") then pcre_opts = bor(pcre_opts, PCRE_UTF8) elseif opt == byte("U") then pcre_opts = bor(pcre_opts, PCRE_UTF8) flags = bor(flags, FLAG_NO_UTF8_CHECK) elseif opt == byte("x") then pcre_opts = bor(pcre_opts, PCRE_EXTENDED) elseif opt == byte("d") then flags = bor(flags, FLAG_DFA) elseif opt == byte("a") then pcre_opts = bor(pcre_opts, PCRE_ANCHORED) elseif opt == byte("D") then pcre_opts = bor(pcre_opts, PCRE_DUPNAMES) flags = bor(flags, FLAG_DUPNAMES) elseif opt == byte("J") then pcre_opts = bor(pcre_opts, PCRE_JAVASCRIPT_COMPAT) else error(fmt('unknown flag "%s" (flags "%s")', sub(opts, i, i), opts), 3) end end cached_re_opts[opts] = {flags, pcre_opts} return flags, pcre_opts end if no_jit_in_init then local parse_regex_opts_ = parse_regex_opts parse_regex_opts = function (opts) if ngx_phase() ~= "init" then -- past init_by_lua* phase now parse_regex_opts = parse_regex_opts_ return parse_regex_opts(opts) end local t = cached_re_opts[opts] if t then return t[1], t[2] end local flags = 0 local pcre_opts = 0 local len = #opts for i = 1, len do local opt = byte(opts, i) if opt == byte("o") then ngx_log(ngx_NOTICE, "regex compilation cache disabled in init ", "phase under macOS") elseif opt == byte("j") then ngx_log(ngx_NOTICE, "regex compilation disabled in init ", "phase under macOS") elseif opt == byte("i") then pcre_opts = bor(pcre_opts, PCRE_CASELESS) elseif opt == byte("s") then pcre_opts = bor(pcre_opts, PCRE_DOTALL) elseif opt == byte("m") then pcre_opts = bor(pcre_opts, PCRE_MULTILINE) elseif opt == byte("u") then pcre_opts = bor(pcre_opts, PCRE_UTF8) elseif opt == byte("U") then pcre_opts = bor(pcre_opts, PCRE_UTF8) flags = bor(flags, FLAG_NO_UTF8_CHECK) elseif opt == byte("x") then pcre_opts = bor(pcre_opts, PCRE_EXTENDED) elseif opt == byte("d") then flags = bor(flags, FLAG_DFA) elseif opt == byte("a") then pcre_opts = bor(pcre_opts, PCRE_ANCHORED) elseif opt == byte("D") then pcre_opts = bor(pcre_opts, PCRE_DUPNAMES) flags = bor(flags, FLAG_DUPNAMES) elseif opt == byte("J") then pcre_opts = bor(pcre_opts, PCRE_JAVASCRIPT_COMPAT) else error(fmt('unknown flag "%s" (flags "%s")', sub(opts, i, i), opts), 3) end end cached_re_opts[opts] = {flags, pcre_opts} return flags, pcre_opts end end local function collect_named_captures(compiled, flags, res) local name_count = compiled.name_count local name_table = compiled.name_table local entry_size = compiled.name_entry_size local ind = 0 local dup_names = (band(flags, FLAG_DUPNAMES) ~= 0) for i = 1, name_count do local n = bor(lshift(name_table[ind], 8), name_table[ind + 1]) -- ngx.say("n = ", n) local name = ffi_string(name_table + ind + 2) local cap = res[n] if dup_names then -- unmatched captures (false) are not collected if cap then local old = res[name] if old then old[#old + 1] = cap else res[name] = {cap} end end else res[name] = cap end ind = ind + entry_size end end local function collect_captures(compiled, rc, subj, flags, res) local cap = compiled.captures local ncap = compiled.ncaptures local name_count = compiled.name_count if not res then res = new_tab(ncap, name_count) end local i = 0 local n = 0 while i <= ncap do if i > rc then res[i] = false else local from = cap[n] if from >= 0 then local to = cap[n + 1] res[i] = sub(subj, from + 1, to) else res[i] = false end end i = i + 1 n = n + 2 end if name_count > 0 then collect_named_captures(compiled, flags, res) end return res end _M.collect_captures = collect_captures local function destroy_compiled_regex(compiled) ngx_lua_ffi_destroy_regex(ffi_gc(compiled, nil)) end _M.destroy_compiled_regex = destroy_compiled_regex local function re_match_compile(regex, opts) local flags = 0 local pcre_opts = 0 if opts then flags, pcre_opts = parse_regex_opts(opts) else opts = "" end local compiled, key local compile_once = (band(flags, FLAG_COMPILE_ONCE) == 1) -- FIXME: better put this in the outer scope when fixing the ngx.re API's -- compatibility in the init_by_lua* context. if not regex_match_cache then local sz = get_max_regex_cache_size() if sz <= 0 then compile_once = false else regex_match_cache = lrucache.new(sz) end end if compile_once then key = regex .. '\0' .. opts compiled = lrucache_get(regex_match_cache, key) end -- compile the regex if compiled == nil then -- print("compiled regex not found, compiling regex...") local errbuf = get_string_buf(MAX_ERR_MSG_LEN) compiled = ngx_lua_ffi_compile_regex(regex, #regex, flags, pcre_opts, errbuf, MAX_ERR_MSG_LEN) if compiled == nil then return nil, ffi_string(errbuf) end ffi_gc(compiled, ngx_lua_ffi_destroy_regex) -- print("ncaptures: ", compiled.ncaptures) if compile_once then -- print("inserting compiled regex into cache") lrucache_set_wrapper(regex_match_cache, key, compiled) end end return compiled, compile_once, flags end _M.re_match_compile = re_match_compile local function re_match_helper(subj, regex, opts, ctx, want_caps, res, nth) -- we need to cast this to strings to avoid exceptions when they are -- something else. subj = tostring(subj) local compiled, compile_once, flags = re_match_compile(regex, opts) if compiled == nil then -- compiled_once holds the error string if not want_caps then return nil, nil, compile_once end return nil, compile_once end -- exec the compiled regex local rc do local pos if ctx then pos = ctx.pos if not pos or pos <= 0 then pos = 0 else pos = pos - 1 end else pos = 0 end rc = ngx_lua_ffi_exec_regex(compiled, flags, subj, #subj, pos) end if rc == PCRE_ERROR_NOMATCH then if not compile_once then destroy_compiled_regex(compiled) end return nil end if rc < 0 then if not compile_once then destroy_compiled_regex(compiled) end if not want_caps then return nil, nil, "pcre_exec() failed: " .. rc end return nil, "pcre_exec() failed: " .. rc end if rc == 0 then if band(flags, FLAG_DFA) == 0 then if not want_caps then return nil, nil, "capture size too small" end return nil, "capture size too small" end rc = 1 end -- print("cap 0: ", compiled.captures[0]) -- print("cap 1: ", compiled.captures[1]) if ctx then ctx.pos = compiled.captures[1] + 1 end if not want_caps then if not nth or nth < 0 then nth = 0 end if nth > compiled.ncaptures then return nil, nil, "nth out of bound" end if nth >= rc then return nil, nil end local from = compiled.captures[nth * 2] + 1 local to = compiled.captures[nth * 2 + 1] if from < 0 or to < 0 then return nil, nil end return from, to end res = collect_captures(compiled, rc, subj, flags, res) if not compile_once then destroy_compiled_regex(compiled) end return res end function ngx.re.match(subj, regex, opts, ctx, res) return re_match_helper(subj, regex, opts, ctx, true, res) end function ngx.re.find(subj, regex, opts, ctx, nth) return re_match_helper(subj, regex, opts, ctx, false, nil, nth) end do local function destroy_re_gmatch_iterator(iterator) if not iterator._compile_once then destroy_compiled_regex(iterator._compiled) end iterator._compiled = nil iterator._pos = nil iterator._subj = nil end local function iterate_re_gmatch(self) local compiled = self._compiled local subj = self._subj local subj_len = self._subj_len local flags = self._flags local pos = self._pos if not pos then -- The iterator is exhausted. return nil end local rc = ngx_lua_ffi_exec_regex(compiled, flags, subj, subj_len, pos) if rc == PCRE_ERROR_NOMATCH then destroy_re_gmatch_iterator(self) return nil end if rc < 0 then destroy_re_gmatch_iterator(self) return nil, "pcre_exec() failed: " .. rc end if rc == 0 then if band(flags, FLAG_DFA) == 0 then destroy_re_gmatch_iterator(self) return nil, "capture size too small" end rc = 1 end local cp_pos = tonumber(compiled.captures[1]) if cp_pos == compiled.captures[0] then cp_pos = cp_pos + 1 if cp_pos > subj_len then local res = collect_captures(compiled, rc, subj, flags) destroy_re_gmatch_iterator(self) return res end end self._pos = cp_pos return collect_captures(compiled, rc, subj, flags) end local re_gmatch_iterator_mt = { __call = iterate_re_gmatch } function ngx.re.gmatch(subj, regex, opts) subj = tostring(subj) local compiled, compile_once, flags = re_match_compile(regex, opts) if compiled == nil then -- compiled_once holds the error string return nil, compile_once end local re_gmatch_iterator = { _compiled = compiled, _compile_once = compile_once, _subj = subj, _subj_len = #subj, _flags = flags, _pos = 0, } return setmetatable(re_gmatch_iterator, re_gmatch_iterator_mt) end end -- do local function new_script_engine(subj, compiled, count) if not script_engine then script_engine = ngx_lua_ffi_create_script_engine() if script_engine == nil then return nil end ffi_gc(script_engine, ngx_lua_ffi_destroy_script_engine) end ngx_lua_ffi_init_script_engine(script_engine, subj, compiled, count) return script_engine end local function check_buf_size(buf, buf_size, pos, len, new_len, must_alloc) if new_len > buf_size then buf_size = buf_size * buf_grow_ratio if buf_size < new_len then buf_size = new_len end local new_buf = get_string_buf(buf_size, must_alloc) ffi_copy(new_buf, buf, len) buf = new_buf pos = buf + len end return buf, buf_size, pos, new_len end _M.check_buf_size = check_buf_size local function re_sub_compile(regex, opts, replace, func) local flags = 0 local pcre_opts = 0 if opts then flags, pcre_opts = parse_regex_opts(opts) else opts = "" end local compiled local compile_once = (band(flags, FLAG_COMPILE_ONCE) == 1) if compile_once then if func then local subcache = regex_sub_func_cache[opts] if subcache then -- print("cache hit!") compiled = subcache[regex] end else local subcache = regex_sub_str_cache[opts] if subcache then local subsubcache = subcache[regex] if subsubcache then -- print("cache hit!") compiled = subsubcache[replace] end end end end -- compile the regex if compiled == nil then -- print("compiled regex not found, compiling regex...") local errbuf = get_string_buf(MAX_ERR_MSG_LEN) compiled = ngx_lua_ffi_compile_regex(regex, #regex, flags, pcre_opts, errbuf, MAX_ERR_MSG_LEN) if compiled == nil then return nil, ffi_string(errbuf) end ffi_gc(compiled, ngx_lua_ffi_destroy_regex) if func == nil then local rc = ngx_lua_ffi_compile_replace_template(compiled, replace, #replace) if rc ~= 0 then if not compile_once then destroy_compiled_regex(compiled) end return nil, "failed to compile the replacement template" end end -- print("ncaptures: ", compiled.ncaptures) if compile_once then if regex_cache_size < get_max_regex_cache_size() then -- print("inserting compiled regex into cache") if func then local subcache = regex_sub_func_cache[opts] if not subcache then regex_sub_func_cache[opts] = {[regex] = compiled} else subcache[regex] = compiled end else local subcache = regex_sub_str_cache[opts] if not subcache then regex_sub_str_cache[opts] = {[regex] = {[replace] = compiled}} else local subsubcache = subcache[regex] if not subsubcache then subcache[regex] = {[replace] = compiled} else subsubcache[replace] = compiled end end end regex_cache_size = regex_cache_size + 1 else compile_once = false end end end return compiled, compile_once, flags end _M.re_sub_compile = re_sub_compile local function re_sub_func_helper(subj, regex, replace, opts, global) local compiled, compile_once, flags = re_sub_compile(regex, opts, nil, replace) if not compiled then -- error string is in compile_once return nil, nil, compile_once end -- exec the compiled regex subj = tostring(subj) local subj_len = #subj local count = 0 local pos = 0 local cp_pos = 0 local dst_buf_size = get_string_buf_size() -- Note: we have to always allocate the string buffer because -- the user might call whatever resty.core's API functions recursively -- in the user callback function. local dst_buf = get_string_buf(dst_buf_size, true) local dst_pos = dst_buf local dst_len = 0 while true do local rc = ngx_lua_ffi_exec_regex(compiled, flags, subj, subj_len, pos) if rc == PCRE_ERROR_NOMATCH then break end if rc < 0 then if not compile_once then destroy_compiled_regex(compiled) end return nil, nil, "pcre_exec() failed: " .. rc end if rc == 0 then if band(flags, FLAG_DFA) == 0 then if not compile_once then destroy_compiled_regex(compiled) end return nil, nil, "capture size too small" end rc = 1 end count = count + 1 local prefix_len = compiled.captures[0] - cp_pos local res = collect_captures(compiled, rc, subj, flags) local piece = tostring(replace(res)) local piece_len = #piece local new_dst_len = dst_len + prefix_len + piece_len dst_buf, dst_buf_size, dst_pos, dst_len = check_buf_size(dst_buf, dst_buf_size, dst_pos, dst_len, new_dst_len, true) if prefix_len > 0 then ffi_copy(dst_pos, ffi_cast(c_str_type, subj) + cp_pos, prefix_len) dst_pos = dst_pos + prefix_len end if piece_len > 0 then ffi_copy(dst_pos, piece, piece_len) dst_pos = dst_pos + piece_len end cp_pos = compiled.captures[1] pos = cp_pos if pos == compiled.captures[0] then pos = pos + 1 if pos > subj_len then break end end if not global then break end end if not compile_once then destroy_compiled_regex(compiled) end if count > 0 then if cp_pos < subj_len then local suffix_len = subj_len - cp_pos local new_dst_len = dst_len + suffix_len local _ dst_buf, _, dst_pos, dst_len = check_buf_size(dst_buf, dst_buf_size, dst_pos, dst_len, new_dst_len, true) ffi_copy(dst_pos, ffi_cast(c_str_type, subj) + cp_pos, suffix_len) end return ffi_string(dst_buf, dst_len), count end return subj, 0 end local function re_sub_str_helper(subj, regex, replace, opts, global) local compiled, compile_once, flags = re_sub_compile(regex, opts, replace, nil) if not compiled then -- error string is in compile_once return nil, nil, compile_once end -- exec the compiled regex subj = tostring(subj) local subj_len = #subj local count = 0 local pos = 0 local cp_pos = 0 local dst_buf_size = get_string_buf_size() local dst_buf = get_string_buf(dst_buf_size) local dst_pos = dst_buf local dst_len = 0 while true do local rc = ngx_lua_ffi_exec_regex(compiled, flags, subj, subj_len, pos) if rc == PCRE_ERROR_NOMATCH then break end if rc < 0 then if not compile_once then destroy_compiled_regex(compiled) end return nil, nil, "pcre_exec() failed: " .. rc end if rc == 0 then if band(flags, FLAG_DFA) == 0 then if not compile_once then destroy_compiled_regex(compiled) end return nil, nil, "capture size too small" end rc = 1 end count = count + 1 local prefix_len = compiled.captures[0] - cp_pos local cv = compiled.replace if cv.lengths ~= nil then local e = new_script_engine(subj, compiled, rc) if e == nil then return nil, nil, "failed to create script engine" end local bit_len = ngx_lua_ffi_script_eval_len(e, cv) local new_dst_len = dst_len + prefix_len + bit_len dst_buf, dst_buf_size, dst_pos, dst_len = check_buf_size(dst_buf, dst_buf_size, dst_pos, dst_len, new_dst_len) if prefix_len > 0 then ffi_copy(dst_pos, ffi_cast(c_str_type, subj) + cp_pos, prefix_len) dst_pos = dst_pos + prefix_len end if bit_len > 0 then ngx_lua_ffi_script_eval_data(e, cv, dst_pos) dst_pos = dst_pos + bit_len end else local bit_len = cv.value.len dst_buf, dst_buf_size, dst_pos, dst_len = check_buf_size(dst_buf, dst_buf_size, dst_pos, dst_len, dst_len + prefix_len + bit_len) if prefix_len > 0 then ffi_copy(dst_pos, ffi_cast(c_str_type, subj) + cp_pos, prefix_len) dst_pos = dst_pos + prefix_len end if bit_len > 0 then ffi_copy(dst_pos, cv.value.data, bit_len) dst_pos = dst_pos + bit_len end end cp_pos = compiled.captures[1] pos = cp_pos if pos == compiled.captures[0] then pos = pos + 1 if pos > subj_len then break end end if not global then break end end if not compile_once then destroy_compiled_regex(compiled) end if count > 0 then if cp_pos < subj_len then local suffix_len = subj_len - cp_pos local new_dst_len = dst_len + suffix_len local _ dst_buf, _, dst_pos, dst_len = check_buf_size(dst_buf, dst_buf_size, dst_pos, dst_len, new_dst_len) ffi_copy(dst_pos, ffi_cast(c_str_type, subj) + cp_pos, suffix_len) end return ffi_string(dst_buf, dst_len), count end return subj, 0 end local function re_sub_helper(subj, regex, replace, opts, global) local repl_type = type(replace) if repl_type == "function" then return re_sub_func_helper(subj, regex, replace, opts, global) end if repl_type ~= "string" then replace = tostring(replace) end return re_sub_str_helper(subj, regex, replace, opts, global) end function ngx.re.sub(subj, regex, replace, opts) return re_sub_helper(subj, regex, replace, opts, false) end function ngx.re.gsub(subj, regex, replace, opts) return re_sub_helper(subj, regex, replace, opts, true) end return _M lua-resty-core-0.1.31/lib/resty/core/request.lua000066400000000000000000000262161474236722600215320ustar00rootroot00000000000000-- Copyright (C) Yichun Zhang (agentzh) local ffi = require 'ffi' local base = require "resty.core.base" local utils = require "resty.core.utils" local subsystem = ngx.config.subsystem local FFI_BAD_CONTEXT = base.FFI_BAD_CONTEXT local FFI_DECLINED = base.FFI_DECLINED local FFI_OK = base.FFI_OK local clear_tab = base.clear_tab local new_tab = base.new_tab local C = ffi.C local ffi_cast = ffi.cast local ffi_new = ffi.new local ffi_str = ffi.string local get_string_buf = base.get_string_buf local get_size_ptr = base.get_size_ptr local setmetatable = setmetatable local lower = string.lower local find = string.find local rawget = rawget local ngx = ngx local get_request = base.get_request local type = type local error = error local tostring = tostring local tonumber = tonumber local str_replace_char = utils.str_replace_char local _M = { version = base.version } local ngx_lua_ffi_req_start_time if subsystem == "stream" then ffi.cdef[[ double ngx_stream_lua_ffi_req_start_time(ngx_stream_lua_request_t *r); ]] ngx_lua_ffi_req_start_time = C.ngx_stream_lua_ffi_req_start_time elseif subsystem == "http" then ffi.cdef[[ double ngx_http_lua_ffi_req_start_time(ngx_http_request_t *r); ]] ngx_lua_ffi_req_start_time = C.ngx_http_lua_ffi_req_start_time end function ngx.req.start_time() local r = get_request() if not r then error("no request found") end return tonumber(ngx_lua_ffi_req_start_time(r)) end if subsystem == "stream" then return _M end local errmsg = base.get_errmsg_ptr() local ffi_str_type = ffi.typeof("ngx_http_lua_ffi_str_t*") local ffi_str_size = ffi.sizeof("ngx_http_lua_ffi_str_t") ffi.cdef[[ typedef struct { ngx_http_lua_ffi_str_t key; ngx_http_lua_ffi_str_t value; } ngx_http_lua_ffi_table_elt_t; int ngx_http_lua_ffi_req_get_headers_count(ngx_http_request_t *r, int max, int *truncated); int ngx_http_lua_ffi_req_get_headers(ngx_http_request_t *r, ngx_http_lua_ffi_table_elt_t *out, int count, int raw); int ngx_http_lua_ffi_req_get_uri_args_count(ngx_http_request_t *r, int max, int *truncated); size_t ngx_http_lua_ffi_req_get_querystring_len(ngx_http_request_t *r); int ngx_http_lua_ffi_req_get_uri_args(ngx_http_request_t *r, unsigned char *buf, ngx_http_lua_ffi_table_elt_t *out, int count); int ngx_http_lua_ffi_req_get_method(ngx_http_request_t *r); int ngx_http_lua_ffi_req_get_method_name(ngx_http_request_t *r, unsigned char **name, size_t *len); int ngx_http_lua_ffi_req_set_method(ngx_http_request_t *r, int method); int ngx_http_lua_ffi_req_set_header(ngx_http_request_t *r, const unsigned char *key, size_t key_len, const unsigned char *value, size_t value_len, ngx_http_lua_ffi_str_t *mvals, size_t mvals_len, int override, char **errmsg); ]] local table_elt_type = ffi.typeof("ngx_http_lua_ffi_table_elt_t*") local table_elt_size = ffi.sizeof("ngx_http_lua_ffi_table_elt_t") local truncated = ffi.new("int[1]") local req_headers_mt = { __index = function (tb, key) key = lower(key) local value = rawget(tb, key) if value == nil and find(key, '_', 1, true) then value = rawget(tb, (str_replace_char(key, '_', '-'))) end return value end } function ngx.req.get_headers(max_headers, raw) local r = get_request() if not r then error("no request found") end if not max_headers then max_headers = -1 end if not raw then raw = 0 else raw = 1 end local n = C.ngx_http_lua_ffi_req_get_headers_count(r, max_headers, truncated) if n == FFI_BAD_CONTEXT then error("API disabled in the current context", 2) end if n == 0 then local headers = {} if raw == 0 then headers = setmetatable(headers, req_headers_mt) end return headers end local raw_buf = get_string_buf(n * table_elt_size) local buf = ffi_cast(table_elt_type, raw_buf) local rc = C.ngx_http_lua_ffi_req_get_headers(r, buf, n, raw) if rc == 0 then local headers = new_tab(0, n) for i = 0, n - 1 do local h = buf[i] local key = h.key key = ffi_str(key.data, key.len) local value = h.value value = ffi_str(value.data, value.len) local existing = headers[key] if existing then if type(existing) == "table" then existing[#existing + 1] = value else headers[key] = {existing, value} end else headers[key] = value end end if raw == 0 then headers = setmetatable(headers, req_headers_mt) end if truncated[0] ~= 0 then return headers, "truncated" end return headers end return nil end function ngx.req.get_uri_args(max_args, tab) local r = get_request() if not r then error("no request found") end if not max_args then max_args = -1 end if tab then clear_tab(tab) end local n = C.ngx_http_lua_ffi_req_get_uri_args_count(r, max_args, truncated) if n == FFI_BAD_CONTEXT then error("API disabled in the current context", 2) end if n == 0 then return tab or {} end local args_len = C.ngx_http_lua_ffi_req_get_querystring_len(r) local strbuf = get_string_buf(args_len + n * table_elt_size) local kvbuf = ffi_cast(table_elt_type, strbuf + args_len) local nargs = C.ngx_http_lua_ffi_req_get_uri_args(r, strbuf, kvbuf, n) local args = tab or new_tab(0, nargs) for i = 0, nargs - 1 do local arg = kvbuf[i] local key = arg.key key = ffi_str(key.data, key.len) local value = arg.value local len = value.len if len == -1 then value = true else value = ffi_str(value.data, len) end local existing = args[key] if existing then if type(existing) == "table" then existing[#existing + 1] = value else args[key] = {existing, value} end else args[key] = value end end if truncated[0] ~= 0 then return args, "truncated" end return args end do local methods = { [0x0002] = "GET", [0x0004] = "HEAD", [0x0008] = "POST", [0x0010] = "PUT", [0x0020] = "DELETE", [0x0040] = "MKCOL", [0x0080] = "COPY", [0x0100] = "MOVE", [0x0200] = "OPTIONS", [0x0400] = "PROPFIND", [0x0800] = "PROPPATCH", [0x1000] = "LOCK", [0x2000] = "UNLOCK", [0x4000] = "PATCH", [0x8000] = "TRACE", } local namep = ffi_new("unsigned char *[1]") function ngx.req.get_method() local r = get_request() if not r then error("no request found") end do local id = C.ngx_http_lua_ffi_req_get_method(r) if id == FFI_BAD_CONTEXT then error("API disabled in the current context", 2) end local method = methods[id] if method then return method end end local sizep = get_size_ptr() local rc = C.ngx_http_lua_ffi_req_get_method_name(r, namep, sizep) if rc ~= 0 then return nil end return ffi_str(namep[0], sizep[0]) end end -- do function ngx.req.set_method(method) local r = get_request() if not r then error("no request found") end if type(method) ~= "number" then error("bad method number", 2) end local rc = C.ngx_http_lua_ffi_req_set_method(r, method) if rc == FFI_OK then return end if rc == FFI_BAD_CONTEXT then error("API disabled in the current context", 2) end if rc == FFI_DECLINED then error("unsupported HTTP method: " .. method, 2) end error("unknown error: " .. rc) end do local function set_req_header(name, value, override) local r = get_request() if not r then error("no request found", 3) end if name == nil then error("bad 'name' argument: string expected, got nil", 3) end if type(name) ~= "string" then name = tostring(name) end local rc if value == nil then if not override then error("bad 'value' argument: string or table expected, got nil", 3) end rc = C.ngx_http_lua_ffi_req_set_header(r, name, #name, nil, 0, nil, 0, 1, errmsg) else local sval, sval_len, mvals, mvals_len, buf local value_type = type(value) if value_type == "table" then mvals_len = #value if mvals_len == 0 and not override then error("bad 'value' argument: non-empty table expected", 3) end buf = get_string_buf(ffi_str_size * mvals_len) mvals = ffi_cast(ffi_str_type, buf) for i = 1, mvals_len do local s = value[i] if type(s) ~= "string" then s = tostring(s) value[i] = s end local str = mvals[i - 1] str.data = s str.len = #s end sval_len = 0 else if value_type ~= "string" then sval = tostring(value) else sval = value end sval_len = #sval mvals_len = 0 end rc = C.ngx_http_lua_ffi_req_set_header(r, name, #name, sval, sval_len, mvals, mvals_len, override and 1 or 0, errmsg) end if rc == FFI_OK or rc == FFI_DECLINED then return end if rc == FFI_BAD_CONTEXT then error("API disabled in the current context", 3) end -- rc == FFI_ERROR error(ffi_str(errmsg[0])) end _M.set_req_header = set_req_header function ngx.req.set_header(name, value) set_req_header(name, value, true) -- override end end -- do function ngx.req.clear_header(name) local r = get_request() if not r then error("no request found") end if type(name) ~= "string" then name = tostring(name) end local rc = C.ngx_http_lua_ffi_req_set_header(r, name, #name, nil, 0, nil, 0, 1, errmsg) if rc == FFI_OK or rc == FFI_DECLINED then return end if rc == FFI_BAD_CONTEXT then error("API disabled in the current context", 2) end -- rc == FFI_ERROR error(ffi_str(errmsg[0])) end return _M lua-resty-core-0.1.31/lib/resty/core/response.lua000066400000000000000000000143311474236722600216730ustar00rootroot00000000000000-- Copyright (C) Yichun Zhang (agentzh) local ffi = require 'ffi' local base = require "resty.core.base" local C = ffi.C local ffi_cast = ffi.cast local ffi_str = ffi.string local new_tab = base.new_tab local FFI_BAD_CONTEXT = base.FFI_BAD_CONTEXT local FFI_NO_REQ_CTX = base.FFI_NO_REQ_CTX local FFI_DECLINED = base.FFI_DECLINED local get_string_buf = base.get_string_buf local setmetatable = setmetatable local type = type local tostring = tostring local get_request = base.get_request local error = error local ngx = ngx local _M = { version = base.version } local MAX_HEADER_VALUES = 100 local errmsg = base.get_errmsg_ptr() local ffi_str_type = ffi.typeof("ngx_http_lua_ffi_str_t*") local ffi_str_size = ffi.sizeof("ngx_http_lua_ffi_str_t") ffi.cdef[[ int ngx_http_lua_ffi_set_resp_header(ngx_http_request_t *r, const char *key_data, size_t key_len, int is_nil, const char *sval, size_t sval_len, ngx_http_lua_ffi_str_t *mvals, size_t mvals_len, int override, char **errmsg); int ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r, const unsigned char *key, size_t key_len, unsigned char *key_buf, ngx_http_lua_ffi_str_t *values, int max_nvalues, char **errmsg); ]] local ngx_lua_ffi_set_resp_header local MACOS = jit and jit.os == "OSX" if MACOS then ffi.cdef[[ typedef struct { ngx_http_request_t *r; const char *key_data; size_t key_len; int is_nil; const char *sval; size_t sval_len; void *mvals; size_t mvals_len; int override; char **errmsg; } ngx_http_lua_set_resp_header_params_t; int ngx_http_lua_ffi_set_resp_header_macos( ngx_http_lua_set_resp_header_params_t *p); ]] local set_params = ffi.new("ngx_http_lua_set_resp_header_params_t") ngx_lua_ffi_set_resp_header = function(r, key, key_len, is_nil, sval, sval_len, mvals, mvals_len, override, err) set_params.r = r set_params.key_data = key set_params.key_len = key_len set_params.is_nil = is_nil set_params.sval = sval set_params.sval_len = sval_len set_params.mvals = mvals set_params.mvals_len = mvals_len set_params.override = override set_params.errmsg = err return C.ngx_http_lua_ffi_set_resp_header_macos(set_params) end else ngx_lua_ffi_set_resp_header = function(r, key, key_len, is_nil, sval, sval_len, mvals, mvals_len, override, err) return C.ngx_http_lua_ffi_set_resp_header(r, key, key_len, is_nil, sval, sval_len, mvals, mvals_len, override, err) end end local function set_resp_header(tb, key, value, no_override) local r = get_request() if not r then error("no request found") end if type(key) ~= "string" then key = tostring(key) end local rc if value == nil then if no_override then error("invalid header value", 3) end rc = ngx_lua_ffi_set_resp_header(r, key, #key, true, nil, 0, nil, 0, 1, errmsg) else local sval, sval_len, mvals, mvals_len, buf if type(value) == "table" then mvals_len = #value if mvals_len == 0 and no_override then return end buf = get_string_buf(ffi_str_size * mvals_len) mvals = ffi_cast(ffi_str_type, buf) for i = 1, mvals_len do local s = value[i] if type(s) ~= "string" then s = tostring(s) value[i] = s end local str = mvals[i - 1] str.data = s str.len = #s end sval_len = 0 else if type(value) ~= "string" then sval = tostring(value) else sval = value end sval_len = #sval mvals_len = 0 end local override_int = no_override and 0 or 1 rc = ngx_lua_ffi_set_resp_header(r, key, #key, false, sval, sval_len, mvals, mvals_len, override_int, errmsg) end if rc == 0 or rc == FFI_DECLINED then return end if rc == FFI_NO_REQ_CTX then error("no request ctx found") end if rc == FFI_BAD_CONTEXT then error("API disabled in the current context", 2) end -- rc == FFI_ERROR error(ffi_str(errmsg[0]), 2) end _M.set_resp_header = set_resp_header local function get_resp_header(tb, key) local r = get_request() if not r then error("no request found") end if type(key) ~= "string" then key = tostring(key) end local key_len = #key local key_buf = get_string_buf(key_len + ffi_str_size * MAX_HEADER_VALUES) local values = ffi_cast(ffi_str_type, key_buf + key_len) local n = C.ngx_http_lua_ffi_get_resp_header(r, key, key_len, key_buf, values, MAX_HEADER_VALUES, errmsg) -- print("retval: ", n) if n == FFI_BAD_CONTEXT then error("API disabled in the current context", 2) end if n == 0 then return nil end if n == 1 then local v = values[0] return ffi_str(v.data, v.len) end if n > 0 then local ret = new_tab(n, 0) for i = 1, n do local v = values[i - 1] ret[i] = ffi_str(v.data, v.len) end return ret end -- n == FFI_ERROR error(ffi_str(errmsg[0]), 2) end do local mt = new_tab(0, 2) mt.__newindex = set_resp_header mt.__index = get_resp_header ngx.header = setmetatable(new_tab(0, 0), mt) end return _M lua-resty-core-0.1.31/lib/resty/core/shdict.lua000066400000000000000000000651001474236722600213130ustar00rootroot00000000000000-- Copyright (C) Yichun Zhang (agentzh) local ffi = require 'ffi' local base = require "resty.core.base" local _M = { version = base.version } local ngx_shared = ngx.shared if not ngx_shared then return _M end local ffi_new = ffi.new local ffi_str = ffi.string local C = ffi.C local get_string_buf = base.get_string_buf local get_string_buf_size = base.get_string_buf_size local get_size_ptr = base.get_size_ptr local tonumber = tonumber local tostring = tostring local next = next local type = type local error = error local getmetatable = getmetatable local FFI_DECLINED = base.FFI_DECLINED local subsystem = ngx.config.subsystem local ngx_lua_ffi_shdict_get local ngx_lua_ffi_shdict_incr local ngx_lua_ffi_shdict_store local ngx_lua_ffi_shdict_flush_all local ngx_lua_ffi_shdict_get_ttl local ngx_lua_ffi_shdict_set_expire local ngx_lua_ffi_shdict_capacity local ngx_lua_ffi_shdict_free_space local ngx_lua_ffi_shdict_udata_to_zone if subsystem == 'http' then ffi.cdef[[ int ngx_http_lua_ffi_shdict_get(void *zone, const unsigned char *key, size_t key_len, int *value_type, unsigned char **str_value_buf, size_t *str_value_len, double *num_value, int *user_flags, int get_stale, int *is_stale, char **errmsg); int ngx_http_lua_ffi_shdict_incr(void *zone, const unsigned char *key, size_t key_len, double *value, char **err, int has_init, double init, long init_ttl, int *forcible); int ngx_http_lua_ffi_shdict_store(void *zone, int op, const unsigned char *key, size_t key_len, int value_type, const unsigned char *str_value_buf, size_t str_value_len, double num_value, long exptime, int user_flags, char **errmsg, int *forcible); int ngx_http_lua_ffi_shdict_flush_all(void *zone); long ngx_http_lua_ffi_shdict_get_ttl(void *zone, const unsigned char *key, size_t key_len); int ngx_http_lua_ffi_shdict_set_expire(void *zone, const unsigned char *key, size_t key_len, long exptime); size_t ngx_http_lua_ffi_shdict_capacity(void *zone); void *ngx_http_lua_ffi_shdict_udata_to_zone(void *zone_udata); ]] ngx_lua_ffi_shdict_get = function(zone, key, key_len, value_type, str_value_buf, value_len, num_value, user_flags, get_stale, is_stale, errmsg) return C.ngx_http_lua_ffi_shdict_get(zone, key, key_len, value_type, str_value_buf, value_len, num_value, user_flags, get_stale, is_stale, errmsg) end ngx_lua_ffi_shdict_incr = function(zone, key, key_len, value, err, has_init, init, init_ttl, forcible) return C.ngx_http_lua_ffi_shdict_incr(zone, key, key_len, value, err, has_init, init, init_ttl, forcible) end ngx_lua_ffi_shdict_store = function(zone, op, key, key_len, value_type, str_value_buf, str_value_len, num_value, exptime, user_flags, errmsg, forcible) return C.ngx_http_lua_ffi_shdict_store(zone, op, key, key_len, value_type, str_value_buf, str_value_len, num_value, exptime, user_flags, errmsg, forcible) end ngx_lua_ffi_shdict_flush_all = C.ngx_http_lua_ffi_shdict_flush_all ngx_lua_ffi_shdict_get_ttl = C.ngx_http_lua_ffi_shdict_get_ttl ngx_lua_ffi_shdict_set_expire = C.ngx_http_lua_ffi_shdict_set_expire ngx_lua_ffi_shdict_capacity = C.ngx_http_lua_ffi_shdict_capacity ngx_lua_ffi_shdict_udata_to_zone = C.ngx_http_lua_ffi_shdict_udata_to_zone if not pcall(function () return C.ngx_http_lua_ffi_shdict_free_space end) then ffi.cdef[[ size_t ngx_http_lua_ffi_shdict_free_space(void *zone); ]] end pcall(function () ngx_lua_ffi_shdict_free_space = C.ngx_http_lua_ffi_shdict_free_space end) elseif subsystem == 'stream' then ffi.cdef[[ int ngx_stream_lua_ffi_shdict_get(void *zone, const unsigned char *key, size_t key_len, int *value_type, unsigned char **str_value_buf, size_t *str_value_len, double *num_value, int *user_flags, int get_stale, int *is_stale, char **errmsg); int ngx_stream_lua_ffi_shdict_incr(void *zone, const unsigned char *key, size_t key_len, double *value, char **err, int has_init, double init, long init_ttl, int *forcible); int ngx_stream_lua_ffi_shdict_store(void *zone, int op, const unsigned char *key, size_t key_len, int value_type, const unsigned char *str_value_buf, size_t str_value_len, double num_value, long exptime, int user_flags, char **errmsg, int *forcible); int ngx_stream_lua_ffi_shdict_flush_all(void *zone); long ngx_stream_lua_ffi_shdict_get_ttl(void *zone, const unsigned char *key, size_t key_len); int ngx_stream_lua_ffi_shdict_set_expire(void *zone, const unsigned char *key, size_t key_len, long exptime); size_t ngx_stream_lua_ffi_shdict_capacity(void *zone); void *ngx_stream_lua_ffi_shdict_udata_to_zone(void *zone_udata); ]] ngx_lua_ffi_shdict_get = function(zone, key, key_len, value_type, str_value_buf, value_len, num_value, user_flags, get_stale, is_stale, errmsg) return C.ngx_stream_lua_ffi_shdict_get(zone, key, key_len, value_type, str_value_buf, value_len, num_value, user_flags, get_stale, is_stale, errmsg) end ngx_lua_ffi_shdict_incr = function(zone, key, key_len, value, err, has_init, init, init_ttl, forcible) return C.ngx_stream_lua_ffi_shdict_incr(zone, key, key_len, value, err, has_init, init, init_ttl, forcible) end ngx_lua_ffi_shdict_store = function(zone, op, key, key_len, value_type, str_value_buf, str_value_len, num_value, exptime, user_flags, errmsg, forcible) return C.ngx_stream_lua_ffi_shdict_store(zone, op, key, key_len, value_type, str_value_buf, str_value_len, num_value, exptime, user_flags, errmsg, forcible) end ngx_lua_ffi_shdict_flush_all = C.ngx_stream_lua_ffi_shdict_flush_all ngx_lua_ffi_shdict_get_ttl = C.ngx_stream_lua_ffi_shdict_get_ttl ngx_lua_ffi_shdict_set_expire = C.ngx_stream_lua_ffi_shdict_set_expire ngx_lua_ffi_shdict_capacity = C.ngx_stream_lua_ffi_shdict_capacity ngx_lua_ffi_shdict_udata_to_zone = C.ngx_stream_lua_ffi_shdict_udata_to_zone if not pcall(function () return C.ngx_stream_lua_ffi_shdict_free_space end) then ffi.cdef[[ size_t ngx_stream_lua_ffi_shdict_free_space(void *zone); ]] end -- ngx_stream_lua is only compatible with NGINX >= 1.13.6, meaning it -- cannot lack support for ngx_stream_lua_ffi_shdict_free_space. ngx_lua_ffi_shdict_free_space = C.ngx_stream_lua_ffi_shdict_free_space else error("unknown subsystem: " .. subsystem) end local MACOS = jit and jit.os == "OSX" if MACOS and subsystem == 'http' then ffi.cdef[[ typedef struct { void *zone; const unsigned char *key; size_t key_len; int *value_type; unsigned char **str_value_buf; size_t *str_value_len; double *num_value; int *user_flags; int get_stale; int *is_stale; char **errmsg; } ngx_http_lua_shdict_get_params_t; typedef struct { void *zone; int op; const unsigned char *key; size_t key_len; int value_type; const unsigned char *str_value_buf; size_t str_value_len; double num_value; long exptime; int user_flags; char **errmsg; int *forcible; } ngx_http_lua_shdict_store_params_t; typedef struct { void *zone; const unsigned char *key; size_t key_len; double *num_value; char **errmsg; int has_init; double init; long init_ttl; int *forcible; } ngx_http_lua_shdict_incr_params_t; int ngx_http_lua_ffi_shdict_get_macos( ngx_http_lua_shdict_get_params_t *p); int ngx_http_lua_ffi_shdict_store_macos( ngx_http_lua_shdict_store_params_t *p); int ngx_http_lua_ffi_shdict_incr_macos( ngx_http_lua_shdict_incr_params_t *p); ]] local get_params = ffi_new("ngx_http_lua_shdict_get_params_t") local incr_params = ffi_new("ngx_http_lua_shdict_incr_params_t") local store_params = ffi_new("ngx_http_lua_shdict_store_params_t") ngx_lua_ffi_shdict_get = function(zone, key, key_len, value_type, str_value_buf, value_len, num_value, user_flags, get_stale, is_stale, errmsg) get_params.zone = zone get_params.key = key get_params.key_len = key_len get_params.value_type = value_type get_params.str_value_buf = str_value_buf get_params.str_value_len = value_len get_params.num_value = num_value get_params.user_flags = user_flags get_params.get_stale = get_stale get_params.is_stale = is_stale get_params.errmsg = errmsg return C.ngx_http_lua_ffi_shdict_get_macos(get_params) end ngx_lua_ffi_shdict_incr = function(zone, key, key_len, value, err, has_init, init, init_ttl, forcible) incr_params.zone = zone incr_params.key = key incr_params.key_len = key_len incr_params.num_value = value incr_params.errmsg = err incr_params.has_init = has_init incr_params.init = init incr_params.init_ttl = init_ttl incr_params.forcible = forcible return C.ngx_http_lua_ffi_shdict_incr_macos(incr_params) end ngx_lua_ffi_shdict_store = function(zone, op, key, key_len, value_type, str_value_buf, str_value_len, num_value, exptime, user_flags, errmsg, forcible) store_params.zone = zone store_params.op = op store_params.key = key store_params.key_len = key_len store_params.value_type = value_type store_params.str_value_buf = str_value_buf store_params.str_value_len = str_value_len store_params.num_value = num_value store_params.exptime = exptime store_params.user_flags = user_flags store_params.errmsg = errmsg store_params.forcible = forcible return C.ngx_http_lua_ffi_shdict_store_macos(store_params) end end if MACOS and subsystem == 'stream' then ffi.cdef[[ typedef struct { void *zone; const unsigned char *key; size_t key_len; int *value_type; unsigned char **str_value_buf; size_t *str_value_len; double *num_value; int *user_flags; int get_stale; int *is_stale; char **errmsg; } ngx_stream_lua_shdict_get_params_t; typedef struct { void *zone; int op; const unsigned char *key; size_t key_len; int value_type; const unsigned char *str_value_buf; size_t str_value_len; double num_value; long exptime; int user_flags; char **errmsg; int *forcible; } ngx_stream_lua_shdict_store_params_t; typedef struct { void *zone; const unsigned char *key; size_t key_len; double *num_value; char **errmsg; int has_init; double init; long init_ttl; int *forcible; } ngx_stream_lua_shdict_incr_params_t; int ngx_stream_lua_ffi_shdict_get_macos( ngx_stream_lua_shdict_get_params_t *p); int ngx_stream_lua_ffi_shdict_store_macos( ngx_stream_lua_shdict_store_params_t *p); int ngx_stream_lua_ffi_shdict_incr_macos( ngx_stream_lua_shdict_incr_params_t *p); ]] local get_params = ffi_new("ngx_stream_lua_shdict_get_params_t") local store_params = ffi_new("ngx_stream_lua_shdict_store_params_t") local incr_params = ffi_new("ngx_stream_lua_shdict_incr_params_t") ngx_lua_ffi_shdict_get = function(zone, key, key_len, value_type, str_value_buf, value_len, num_value, user_flags, get_stale, is_stale, errmsg) get_params.zone = zone get_params.key = key get_params.key_len = key_len get_params.value_type = value_type get_params.str_value_buf = str_value_buf get_params.str_value_len = value_len get_params.num_value = num_value get_params.user_flags = user_flags get_params.get_stale = get_stale get_params.is_stale = is_stale get_params.errmsg = errmsg return C.ngx_stream_lua_ffi_shdict_get_macos(get_params) end ngx_lua_ffi_shdict_incr = function(zone, key, key_len, value, err, has_init, init, init_ttl, forcible) incr_params.zone = zone incr_params.key = key incr_params.key_len = key_len incr_params.num_value = value incr_params.errmsg = err incr_params.has_init = has_init incr_params.init = init incr_params.init_ttl = init_ttl incr_params.forcible = forcible return C.ngx_stream_lua_ffi_shdict_incr_macos(incr_params) end ngx_lua_ffi_shdict_store = function(zone, op, key, key_len, value_type, str_value_buf, str_value_len, num_value, exptime, user_flags, errmsg, forcible) store_params.zone = zone store_params.op = op store_params.key = key store_params.key_len = key_len store_params.value_type = value_type store_params.str_value_buf = str_value_buf store_params.str_value_len = str_value_len store_params.num_value = num_value store_params.exptime = exptime store_params.user_flags = user_flags store_params.errmsg = errmsg store_params.forcible = forcible return C.ngx_stream_lua_ffi_shdict_store_macos(store_params) end end if not pcall(function () return C.free end) then ffi.cdef[[ void free(void *ptr); ]] end local value_type = ffi_new("int[1]") local user_flags = ffi_new("int[1]") local num_value = ffi_new("double[1]") local is_stale = ffi_new("int[1]") local forcible = ffi_new("int[1]") local str_value_buf = ffi_new("unsigned char *[1]") local errmsg = base.get_errmsg_ptr() local function check_zone(zone) if not zone or type(zone) ~= "table" then error("bad \"zone\" argument", 3) end zone = zone[1] if type(zone) ~= "userdata" then error("bad \"zone\" argument", 3) end zone = ngx_lua_ffi_shdict_udata_to_zone(zone) if zone == nil then error("bad \"zone\" argument", 3) end return zone end local function shdict_store(zone, op, key, value, exptime, flags) zone = check_zone(zone) if not exptime then exptime = 0 elseif exptime < 0 then error('bad "exptime" argument', 2) end if not flags then flags = 0 end if key == nil then return nil, "nil key" end if type(key) ~= "string" then key = tostring(key) end local key_len = #key if key_len == 0 then return nil, "empty key" end if key_len > 65535 then return nil, "key too long" end local str_val_buf local str_val_len = 0 local num_val = 0 local valtyp = type(value) -- print("value type: ", valtyp) -- print("exptime: ", exptime) if valtyp == "string" then valtyp = 4 -- LUA_TSTRING str_val_buf = value str_val_len = #value elseif valtyp == "number" then valtyp = 3 -- LUA_TNUMBER num_val = value elseif value == nil then valtyp = 0 -- LUA_TNIL elseif valtyp == "boolean" then valtyp = 1 -- LUA_TBOOLEAN num_val = value and 1 or 0 else return nil, "bad value type" end local rc = ngx_lua_ffi_shdict_store(zone, op, key, key_len, valtyp, str_val_buf, str_val_len, num_val, exptime * 1000, flags, errmsg, forcible) -- print("rc == ", rc) if rc == 0 then -- NGX_OK return true, nil, forcible[0] == 1 end -- NGX_DECLINED or NGX_ERROR return false, ffi_str(errmsg[0]), forcible[0] == 1 end local function shdict_set(zone, key, value, exptime, flags) return shdict_store(zone, 0, key, value, exptime, flags) end local function shdict_safe_set(zone, key, value, exptime, flags) return shdict_store(zone, 0x0004, key, value, exptime, flags) end local function shdict_add(zone, key, value, exptime, flags) return shdict_store(zone, 0x0001, key, value, exptime, flags) end local function shdict_safe_add(zone, key, value, exptime, flags) return shdict_store(zone, 0x0005, key, value, exptime, flags) end local function shdict_replace(zone, key, value, exptime, flags) return shdict_store(zone, 0x0002, key, value, exptime, flags) end local function shdict_delete(zone, key) return shdict_set(zone, key, nil) end local function shdict_get(zone, key) zone = check_zone(zone) if key == nil then return nil, "nil key" end if type(key) ~= "string" then key = tostring(key) end local key_len = #key if key_len == 0 then return nil, "empty key" end if key_len > 65535 then return nil, "key too long" end local size = get_string_buf_size() local buf = get_string_buf(size) str_value_buf[0] = buf local value_len = get_size_ptr() value_len[0] = size local rc = ngx_lua_ffi_shdict_get(zone, key, key_len, value_type, str_value_buf, value_len, num_value, user_flags, 0, is_stale, errmsg) if rc ~= 0 then if errmsg[0] ~= nil then return nil, ffi_str(errmsg[0]) end error("failed to get the key") end local typ = value_type[0] if typ == 0 then -- LUA_TNIL return nil end local flags = tonumber(user_flags[0]) local val if typ == 4 then -- LUA_TSTRING if str_value_buf[0] ~= buf then -- ngx.say("len: ", tonumber(value_len[0])) buf = str_value_buf[0] val = ffi_str(buf, value_len[0]) C.free(buf) else val = ffi_str(buf, value_len[0]) end elseif typ == 3 then -- LUA_TNUMBER val = tonumber(num_value[0]) elseif typ == 1 then -- LUA_TBOOLEAN val = (tonumber(buf[0]) ~= 0) else error("unknown value type: " .. typ) end if flags ~= 0 then return val, flags end return val end local function shdict_get_stale(zone, key) zone = check_zone(zone) if key == nil then return nil, "nil key" end if type(key) ~= "string" then key = tostring(key) end local key_len = #key if key_len == 0 then return nil, "empty key" end if key_len > 65535 then return nil, "key too long" end local size = get_string_buf_size() local buf = get_string_buf(size) str_value_buf[0] = buf local value_len = get_size_ptr() value_len[0] = size local rc = ngx_lua_ffi_shdict_get(zone, key, key_len, value_type, str_value_buf, value_len, num_value, user_flags, 1, is_stale, errmsg) if rc ~= 0 then if errmsg[0] ~= nil then return nil, ffi_str(errmsg[0]) end error("failed to get the key") end local typ = value_type[0] if typ == 0 then -- LUA_TNIL return nil end local flags = tonumber(user_flags[0]) local val if typ == 4 then -- LUA_TSTRING if str_value_buf[0] ~= buf then -- ngx.say("len: ", tonumber(value_len[0])) buf = str_value_buf[0] val = ffi_str(buf, value_len[0]) C.free(buf) else val = ffi_str(buf, value_len[0]) end elseif typ == 3 then -- LUA_TNUMBER val = tonumber(num_value[0]) elseif typ == 1 then -- LUA_TBOOLEAN val = (tonumber(buf[0]) ~= 0) else error("unknown value type: " .. typ) end if flags ~= 0 then return val, flags, is_stale[0] == 1 end return val, nil, is_stale[0] == 1 end local function shdict_incr(zone, key, value, init, init_ttl) zone = check_zone(zone) if key == nil then return nil, "nil key" end if type(key) ~= "string" then key = tostring(key) end local key_len = #key if key_len == 0 then return nil, "empty key" end if key_len > 65535 then return nil, "key too long" end if type(value) ~= "number" then value = tonumber(value) end num_value[0] = value if init then local typ = type(init) if typ ~= "number" then init = tonumber(init) if not init then error("bad init arg: number expected, got " .. typ, 2) end end end if init_ttl ~= nil then local typ = type(init_ttl) if typ ~= "number" then init_ttl = tonumber(init_ttl) if not init_ttl then error("bad init_ttl arg: number expected, got " .. typ, 2) end end if init_ttl < 0 then error('bad "init_ttl" argument', 2) end if not init then error('must provide "init" when providing "init_ttl"', 2) end else init_ttl = 0 end local rc = ngx_lua_ffi_shdict_incr(zone, key, key_len, num_value, errmsg, init and 1 or 0, init or 0, init_ttl * 1000, forcible) if rc ~= 0 then -- ~= NGX_OK return nil, ffi_str(errmsg[0]) end if not init then return tonumber(num_value[0]) end return tonumber(num_value[0]), nil, forcible[0] == 1 end local function shdict_flush_all(zone) zone = check_zone(zone) ngx_lua_ffi_shdict_flush_all(zone) end local function shdict_ttl(zone, key) zone = check_zone(zone) if key == nil then return nil, "nil key" end if type(key) ~= "string" then key = tostring(key) end local key_len = #key if key_len == 0 then return nil, "empty key" end if key_len > 65535 then return nil, "key too long" end local rc = ngx_lua_ffi_shdict_get_ttl(zone, key, key_len) if rc == FFI_DECLINED then return nil, "not found" end return tonumber(rc) / 1000 end local function shdict_expire(zone, key, exptime) zone = check_zone(zone) if not exptime then error('bad "exptime" argument', 2) end if key == nil then return nil, "nil key" end if type(key) ~= "string" then key = tostring(key) end local key_len = #key if key_len == 0 then return nil, "empty key" end if key_len > 65535 then return nil, "key too long" end local rc = ngx_lua_ffi_shdict_set_expire(zone, key, key_len, exptime * 1000) if rc == FFI_DECLINED then return nil, "not found" end -- NGINX_OK/FFI_OK return true end local function shdict_capacity(zone) zone = check_zone(zone) return tonumber(ngx_lua_ffi_shdict_capacity(zone)) end local shdict_free_space if ngx_lua_ffi_shdict_free_space then shdict_free_space = function (zone) zone = check_zone(zone) return tonumber(ngx_lua_ffi_shdict_free_space(zone)) end else shdict_free_space = function () error("'shm:free_space()' not supported in NGINX < 1.11.7", 2) end end local _, dict = next(ngx_shared, nil) if dict then local mt = getmetatable(dict) if mt then mt = mt.__index if mt then mt.get = shdict_get mt.get_stale = shdict_get_stale mt.incr = shdict_incr mt.set = shdict_set mt.safe_set = shdict_safe_set mt.add = shdict_add mt.safe_add = shdict_safe_add mt.replace = shdict_replace mt.delete = shdict_delete mt.flush_all = shdict_flush_all mt.ttl = shdict_ttl mt.expire = shdict_expire mt.capacity = shdict_capacity mt.free_space = shdict_free_space end end end return _M lua-resty-core-0.1.31/lib/resty/core/socket.lua000066400000000000000000000163421474236722600213310ustar00rootroot00000000000000local base = require "resty.core.base" base.allows_subsystem("http") local debug = require "debug" local ffi = require "ffi" local error = error local assert = assert local tonumber = tonumber local tostring = tostring local type = type local select = select local registry = debug.getregistry() local C = ffi.C local ffi_new = ffi.new local ffi_str = ffi.string local ffi_gc = ffi.gc local get_string_buf = base.get_string_buf local get_size_ptr = base.get_size_ptr local get_request = base.get_request local co_yield = coroutine._yield local option_index = { ["keepalive"] = 1, ["reuseaddr"] = 2, ["tcp-nodelay"] = 3, ["sndbuf"] = 4, ["rcvbuf"] = 5, } ffi.cdef[[ typedef struct ngx_http_lua_socket_tcp_upstream_s ngx_http_lua_socket_tcp_upstream_t; int ngx_http_lua_ffi_socket_tcp_getoption(ngx_http_lua_socket_tcp_upstream_t *u, int opt, int *val, unsigned char *err, size_t *errlen); int ngx_http_lua_ffi_socket_tcp_setoption(ngx_http_lua_socket_tcp_upstream_t *u, int opt, int val, unsigned char *err, size_t *errlen); int ngx_http_lua_ffi_socket_tcp_sslhandshake(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, void *sess, int enable_session_reuse, ngx_str_t *server_name, int verify, int ocsp_status_req, void *chain, void *pkey, char **errmsg); int ngx_http_lua_ffi_socket_tcp_get_sslhandshake_result(ngx_http_request_t *r, ngx_http_lua_socket_tcp_upstream_t *u, void **sess, char **errmsg, int *openssl_error_code); void ngx_http_lua_ffi_ssl_free_session(void *sess); ]] local output_value_buf = ffi_new("int[1]") local ERR_BUF_SIZE = 4096 local FFI_OK = base.FFI_OK local FFI_ERROR = base.FFI_ERROR local FFI_DONE = base.FFI_DONE local FFI_AGAIN = base.FFI_AGAIN local FFI_NO_REQ_CTX = base.FFI_NO_REQ_CTX local SOCKET_CTX_INDEX = 1 local SOCKET_CLIENT_CERT_INDEX = 6 local SOCKET_CLIENT_PKEY_INDEX = 7 local function get_tcp_socket(cosocket) local tcp_socket = cosocket[SOCKET_CTX_INDEX] if not tcp_socket then error("socket is never created nor connected") end return tcp_socket end local function getoption(cosocket, option) local tcp_socket = get_tcp_socket(cosocket) if option == nil then return nil, 'missing the "option" argument' end if option_index[option] == nil then return nil, "unsupported option " .. tostring(option) end local err = get_string_buf(ERR_BUF_SIZE) local errlen = get_size_ptr() errlen[0] = ERR_BUF_SIZE local rc = C.ngx_http_lua_ffi_socket_tcp_getoption(tcp_socket, option_index[option], output_value_buf, err, errlen) if rc ~= FFI_OK then return nil, ffi_str(err, errlen[0]) end return tonumber(output_value_buf[0]) end local function setoption(cosocket, option, value) local tcp_socket = get_tcp_socket(cosocket) if option == nil then return nil, 'missing the "option" argument' end if value == nil then return nil, 'missing the "value" argument' end if option_index[option] == nil then return nil, "unsupported option " .. tostring(option) end local err = get_string_buf(ERR_BUF_SIZE) local errlen = get_size_ptr() errlen[0] = ERR_BUF_SIZE local rc = C.ngx_http_lua_ffi_socket_tcp_setoption(tcp_socket, option_index[option], value, err, errlen) if rc ~= FFI_OK then return nil, ffi_str(err, errlen[0]) end return true end local errmsg = base.get_errmsg_ptr() local session_ptr = ffi_new("void *[1]") local server_name_str = ffi_new("ngx_str_t[1]") local openssl_error_code = ffi_new("int[1]") local function setclientcert(cosocket, cert, pkey) if not cert and not pkey then cosocket[SOCKET_CLIENT_CERT_INDEX] = nil cosocket[SOCKET_CLIENT_PKEY_INDEX] = nil return true end if not cert or not pkey then return nil, "client certificate must be supplied with corresponding " .. "private key" end if type(cert) ~= "cdata" then return nil, "bad cert arg: cdata expected, got " .. type(cert) end if type(pkey) ~= "cdata" then return nil, "bad pkey arg: cdata expected, got " .. type(pkey) end cosocket[SOCKET_CLIENT_CERT_INDEX] = cert cosocket[SOCKET_CLIENT_PKEY_INDEX] = pkey return true end local function sslhandshake(cosocket, reused_session, server_name, ssl_verify, send_status_req, ...) local n = select("#", ...) if not cosocket or n > 0 then error("ngx.socket sslhandshake: expecting 1 ~ 5 arguments " .. "(including the object), but seen " .. (cosocket and 5 + n or 0)) end local r = get_request() if not r then error("no request found", 2) end session_ptr[0] = type(reused_session) == "cdata" and reused_session or nil if server_name then server_name_str[0].data = server_name server_name_str[0].len = #server_name else server_name_str[0].data = nil server_name_str[0].len = 0 end local u = get_tcp_socket(cosocket) local rc = C.ngx_http_lua_ffi_socket_tcp_sslhandshake(r, u, session_ptr[0], reused_session ~= false, server_name_str, ssl_verify and 1 or 0, send_status_req and 1 or 0, cosocket[SOCKET_CLIENT_CERT_INDEX], cosocket[SOCKET_CLIENT_PKEY_INDEX], errmsg) if rc == FFI_NO_REQ_CTX then error("no request ctx found", 2) end while true do if rc == FFI_ERROR then if openssl_error_code[0] ~= 0 then return nil, openssl_error_code[0] .. ": " .. ffi_str(errmsg[0]) end return nil, ffi_str(errmsg[0]) end if rc == FFI_DONE then return reused_session end if rc == FFI_OK then if reused_session == false then return true end rc = C.ngx_http_lua_ffi_socket_tcp_get_sslhandshake_result(r, u, session_ptr, errmsg, openssl_error_code) assert(rc == FFI_OK) if session_ptr[0] == nil then return session_ptr[0] end return ffi_gc(session_ptr[0], C.ngx_http_lua_ffi_ssl_free_session) end assert(rc == FFI_AGAIN) co_yield() rc = C.ngx_http_lua_ffi_socket_tcp_get_sslhandshake_result(r, u, session_ptr, errmsg, openssl_error_code) end end do local method_table = registry.__tcp_cosocket_mt method_table.getoption = getoption method_table.setoption = setoption method_table.setclientcert = setclientcert method_table.sslhandshake = sslhandshake end return { version = base.version } lua-resty-core-0.1.31/lib/resty/core/time.lua000066400000000000000000000112161474236722600207720ustar00rootroot00000000000000-- Copyright (C) Yichun Zhang (agentzh) local ffi = require 'ffi' local base = require "resty.core.base" local error = error local tonumber = tonumber local type = type local C = ffi.C local ffi_new = ffi.new local ffi_str = ffi.string local time_val = ffi_new("long[1]") local get_string_buf = base.get_string_buf local ngx = ngx local FFI_ERROR = base.FFI_ERROR local subsystem = ngx.config.subsystem local ngx_lua_ffi_now local ngx_lua_ffi_time local ngx_lua_ffi_monotonic_msec local ngx_lua_ffi_today local ngx_lua_ffi_localtime local ngx_lua_ffi_utctime local ngx_lua_ffi_update_time if subsystem == 'http' then ffi.cdef[[ double ngx_http_lua_ffi_now(void); long ngx_http_lua_ffi_time(void); long ngx_http_lua_ffi_monotonic_msec(void); void ngx_http_lua_ffi_today(unsigned char *buf); void ngx_http_lua_ffi_localtime(unsigned char *buf); void ngx_http_lua_ffi_utctime(unsigned char *buf); void ngx_http_lua_ffi_update_time(void); int ngx_http_lua_ffi_cookie_time(unsigned char *buf, long t); void ngx_http_lua_ffi_http_time(unsigned char *buf, long t); void ngx_http_lua_ffi_parse_http_time(const unsigned char *str, size_t len, long *time); ]] ngx_lua_ffi_now = C.ngx_http_lua_ffi_now ngx_lua_ffi_time = C.ngx_http_lua_ffi_time ngx_lua_ffi_monotonic_msec = C.ngx_http_lua_ffi_monotonic_msec ngx_lua_ffi_today = C.ngx_http_lua_ffi_today ngx_lua_ffi_localtime = C.ngx_http_lua_ffi_localtime ngx_lua_ffi_utctime = C.ngx_http_lua_ffi_utctime ngx_lua_ffi_update_time = C.ngx_http_lua_ffi_update_time elseif subsystem == 'stream' then ffi.cdef[[ double ngx_stream_lua_ffi_now(void); long ngx_stream_lua_ffi_time(void); long ngx_stream_lua_ffi_monotonic_msec(void); void ngx_stream_lua_ffi_today(unsigned char *buf); void ngx_stream_lua_ffi_localtime(unsigned char *buf); void ngx_stream_lua_ffi_utctime(unsigned char *buf); void ngx_stream_lua_ffi_update_time(void); ]] ngx_lua_ffi_now = C.ngx_stream_lua_ffi_now ngx_lua_ffi_time = C.ngx_stream_lua_ffi_time ngx_lua_ffi_monotonic_msec = C.ngx_stream_lua_ffi_monotonic_msec ngx_lua_ffi_today = C.ngx_stream_lua_ffi_today ngx_lua_ffi_localtime = C.ngx_stream_lua_ffi_localtime ngx_lua_ffi_utctime = C.ngx_stream_lua_ffi_utctime ngx_lua_ffi_update_time = C.ngx_stream_lua_ffi_update_time end function ngx.now() local now = tonumber(ngx_lua_ffi_now()) return now end function ngx.time() local time = tonumber(ngx_lua_ffi_time()) return time end local function monotonic_msec() local msec = tonumber(ngx_lua_ffi_monotonic_msec()) return msec end local function monotonic_time() local msec = tonumber(ngx_lua_ffi_monotonic_msec()) local time = msec / 1000 return time end function ngx.update_time() ngx_lua_ffi_update_time() end function ngx.today() -- the format of today is 2010-11-19 local today_buf_size = 10 local buf = get_string_buf(today_buf_size) ngx_lua_ffi_today(buf) return ffi_str(buf, today_buf_size) end function ngx.localtime() -- the format of localtime is 2010-11-19 20:56:31 local localtime_buf_size = 19 local buf = get_string_buf(localtime_buf_size) ngx_lua_ffi_localtime(buf) return ffi_str(buf, localtime_buf_size) end function ngx.utctime() -- the format of utctime is 2010-11-19 20:56:31 local utctime_buf_size = 19 local buf = get_string_buf(utctime_buf_size) ngx_lua_ffi_utctime(buf) return ffi_str(buf, utctime_buf_size) end if subsystem == 'http' then function ngx.cookie_time(sec) if type(sec) ~= "number" then error("number argument only", 2) end -- the format of cookie time is Mon, 28-Sep-2038 06:00:00 GMT -- or Mon, 28-Sep-18 06:00:00 GMT local cookie_time_buf_size = 29 local buf = get_string_buf(cookie_time_buf_size) local used_size = C.ngx_http_lua_ffi_cookie_time(buf, sec) return ffi_str(buf, used_size) end function ngx.http_time(sec) if type(sec) ~= "number" then error("number argument only", 2) end -- the format of http time is Mon, 28 Sep 1970 06:00:00 GMT local http_time_buf_size = 29 local buf = get_string_buf(http_time_buf_size) C.ngx_http_lua_ffi_http_time(buf, sec) return ffi_str(buf, http_time_buf_size) end function ngx.parse_http_time(time_str) if type(time_str) ~= "string" then error("string argument only", 2) end C.ngx_http_lua_ffi_parse_http_time(time_str, #time_str, time_val) local res = time_val[0] if res == FFI_ERROR then return nil end local time = tonumber(res) return time end end return { version = base.version, monotonic_msec = monotonic_msec, monotonic_time = monotonic_time } lua-resty-core-0.1.31/lib/resty/core/time.md000066400000000000000000000103661474236722600206160ustar00rootroot00000000000000Name ==== `resty.core.time` - utility functions for time operations. Table of Contents ================= * [Name](#name) * [Status](#status) * [Synopsis](#synopsis) * [Description](#description) * [Methods](#methods) * [monotonic_msec](#monotonic_msec) * [monotonic_time](#monotonic_time) * [Community](#community) * [English Mailing List](#english-mailing-list) * [Chinese Mailing List](#chinese-mailing-list) * [Bugs and Patches](#bugs-and-patches) * [Copyright and License](#copyright-and-license) * [See Also](#see-also) Status ====== This Lua module is currently considered production ready. Synopsis ======== ```nginx location = /t { content_by_lua_block { local time = require "resty.core.time" ngx.say(time.monotonic_time()) ngx.say(time.monotonic_msec()) } } ``` The value get by `"resty.core.time".monotonic_time` should equal to the value from /proc/uptime. [Back to TOC](#table-of-contents) Description =========== This module provides utility functions for the time operations. [Back to TOC](#table-of-contents) Methods ======= monotonic_msec -------------- **syntax:** *monotonic_msec()* Returns the elapsed time in milliseconds from the machine boot for the current time stamp from the Nginx cached time (no syscall involved unlike Lua's date library). ```lua local cur_msec = require "resty.core.time".monotonic_msec ngx.say(cur_msec()) ``` This api was first introduced in lua-resty-core v0.1.25. [Back to TOC](#table-of-contents) monotonic_time -------------- **syntax:** *monotonic_time()* Returns a floating-point number for the elapsed time in seconds (including milliseconds as the decimal part) from the machine boot for the current time stamp from the Nginx cached time (no syscall involved unlike Lua's date library). ```lua local cur_time = require "resty.core.time".monotonic_time ngx.say(cur_time()) ``` This api was first introduced in lua-resty-core v0.1.25. [Back to TOC](#table-of-contents) Community ========= [Back to TOC](#table-of-contents) English Mailing List -------------------- The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers. [Back to TOC](#table-of-contents) Chinese Mailing List -------------------- The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers. [Back to TOC](#table-of-contents) Bugs and Patches ================ Please report bugs or submit patches by 1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues), 1. or posting to the [OpenResty community](#community). [Back to TOC](#table-of-contents) Copyright and License ===================== This module is licensed under the BSD license. Copyright (C) 2018, by OpenResty Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * 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. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. [Back to TOC](#table-of-contents) See Also ======== * the [lua-resty-core](https://github.com/openresty/lua-resty-core) library. * the ngx_lua module: https://github.com/openresty/lua-nginx-module * OpenResty: https://openresty.org [Back to TOC](#table-of-contents) lua-resty-core-0.1.31/lib/resty/core/uri.lua000066400000000000000000000060321474236722600206330ustar00rootroot00000000000000-- Copyright (C) Yichun Zhang (agentzh) local ffi = require "ffi" local base = require "resty.core.base" local C = ffi.C local ffi_string = ffi.string local ngx = ngx local type = type local error = error local tostring = tostring local get_string_buf = base.get_string_buf local subsystem = ngx.config.subsystem local ngx_lua_ffi_escape_uri local ngx_lua_ffi_unescape_uri local ngx_lua_ffi_uri_escaped_length local NGX_ESCAPE_URI = 0 local NGX_ESCAPE_URI_COMPONENT = 2 local NGX_ESCAPE_MAIL_AUTH = 6 if subsystem == "http" then ffi.cdef[[ size_t ngx_http_lua_ffi_uri_escaped_length(const unsigned char *src, size_t len, int type); void ngx_http_lua_ffi_escape_uri(const unsigned char *src, size_t len, unsigned char *dst, int type); size_t ngx_http_lua_ffi_unescape_uri(const unsigned char *src, size_t len, unsigned char *dst); ]] ngx_lua_ffi_escape_uri = C.ngx_http_lua_ffi_escape_uri ngx_lua_ffi_unescape_uri = C.ngx_http_lua_ffi_unescape_uri ngx_lua_ffi_uri_escaped_length = C.ngx_http_lua_ffi_uri_escaped_length elseif subsystem == "stream" then ffi.cdef[[ size_t ngx_stream_lua_ffi_uri_escaped_length(const unsigned char *src, size_t len, int type); void ngx_stream_lua_ffi_escape_uri(const unsigned char *src, size_t len, unsigned char *dst, int type); size_t ngx_stream_lua_ffi_unescape_uri(const unsigned char *src, size_t len, unsigned char *dst); ]] ngx_lua_ffi_escape_uri = C.ngx_stream_lua_ffi_escape_uri ngx_lua_ffi_unescape_uri = C.ngx_stream_lua_ffi_unescape_uri ngx_lua_ffi_uri_escaped_length = C.ngx_stream_lua_ffi_uri_escaped_length end ngx.escape_uri = function (s, esc_type) if type(s) ~= 'string' then if not s then s = '' else s = tostring(s) end end if esc_type == nil then esc_type = NGX_ESCAPE_URI_COMPONENT else if type(esc_type) ~= 'number' then error("\"type\" is not a number", 3) end if esc_type < NGX_ESCAPE_URI or esc_type > NGX_ESCAPE_MAIL_AUTH then error("\"type\" " .. esc_type .. " out of range", 3) end end local slen = #s local dlen = ngx_lua_ffi_uri_escaped_length(s, slen, esc_type) -- print("dlen: ", tonumber(dlen)) if dlen == slen then return s end local dst = get_string_buf(dlen) ngx_lua_ffi_escape_uri(s, slen, dst, esc_type) return ffi_string(dst, dlen) end ngx.unescape_uri = function (s) if type(s) ~= 'string' then if not s then s = '' else s = tostring(s) end end local slen = #s local dlen = slen local dst = get_string_buf(dlen) dlen = ngx_lua_ffi_unescape_uri(s, slen, dst) return ffi_string(dst, dlen) end return { version = base.version, } lua-resty-core-0.1.31/lib/resty/core/utils.lua000066400000000000000000000017141474236722600211760ustar00rootroot00000000000000-- Copyright (C) Yichun Zhang (agentzh) local ffi = require "ffi" local base = require "resty.core.base" local C = ffi.C local ffi_str = ffi.string local ffi_copy = ffi.copy local byte = string.byte local str_find = string.find local get_string_buf = base.get_string_buf local subsystem = ngx.config.subsystem local _M = { version = base.version } if subsystem == "http" then ffi.cdef[[ void ngx_http_lua_ffi_str_replace_char(unsigned char *buf, size_t len, const unsigned char find, const unsigned char replace); ]] function _M.str_replace_char(str, find, replace) if not str_find(str, find, nil, true) then return str end local len = #str local buf = get_string_buf(len) ffi_copy(buf, str, len) C.ngx_http_lua_ffi_str_replace_char(buf, len, byte(find), byte(replace)) return ffi_str(buf, len) end end return _M lua-resty-core-0.1.31/lib/resty/core/var.lua000066400000000000000000000075051474236722600206320ustar00rootroot00000000000000-- Copyright (C) Yichun Zhang (agentzh) local ffi = require "ffi" local base = require "resty.core.base" local C = ffi.C local ffi_new = ffi.new local ffi_str = ffi.string local type = type local error = error local tostring = tostring local setmetatable = setmetatable local get_request = base.get_request local get_string_buf = base.get_string_buf local get_size_ptr = base.get_size_ptr local new_tab = base.new_tab local subsystem = ngx.config.subsystem local ngx_lua_ffi_var_get local ngx_lua_ffi_var_set local ERR_BUF_SIZE = 256 ngx.var = new_tab(0, 0) if subsystem == "http" then ffi.cdef[[ int ngx_http_lua_ffi_var_get(ngx_http_request_t *r, const char *name_data, size_t name_len, char *lowcase_buf, int capture_id, char **value, size_t *value_len, char **err); int ngx_http_lua_ffi_var_set(ngx_http_request_t *r, const unsigned char *name_data, size_t name_len, unsigned char *lowcase_buf, const unsigned char *value, size_t value_len, unsigned char *errbuf, size_t *errlen); ]] ngx_lua_ffi_var_get = C.ngx_http_lua_ffi_var_get ngx_lua_ffi_var_set = C.ngx_http_lua_ffi_var_set elseif subsystem == "stream" then ffi.cdef[[ int ngx_stream_lua_ffi_var_get(ngx_stream_lua_request_t *r, const char *name_data, size_t name_len, char *lowcase_buf, int capture_id, char **value, size_t *value_len, char **err); int ngx_stream_lua_ffi_var_set(ngx_stream_lua_request_t *r, const unsigned char *name_data, size_t name_len, unsigned char *lowcase_buf, const unsigned char *value, size_t value_len, unsigned char *errbuf, size_t *errlen); ]] ngx_lua_ffi_var_get = C.ngx_stream_lua_ffi_var_get ngx_lua_ffi_var_set = C.ngx_stream_lua_ffi_var_set end local value_ptr = ffi_new("unsigned char *[1]") local errmsg = base.get_errmsg_ptr() local function var_get(self, name) local r = get_request() if not r then error("no request found") end local value_len = get_size_ptr() local rc if type(name) == "number" then rc = ngx_lua_ffi_var_get(r, nil, 0, nil, name, value_ptr, value_len, errmsg) else if type(name) ~= "string" then error("bad variable name", 2) end local name_len = #name local lowcase_buf = get_string_buf(name_len) rc = ngx_lua_ffi_var_get(r, name, name_len, lowcase_buf, 0, value_ptr, value_len, errmsg) end -- ngx.log(ngx.WARN, "rc = ", rc) if rc == 0 then -- NGX_OK return ffi_str(value_ptr[0], value_len[0]) end if rc == -5 then -- NGX_DECLINED return nil end if rc == -1 then -- NGX_ERROR error(ffi_str(errmsg[0]), 2) end end local function var_set(self, name, value) local r = get_request() if not r then error("no request found") end if type(name) ~= "string" then error("bad variable name", 2) end local name_len = #name local errlen = get_size_ptr() errlen[0] = ERR_BUF_SIZE local lowcase_buf = get_string_buf(name_len + ERR_BUF_SIZE) local value_len if value == nil then value_len = 0 else if type(value) ~= 'string' then value = tostring(value) end value_len = #value end local errbuf = lowcase_buf + name_len local rc = ngx_lua_ffi_var_set(r, name, name_len, lowcase_buf, value, value_len, errbuf, errlen) -- ngx.log(ngx.WARN, "rc = ", rc) if rc == 0 then -- NGX_OK return end if rc == -1 then -- NGX_ERROR error(ffi_str(errbuf, errlen[0]), 2) end end do local mt = new_tab(0, 2) mt.__index = var_get mt.__newindex = var_set setmetatable(ngx.var, mt) end return { version = base.version } lua-resty-core-0.1.31/lib/resty/core/worker.lua000066400000000000000000000066461474236722600213600ustar00rootroot00000000000000-- Copyright (C) Yichun Zhang (agentzh) local ffi = require "ffi" local jit = require "jit" local base = require "resty.core.base" local ffi_cast = ffi.cast local C = ffi.C local new_tab = base.new_tab local subsystem = ngx.config.subsystem local get_string_buf = base.get_string_buf local get_size_ptr = base.get_size_ptr local ngx_lua_ffi_worker_id local ngx_lua_ffi_worker_pid local ngx_lua_ffi_worker_pids local ngx_lua_ffi_worker_count local ngx_lua_ffi_worker_exiting local ffi_intp_type = ffi.typeof("int *") local ffi_int_size = ffi.sizeof("int") local is_not_windows = jit.os ~= "Windows" if is_not_windows then ngx.worker = new_tab(0, 5) else ngx.worker = new_tab(0, 4) end if subsystem == "http" then ffi.cdef[[ int ngx_http_lua_ffi_worker_id(void); int ngx_http_lua_ffi_worker_pid(void); int ngx_http_lua_ffi_worker_count(void); int ngx_http_lua_ffi_worker_exiting(void); ]] ngx_lua_ffi_worker_id = C.ngx_http_lua_ffi_worker_id ngx_lua_ffi_worker_pid = C.ngx_http_lua_ffi_worker_pid ngx_lua_ffi_worker_count = C.ngx_http_lua_ffi_worker_count ngx_lua_ffi_worker_exiting = C.ngx_http_lua_ffi_worker_exiting elseif subsystem == "stream" then ffi.cdef[[ int ngx_stream_lua_ffi_worker_id(void); int ngx_stream_lua_ffi_worker_pid(void); int ngx_stream_lua_ffi_worker_count(void); int ngx_stream_lua_ffi_worker_exiting(void); ]] ngx_lua_ffi_worker_id = C.ngx_stream_lua_ffi_worker_id ngx_lua_ffi_worker_pid = C.ngx_stream_lua_ffi_worker_pid ngx_lua_ffi_worker_count = C.ngx_stream_lua_ffi_worker_count ngx_lua_ffi_worker_exiting = C.ngx_stream_lua_ffi_worker_exiting end function ngx.worker.exiting() return ngx_lua_ffi_worker_exiting() ~= 0 end function ngx.worker.pid() return ngx_lua_ffi_worker_pid() end if is_not_windows then if subsystem == "http" then require "resty.core.phase" -- for ngx.get_phase ffi.cdef[[ int ngx_http_lua_ffi_worker_pids(int *pids, size_t *pids_len); ]] ngx_lua_ffi_worker_pids = C.ngx_http_lua_ffi_worker_pids elseif subsystem == "stream" then ffi.cdef[[ int ngx_stream_lua_ffi_worker_pids(int *pids, size_t *pids_len); ]] ngx_lua_ffi_worker_pids = C.ngx_stream_lua_ffi_worker_pids end local tonumber = tonumber local ngx_phase = ngx.get_phase function ngx.worker.pids() local phase = ngx_phase() if phase == "init" or phase == "init_worker" then return nil, "API disabled in the current context" end local pids = {} local size_ptr = get_size_ptr() -- the old and the new workers coexist during reloading local worker_cnt = ngx_lua_ffi_worker_count() * 4 if worker_cnt == 0 then return pids end size_ptr[0] = worker_cnt local pids_ptr = get_string_buf(worker_cnt * ffi_int_size) local intp_buf = ffi_cast(ffi_intp_type, pids_ptr) local res = ngx_lua_ffi_worker_pids(intp_buf, size_ptr) if res == 0 then for i = 1, tonumber(size_ptr[0]) do pids[i] = intp_buf[i - 1] end end return pids end end function ngx.worker.id() local id = ngx_lua_ffi_worker_id() if id < 0 then return nil end return id end function ngx.worker.count() return ngx_lua_ffi_worker_count() end return { _VERSION = base.version } lua-resty-core-0.1.31/t/000077500000000000000000000000001474236722600147275ustar00rootroot00000000000000lua-resty-core-0.1.31/t/TestCore.pm000066400000000000000000000034551474236722600170240ustar00rootroot00000000000000package t::TestCore; use Test::Nginx::Socket::Lua -Base; use Cwd qw(cwd realpath abs_path); use File::Basename; use Test::Nginx::Util 'is_tcp_port_used'; $ENV{TEST_NGINX_HOTLOOP} ||= 10; $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_CERT_DIR} ||= dirname(realpath(abs_path(__FILE__))); sub get_unused_port ($); $ENV{TEST_NGINX_SERVER_SSL_PORT} ||= get_unused_port 23456; our $pwd = cwd(); our $lua_package_path = './lib/?.lua;./t/lib/?.lua;../lua-resty-lrucache/lib/?.lua;;'; our $init_by_lua_block = <<_EOC_; local verbose = false if verbose then local dump = require "jit.dump" dump.on("b", "$Test::Nginx::Util::ErrLogFile") else local v = require "jit.v" v.on("$Test::Nginx::Util::ErrLogFile") end require "resty.core" jit.opt.start("hotloop=$ENV{TEST_NGINX_HOTLOOP}") -- jit.off() _EOC_ our $HttpConfig = <<_EOC_; lua_package_path '$lua_package_path'; init_by_lua_block { $t::TestCore::init_by_lua_block } _EOC_ our @EXPORT = qw( $pwd $lua_package_path $init_by_lua_block $HttpConfig get_unused_port ); add_block_preprocessor(sub { my $block = shift; if (!defined $block->http_config) { $block->set_value("http_config", $HttpConfig); } if ($Test::Nginx::Util::UseValgrind) { my $timeout = $block->timeout || 3; $timeout *= 5; $block->set_value("timeout", $timeout); } }); sub get_unused_port ($) { my $port = shift; my $i = 1000; srand($$); # reset the random seed while ($i-- > 0) { my $rand_port = $port + int(rand(65535 - $port)); if (!is_tcp_port_used $rand_port) { #warn "found unused port $rand_port, pid $$\n"; return $rand_port; } } die "no unused port available"; } 1; lua-resty-core-0.1.31/t/TestCore/000077500000000000000000000000001474236722600164575ustar00rootroot00000000000000lua-resty-core-0.1.31/t/TestCore/Stream.pm000066400000000000000000000027111474236722600202510ustar00rootroot00000000000000package t::TestCore::Stream; use Test::Nginx::Socket::Lua::Stream -Base; use Cwd qw(cwd); use Test::Nginx::Util 'is_tcp_port_used'; $ENV{TEST_NGINX_HOTLOOP} ||= 10; sub get_unused_port ($); our $pwd = cwd(); our $lua_package_path = './lib/?.lua;../lua-resty-lrucache/lib/?.lua;;'; our $init_by_lua_block = <<_EOC_; local verbose = false if verbose then local dump = require "jit.dump" dump.on("b", "$Test::Nginx::Util::ErrLogFile") else local v = require "jit.v" v.on("$Test::Nginx::Util::ErrLogFile") end require "resty.core" jit.opt.start("hotloop=$ENV{TEST_NGINX_HOTLOOP}") -- jit.off() _EOC_ our $StreamConfig = <<_EOC_; lua_package_path '$lua_package_path'; init_by_lua_block { $t::TestCore::Stream::init_by_lua_block } _EOC_ our @EXPORT = qw( $pwd $lua_package_path $init_by_lua_block $StreamConfig get_unused_port ); add_block_preprocessor(sub { my $block = shift; if (!defined $block->stream_config) { $block->set_value("stream_config", $StreamConfig); } }); sub get_unused_port ($) { my $port = shift; my $i = 1000; srand($$); # reset the random seed while ($i-- > 0) { my $rand_port = $port + int(rand(65535 - $port)); if (!is_tcp_port_used $rand_port) { #warn "found unused port $rand_port, pid $$\n"; return $rand_port; } } die "no unused port available"; } 1; lua-resty-core-0.1.31/t/balancer-keepalive-localaddr.t000066400000000000000000000355251474236722600225630ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; my $NginxBinary = $ENV{TEST_NGINX_BINARY} || 'nginx'; my $NginxV = eval { `$NginxBinary -V 2>&1` }; if ($NginxV !~ m/built with OpenSSL/) { plan(skip_all => "OpenSSL required"); } elsif ($NginxV !~ m/--with-debug/) { plan(skip_all => "--with-debug required"); } else { plan tests => repeat_each() * (blocks() * 4); } our $UpstreamSrvConfig = <<_EOC_; server { listen 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT} ssl; listen 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT} ssl; ssl_certificate $ENV{TEST_NGINX_CERT_DIR}/cert/test.crt; ssl_certificate_key $ENV{TEST_NGINX_CERT_DIR}/cert/test.key; ssl_session_tickets off; ssl_verify_client optional_no_ca; keepalive_requests 1000; location = /echo_client_addr { content_by_lua_block { ngx.say(ngx.var.remote_addr) } } location = /echo_client_addr_port { content_by_lua_block { ngx.say(ngx.var.remote_addr, ":", ngx.var.remote_port) } } location / { return 200; } } _EOC_ our $ProxyLocConfig = <<_EOC_; location ~ ^/proxy/(?.*) { proxy_ssl_verify off; proxy_ssl_server_name on; proxy_ssl_name '\$arg_sni'; proxy_http_version 1.1; proxy_set_header Connection ''; proxy_pass https://test_upstream/\$upstream_uri; } _EOC_ add_block_preprocessor(sub { my $block = shift; if (defined $block->http_upstream) { $block->set_value("http_config", $block->http_upstream . "\n" . $UpstreamSrvConfig); } if (defined $block->config) { $block->set_value("config", $block->config . "\n" . $ProxyLocConfig); } else { $block->set_value("config", $ProxyLocConfig); } if (!defined $block->request) { $block->set_value("request", "GET /t"); } if (!defined $block->grep_error_log) { $block->set_value("grep_error_log", qr/lua balancer: keepalive (?!closing).*/); } if (!defined $block->no_error_log) { $block->set_value("no_error_log", "[error]"); } }); log_level('debug'); no_long_string(); run_tests(); __DATA__ === TEST 1: get keepalive from pool --- http_upstream upstream test_upstream { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" local ip = ngx.var.arg_ip or "127.0.0.1" local port = ngx.var.arg_port or $TEST_NGINX_SERVER_SSL_PORT local ok, err = b.set_current_peer(ip, port, "test.com") if not ok then ngx.log(ngx.ERR, "failed to set current peer: ", err) return end local ok, err = b.enable_keepalive() if not ok then ngx.log(ngx.ERR, "failed to set keepalive: ", err) return end ok, err = b.bind_to_local_addr("127.0.0.11") if not ok then ngx.log(ngx.ERR, "failed to set local addr: ", err) return end } } --- config eval " location = /t { echo_subrequest GET '/proxy/echo_client_addr' -q 'ip=127.0.0.2'; echo_subrequest GET '/proxy/echo_client_addr' -q 'ip=127.0.0.2'; } " --- response_body 127.0.0.11 127.0.0.11 --- grep_error_log_out eval qr/^lua balancer: keepalive no free connection, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com lua balancer: keepalive saving connection [0-9A-F]+, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com lua balancer: keepalive reusing connection [0-9A-F]+, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com lua balancer: keepalive saving connection [0-9A-F]+, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com $/ === TEST 2: get keepalive from pool twice --- http_upstream upstream test_upstream { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" local ip = ngx.var.arg_ip or "127.0.0.1" local port = ngx.var.arg_port or $TEST_NGINX_SERVER_SSL_PORT local ok, err = b.set_current_peer(ip, port, "test.com") if not ok then ngx.log(ngx.ERR, "failed to set current peer: ", err) return end local ok, err = b.enable_keepalive() if not ok then ngx.log(ngx.ERR, "failed to set keepalive: ", err) return end ok, err = b.bind_to_local_addr("127.0.0.11") if not ok then ngx.log(ngx.ERR, "failed to set local addr: ", err) return end } } --- config eval " location = /t { echo_subrequest GET '/proxy/echo_client_addr' -q 'ip=127.0.0.2'; echo_subrequest GET '/proxy/echo_client_addr' -q 'ip=127.0.0.2'; echo_subrequest GET '/proxy/echo_client_addr' -q 'ip=127.0.0.2'; } " --- response_body 127.0.0.11 127.0.0.11 127.0.0.11 --- grep_error_log_out eval qr/^lua balancer: keepalive no free connection, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com lua balancer: keepalive saving connection [0-9A-F]+, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com lua balancer: keepalive reusing connection [0-9A-F]+, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com lua balancer: keepalive saving connection [0-9A-F]+, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com lua balancer: keepalive reusing connection [0-9A-F]+, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com lua balancer: keepalive saving connection [0-9A-F]+, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com $/ === TEST 3: can not get idle connection from the pool --- http_upstream upstream test_upstream { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" local ip = ngx.var.arg_ip or "127.0.0.1" local port = ngx.var.arg_port or $TEST_NGINX_SERVER_SSL_PORT local ok, err = b.set_current_peer(ip, port, "test.com") if not ok then ngx.log(ngx.ERR, "failed to set current peer: ", err) return end local ok, err = b.enable_keepalive() if not ok then ngx.log(ngx.ERR, "failed to set keepalive: ", err) return end local src_ip = ngx.var.arg_src_ip or "127.0.0.1" ok, err = b.bind_to_local_addr(src_ip) if not ok then ngx.log(ngx.ERR, "failed to set local addr: ", err) return end } } --- config eval " location = /t { echo_subrequest GET '/proxy/echo_client_addr' -q 'ip=127.0.0.2&src_ip=127.0.0.10'; echo_subrequest GET '/proxy/echo_client_addr' -q 'ip=127.0.0.2&src_ip=127.0.0.11'; } " --- response_body 127.0.0.10 127.0.0.11 --- grep_error_log_out eval qr/^lua balancer: keepalive no free connection, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com lua balancer: keepalive saving connection [0-9A-F]+, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com lua balancer: keepalive no free connection, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com lua balancer: keepalive saving connection [0-9A-F]+, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com $/ === TEST 4: et idle connections from the pool for different src ip --- http_upstream upstream test_upstream { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" local ip = ngx.var.arg_ip or "127.0.0.1" local port = ngx.var.arg_port or $TEST_NGINX_SERVER_SSL_PORT local ok, err = b.set_current_peer(ip, port, "test.com") if not ok then ngx.log(ngx.ERR, "failed to set current peer: ", err) return end local ok, err = b.enable_keepalive() if not ok then ngx.log(ngx.ERR, "failed to set keepalive: ", err) return end local src_ip = ngx.var.arg_src_ip or "127.0.0.1" ok, err = b.bind_to_local_addr(src_ip) if not ok then ngx.log(ngx.ERR, "failed to set local addr: ", err) return end } } --- config eval " location = /t { echo_subrequest GET '/proxy/echo_client_addr' -q 'ip=127.0.0.2&src_ip=127.0.0.10'; echo_subrequest GET '/proxy/echo_client_addr' -q 'ip=127.0.0.2&src_ip=127.0.0.11'; echo_subrequest GET '/proxy/echo_client_addr' -q 'ip=127.0.0.2&src_ip=127.0.0.11'; echo_subrequest GET '/proxy/echo_client_addr' -q 'ip=127.0.0.2&src_ip=127.0.0.10'; } " --- response_body 127.0.0.10 127.0.0.11 127.0.0.11 127.0.0.10 --- grep_error_log_out eval qr/^lua balancer: keepalive no free connection, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com lua balancer: keepalive saving connection [0-9A-F]+, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com lua balancer: keepalive no free connection, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com lua balancer: keepalive saving connection [0-9A-F]+, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com lua balancer: keepalive reusing connection [0-9A-F]+, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com lua balancer: keepalive saving connection [0-9A-F]+, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com lua balancer: keepalive reusing connection [0-9A-F]+, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com lua balancer: keepalive saving connection [0-9A-F]+, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com $/ === TEST 5: should not use idle connection with different dest ip --- http_upstream upstream test_upstream { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" local ip = ngx.var.arg_ip or "127.0.0.1" local port = ngx.var.arg_port or $TEST_NGINX_SERVER_SSL_PORT local ok, err = b.set_current_peer(ip, port, "test.com") if not ok then ngx.log(ngx.ERR, "failed to set current peer: ", err) return end local ok, err = b.enable_keepalive() if not ok then ngx.log(ngx.ERR, "failed to set keepalive: ", err) return end ok, err = b.bind_to_local_addr("127.0.0.11") if not ok then ngx.log(ngx.ERR, "failed to set local addr: ", err) return end } } --- config eval " location = /t { echo_subrequest GET '/proxy/echo_client_addr' -q 'ip=127.0.0.1'; echo_subrequest GET '/proxy/echo_client_addr' -q 'ip=127.0.0.2'; } " --- response_body 127.0.0.11 127.0.0.11 --- grep_error_log_out eval qr/^lua balancer: keepalive no free connection, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com lua balancer: keepalive saving connection [0-9A-F]+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com lua balancer: keepalive no free connection, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com lua balancer: keepalive saving connection [0-9A-F]+, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com $/ === TEST 6: empty host --- http_upstream upstream test_upstream { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" local ip = ngx.var.arg_ip or "127.0.0.1" local port = ngx.var.arg_port or $TEST_NGINX_SERVER_SSL_PORT local ok, err = b.set_current_peer(ip, port, "test.com") if not ok then ngx.log(ngx.ERR, "failed to set current peer: ", err) return end local ok, err = b.enable_keepalive() if not ok then ngx.log(ngx.ERR, "failed to set keepalive: ", err) return end ok, err = b.bind_to_local_addr("127.0.0.11") if not ok then ngx.log(ngx.ERR, "failed to set local addr: ", err) return end } } --- config eval " location = /t { echo_subrequest GET '/proxy/echo_client_addr' -q 'ip=127.0.0.2'; echo_subrequest GET '/proxy/echo_client_addr' -q 'ip=127.0.0.2'; } " --- response_body 127.0.0.11 127.0.0.11 --- grep_error_log_out eval qr/^lua balancer: keepalive no free connection, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com lua balancer: keepalive saving connection [0-9A-F]+, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com lua balancer: keepalive reusing connection [0-9A-F]+, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com lua balancer: keepalive saving connection [0-9A-F]+, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com $/ === TEST 7: bind addr with port --- http_upstream upstream test_upstream { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" local ip = ngx.var.arg_ip or "127.0.0.1" local port = ngx.var.arg_port or $TEST_NGINX_SERVER_SSL_PORT local ok, err = b.set_current_peer(ip, port, "test.com") if not ok then ngx.log(ngx.ERR, "failed to set current peer: ", err) return end local ok, err = b.enable_keepalive() if not ok then ngx.log(ngx.ERR, "failed to set keepalive: ", err) return end ok, err = b.bind_to_local_addr("127.0.0.11:64321") if not ok then ngx.log(ngx.ERR, "failed to set local addr: ", err) return end } } --- config eval " location = /t { echo_subrequest GET '/proxy/echo_client_addr_port' -q 'ip=127.0.0.2'; echo_subrequest GET '/proxy/echo_client_addr_port' -q 'ip=127.0.0.2'; } " --- response_body 127.0.0.11:64321 127.0.0.11:64321 --- grep_error_log_out eval qr/^lua balancer: keepalive no free connection, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com lua balancer: keepalive saving connection [0-9A-F]+, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com lua balancer: keepalive reusing connection [0-9A-F]+, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com lua balancer: keepalive saving connection [0-9A-F]+, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.com $/ lua-resty-core-0.1.31/t/balancer-keepalive.t000066400000000000000000001211311474236722600206250ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; my $NginxBinary = $ENV{TEST_NGINX_BINARY} || 'nginx'; my $NginxV = eval { `$NginxBinary -V 2>&1` }; if ($NginxV !~ m/built with OpenSSL/) { plan(skip_all => "OpenSSL required"); } elsif ($NginxV !~ m/--with-debug/) { plan(skip_all => "--with-debug required"); } else { plan tests => repeat_each() * (blocks() * 4); } $ENV{TEST_NGINX_SERVER_SSL_PORT_2} = get_unused_port $ENV{TEST_NGINX_SERVER_SSL_PORT} + 1; our $UpstreamSrvConfig = <<_EOC_; server { listen 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT} ssl; listen 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT} ssl; listen 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT_2} ssl; ssl_certificate $ENV{TEST_NGINX_CERT_DIR}/cert/test.crt; ssl_certificate_key $ENV{TEST_NGINX_CERT_DIR}/cert/test.key; ssl_session_tickets off; ssl_verify_client optional_no_ca; keepalive_requests 1000; location = /echo_sni { return 200 'SNI=\$ssl_server_name\\n'; } location = /echo_ssl_client_s_dn_and_protocol { return 200 'ssl_client_s_dn=\$ssl_client_s_dn ssl_protocol=\$ssl_protocol\\n'; } location = /close { add_header Connection close; return 200; } location = /short_keepalive { keepalive_timeout 100ms; return 200; } location = /sleep { echo_sleep 0.3; echo_status 200; } location / { return 200; } } _EOC_ our $ProxyLocConfig = <<_EOC_; location ~ ^/proxy/(?.*) { proxy_ssl_verify off; proxy_ssl_server_name on; proxy_ssl_name '\$arg_sni'; proxy_http_version 1.1; proxy_set_header Connection ''; proxy_pass https://test_upstream/\$upstream_uri; } location ~ ^/proxy_lua_sni/(?.*) { proxy_ssl_verify off; proxy_ssl_server_name on; #proxy_ssl_name '\$arg_sni'; proxy_http_version 1.1; proxy_set_header Connection ''; proxy_pass https://test_upstream/\$upstream_uri; } _EOC_ add_block_preprocessor(sub { my $block = shift; if (defined $block->http_upstream) { $block->set_value("http_config", $block->http_upstream . "\n" . $UpstreamSrvConfig); } if (defined $block->config) { $block->set_value("config", $block->config . "\n" . $ProxyLocConfig); } else { $block->set_value("config", $ProxyLocConfig); } if (!defined $block->request) { $block->set_value("request", "GET /t"); } if (!defined $block->grep_error_log) { $block->set_value("grep_error_log", qr/lua balancer: keepalive .*/); } if (!defined $block->no_error_log) { $block->set_value("no_error_log", "[error]"); } }); log_level('debug'); no_long_string(); run_tests(); __DATA__ === TEST 1: upstream_keepalive_module: sanity (nginx default) --- http_upstream upstream test_upstream { server 127.0.0.1:$TEST_NGINX_SERVER_SSL_PORT; keepalive 60; } --- config location = /t { echo_subrequest GET '/proxy/echo_sni' -q 'sni=one'; echo_subrequest GET '/proxy/echo_sni' -q 'sni=two'; } --- response_body SNI=one SNI=one --- grep_error_log_out === TEST 2: enable_keepalive: sanity (different ip port) --- http_upstream upstream test_upstream { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" local ip = ngx.var.arg_ip or "127.0.0.1" local port = ngx.var.arg_port or $TEST_NGINX_SERVER_SSL_PORT local ok, err = b.set_current_peer(ip, port) if not ok then ngx.log(ngx.ERR, "failed to set current peer: ", err) return end local ok, err = b.enable_keepalive() if not ok then ngx.log(ngx.ERR, "failed to set keepalive: ", err) return end } } --- config eval " location = /t { echo_subrequest GET '/proxy/echo_sni' -q 'sni=one'; echo_subrequest GET '/proxy/echo_sni' -q 'sni=two'; echo_subrequest GET '/proxy/echo_sni' -q 'sni=two&ip=127.0.0.2'; echo_subrequest GET '/proxy/echo_sni' -q 'sni=three&ip=127.0.0.2'; echo_subrequest GET '/proxy/echo_sni' -q 'sni=three&ip=127.0.0.2&port=$ENV{TEST_NGINX_SERVER_SSL_PORT_2}'; } " --- response_body SNI=one SNI=two SNI=two SNI=three SNI=three --- grep_error_log_out eval qr/^lua balancer: keepalive no free connection, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: one lua balancer: keepalive saving connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: one lua balancer: keepalive no free connection, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: two lua balancer: keepalive saving connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: two lua balancer: keepalive no free connection, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: two lua balancer: keepalive saving connection \S+, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: two lua balancer: keepalive no free connection, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: three lua balancer: keepalive saving connection \S+, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: three lua balancer: keepalive no free connection, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT_2}, name: three lua balancer: keepalive saving connection \S+, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT_2}, name: three$/ === TEST 3: enable_keepalive: sanity(same ip port with different sni) --- http_upstream upstream test_upstream { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" local pool local ip = ngx.var.arg_ip or "127.0.0.1" local port = ngx.var.arg_port or $TEST_NGINX_SERVER_SSL_PORT local ok, err = b.set_current_peer(ip, port) if not ok then ngx.log(ngx.ERR, "failed to set current peer: ", err) return end local ok, err = b.enable_keepalive() if not ok then ngx.log(ngx.ERR, "failed to set keepalive: ", err) return end } } --- config location = /t { echo_subrequest GET '/proxy/echo_sni' -q 'sni=one'; echo_subrequest GET '/proxy/echo_sni' -q 'sni=two'; echo_subrequest GET '/proxy/echo_sni' -q 'sni=three'; } --- response_body SNI=one SNI=two SNI=three --- grep_error_log_out eval qr/^lua balancer: keepalive no free connection, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: one lua balancer: keepalive saving connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: one lua balancer: keepalive no free connection, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: two lua balancer: keepalive saving connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: two lua balancer: keepalive no free connection, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: three lua balancer: keepalive saving connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: three/ === TEST 4: enable_keepalive: sanity --- http_upstream upstream test_upstream { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" local ip = ngx.var.arg_ip or "127.0.0.1" local port = ngx.var.arg_port or $TEST_NGINX_SERVER_SSL_PORT local ok, err = b.set_current_peer(ip, port) if not ok then ngx.log(ngx.ERR, "failed to set current peer: ", err) return end local ok, err = b.enable_keepalive() if not ok then ngx.log(ngx.ERR, "failed to set keepalive: ", err) return end } } --- config eval " location = /t { echo_subrequest GET '/proxy/echo_sni' -q 'sni=one'; echo_subrequest GET '/proxy/echo_sni' -q 'sni=two'; echo_subrequest GET '/proxy/echo_sni' -q 'sni=two&ip=127.0.0.2'; echo_subrequest GET '/proxy/echo_sni' -q 'sni=three&ip=127.0.0.2'; echo_subrequest GET '/proxy/echo_sni' -q 'sni=three&ip=127.0.0.2&port=$ENV{TEST_NGINX_SERVER_SSL_PORT_2}'; } " --- response_body SNI=one SNI=two SNI=two SNI=three SNI=three --- grep_error_log_out eval qr/^lua balancer: keepalive no free connection, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: one lua balancer: keepalive saving connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: one lua balancer: keepalive no free connection, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: two lua balancer: keepalive saving connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: two lua balancer: keepalive no free connection, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: two lua balancer: keepalive saving connection \S+, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: two lua balancer: keepalive no free connection, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: three lua balancer: keepalive saving connection \S+, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: three lua balancer: keepalive no free connection, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT_2}, name: three lua balancer: keepalive saving connection \S+, host: 127.0.0.2:$ENV{TEST_NGINX_SERVER_SSL_PORT_2}, name: three$/ === TEST 5: enable_keepalive: sanity (dynamic sni option) --- http_upstream upstream test_upstream { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" local ok, err = b.set_current_peer("127.0.0.1", $TEST_NGINX_SERVER_SSL_PORT, ngx.var.arg_sni) if not ok then ngx.log(ngx.ERR, "failed to set current peer: ", err) return end local ok, err = b.enable_keepalive() if not ok then ngx.log(ngx.ERR, "failed to set keepalive: ", err) return end } } --- config location = /t { echo_subrequest GET '/proxy_lua_sni/echo_sni' -q 'sni=one'; echo_subrequest GET '/proxy_lua_sni/echo_sni' -q 'sni=two'; } --- response_body SNI=one SNI=two --- grep_error_log_out eval qr/^lua balancer: keepalive no free connection, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: one lua balancer: keepalive saving connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: one lua balancer: keepalive no free connection, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: two lua balancer: keepalive saving connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: two $/ === TEST 6: upstream_keepalive_module: no granular pooling (TLS properties) --- http_upstream upstream test_upstream { server 127.0.0.1:$TEST_NGINX_SERVER_SSL_PORT; keepalive 60; } --- config proxy_ssl_verify off; proxy_http_version 1.1; proxy_set_header Connection ''; location ~ ^/client_one/tls11/proxy/(?.*) { proxy_ssl_protocols TLSv1.1; proxy_ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; proxy_ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; proxy_pass https://test_upstream/$upstream_uri; } location ~ ^/client_one/tls12/proxy/(?.*) { proxy_ssl_protocols TLSv1.2; proxy_ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; proxy_ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; proxy_pass https://test_upstream/$upstream_uri; } location ~ ^/client_two/tls11/proxy/(?.*) { proxy_ssl_protocols TLSv1.1; proxy_ssl_certificate $TEST_NGINX_CERT_DIR/cert/test2.crt; proxy_ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test2.key; proxy_pass https://test_upstream/$upstream_uri; } location ~ ^/client_two/tls12/proxy/(?.*) { proxy_ssl_protocols TLSv1.2; proxy_ssl_certificate $TEST_NGINX_CERT_DIR/cert/test2.crt; proxy_ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test2.key; proxy_pass https://test_upstream/$upstream_uri; } location = /t { echo_subrequest GET '/client_one/tls11/proxy/echo_ssl_client_s_dn_and_protocol'; echo_subrequest GET '/client_one/tls12/proxy/echo_ssl_client_s_dn_and_protocol'; echo_subrequest GET '/client_two/tls11/proxy/echo_ssl_client_s_dn_and_protocol'; echo_subrequest GET '/client_two/tls12/proxy/echo_ssl_client_s_dn_and_protocol'; } --- response_body_like ssl_client_s_dn=.*?CN=test\.com.*? ssl_protocol=TLSv1\.1 ssl_client_s_dn=.*?CN=test\.com.*? ssl_protocol=TLSv1\.1 ssl_client_s_dn=.*?CN=test\.com.*? ssl_protocol=TLSv1\.1 ssl_client_s_dn=.*?CN=test\.com.*? ssl_protocol=TLSv1\.1 --- grep_error_log_out === TEST 7: enable_keepalive: do not support reuse by TLS properties --- http_upstream upstream test_upstream { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" local ok, err = b.set_current_peer("127.0.0.1", $TEST_NGINX_SERVER_SSL_PORT, ngx.var.client_cert) if not ok then ngx.log(ngx.ERR, "failed to set current peer: ", err) return end local ok, err = b.enable_keepalive() if not ok then ngx.log(ngx.ERR, "failed to set keepalive: ", err) return end } } --- config proxy_ssl_verify off; proxy_http_version 1.1; proxy_set_header Connection ''; location ~ ^/client_one/tls11/proxy/(?.*) { set $client_cert 'test.crt'; set $client_protocol 'TLSv1.1'; proxy_ssl_protocols TLSv1.1; proxy_ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; proxy_ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; proxy_pass https://test_upstream/$upstream_uri; } location ~ ^/client_one/tls12/proxy/(?.*) { set $client_cert 'test.crt'; set $client_protocol 'TLSv1.2'; proxy_ssl_protocols TLSv1.2; proxy_ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; proxy_ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; proxy_pass https://test_upstream/$upstream_uri; } location ~ ^/client_two/tls11/proxy/(?.*) { set $client_cert 'test2.crt'; set $client_protocol 'TLSv1.1'; proxy_ssl_protocols TLSv1.1; proxy_ssl_certificate $TEST_NGINX_CERT_DIR/cert/test2.crt; proxy_ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test2.key; proxy_pass https://test_upstream/$upstream_uri; } location ~ ^/client_two/tls12/proxy/(?.*) { set $client_cert 'test2.crt'; set $client_protocol 'TLSv1.2'; proxy_ssl_protocols TLSv1.2; proxy_ssl_certificate $TEST_NGINX_CERT_DIR/cert/test2.crt; proxy_ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test2.key; proxy_pass https://test_upstream/$upstream_uri; } location = /t { echo_subrequest GET '/client_one/tls11/proxy/echo_ssl_client_s_dn_and_protocol'; echo_subrequest GET '/client_one/tls12/proxy/echo_ssl_client_s_dn_and_protocol'; echo_subrequest GET '/client_two/tls11/proxy/echo_ssl_client_s_dn_and_protocol'; echo_subrequest GET '/client_two/tls12/proxy/echo_ssl_client_s_dn_and_protocol'; } --- response_body_like ssl_client_s_dn=.*?CN=test\.com.*? ssl_protocol=TLSv1\.1 ssl_client_s_dn=.*?CN=test\.com.*? ssl_protocol=TLSv1\.1 ssl_client_s_dn=.*?CN=test2\.com.*? ssl_protocol=TLSv1\.1 ssl_client_s_dn=.*?CN=test2\.com.*? ssl_protocol=TLSv1\.1 --- grep_error_log_out eval qr/^lua balancer: keepalive no free connection, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.crt lua balancer: keepalive saving connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.crt lua balancer: keepalive reusing connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.crt lua balancer: keepalive saving connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test.crt lua balancer: keepalive no free connection, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test2.crt lua balancer: keepalive saving connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test2.crt lua balancer: keepalive reusing connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test2.crt lua balancer: keepalive saving connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: test2.crt $/ === TEST 8: set_current_peer: bad argument #4 'sni' --- config location = /t { content_by_lua_block { local b = require "ngx.balancer" local values = { true, 0 } for _, val in ipairs(values) do local pok, perr = pcall(b.set_current_peer, "127.0.0.1", 80, val) if not pok then ngx.say(perr) end end } } --- response_body eval qr{./lib/ngx/balancer.lua:\d+: bad argument #3 to 'set_current_peer' \(string expected, got boolean\) ./lib/ngx/balancer.lua:\d+: bad argument #3 to 'set_current_peer' \(string expected, got number\)} --- grep_error_log_out === TEST 9: set_current_peer: bad option 'pool_size' --- SKIP --- config location = /t { content_by_lua_block { local b = require "ngx.balancer" local values = { true, 0, -1 } for _, val in ipairs(values) do local pok, perr = pcall(b.set_current_peer, "127.0.0.1", 80, { pool = "foo", pool_size = val, }) if not pok then ngx.say(perr) end end } } --- response_body bad option 'pool_size' to 'set_current_peer' (number expected, got boolean) bad option 'pool_size' to 'set_current_peer' (expected > 0) bad option 'pool_size' to 'set_current_peer' (expected > 0) --- grep_error_log_out === TEST 10: enable_keepalive: bad usage (no upstream) --- config location = /t { content_by_lua_block { local b = require "ngx.balancer" local ok, err = b.enable_keepalive() if not ok then ngx.say(err) end } } --- response_body no upstream found --- grep_error_log_out === TEST 11: enable_keepalive: bad usage (bad context) --- http_upstream upstream test_upstream { server 127.0.0.1:$TEST_NGINX_SERVER_SSL_PORT; } --- config location = /t { proxy_pass https://test_upstream/; log_by_lua_block { local b = require "ngx.balancer" local ok, err = b.enable_keepalive() if not ok then ngx.log(ngx.NOTICE, err) end } } --- ignore_response_body --- grep_error_log_out --- error_log API disabled in the current context === TEST 12: enable_keepalive: bad usage (no current peer) --- http_upstream upstream test_upstream { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" local ok, err = b.enable_keepalive() if not ok then ngx.log(ngx.ERR, "failed to set keepalive: ", err) end local ok, err = b.set_current_peer("127.0.0.1", $TEST_NGINX_SERVER_SSL_PORT) if not ok then ngx.log(ngx.ERR, "failed to set current peer: ", err) return end } } --- config location = /t { echo_subrequest GET '/proxy/'; } --- response_body --- grep_error_log_out --- no_error_log --- error_log failed to set keepalive: no current peer set === TEST 13: enable_keepalive: bad argument #1 'idle_timeout' --- config location = /t { content_by_lua_block { local b = require "ngx.balancer" local values = { true, -1 } for _, val in ipairs(values) do local pok, perr = pcall(b.enable_keepalive, val) if not pok then ngx.say(perr) end end } } --- response_body bad argument #1 to 'enable_keepalive' (number expected, got boolean) bad argument #1 to 'enable_keepalive' (expected >= 0) --- grep_error_log_out === TEST 14: enable_keepalive: bad argument #2 'max_requests' --- config location = /t { content_by_lua_block { local b = require "ngx.balancer" local values = { true, -1 } for _, val in ipairs(values) do local pok, perr = pcall(b.enable_keepalive, nil, val) if not pok then ngx.say(perr) end end } } --- response_body bad argument #2 to 'enable_keepalive' (number expected, got boolean) bad argument #2 to 'enable_keepalive' (expected >= 0) --- grep_error_log_out === TEST 15: enable_keepalive: reaching 'max_requests > 0' closes keepalive connection (and frees empty pool) --- http_upstream upstream test_upstream { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" local ok, err = b.set_current_peer("127.0.0.1", $TEST_NGINX_SERVER_SSL_PORT) if not ok then ngx.log(ngx.ERR, "failed to set current peer: ", err) return end local ok, err = b.enable_keepalive(nil, 3) if not ok then ngx.log(ngx.ERR, "failed to set keepalive: ", err) return end } } --- config location = /t { set $requests_plan '/,/,/,/'; echo_foreach_split ',' $requests_plan; echo_subrequest GET '/proxy$echo_it'; echo_end; } --- response_body --- wait: 0.15 --- grep_error_log_out eval qr/^lua balancer: keepalive no free connection, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive saving connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive reusing connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive saving connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive reusing connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive not saving connection \S+ lua balancer: keepalive no free connection, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive saving connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: $/ === TEST 16: enable_keepalive: 'max_requests == 100' is the default value --- http_upstream upstream test_upstream { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" local ok, err = b.set_current_peer("127.0.0.1", $TEST_NGINX_SERVER_SSL_PORT) if not ok then ngx.log(ngx.ERR, "failed to set current peer: ", err) return end local ok, err = b.enable_keepalive() if not ok then ngx.log(ngx.ERR, "failed to set keepalive: ", err) return end } } --- config location = /t { content_by_lua_block { for i = 1, 100 do ngx.location.capture("/proxy/") end } } --- response_body --- grep_error_log_out eval qr/\Alua balancer: keepalive no free connection, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive saving connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s (lua balancer: keepalive reusing connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive saving connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s ){98}lua balancer: keepalive reusing connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive not saving connection \S+ \z/ === TEST 17: enable_keepalive: 'max_requests == 0' never closes upstream connections --- http_upstream upstream test_upstream { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" local ok, err = b.set_current_peer("127.0.0.1", $TEST_NGINX_SERVER_SSL_PORT) if not ok then ngx.log(ngx.ERR, "failed to set current peer: ", err) return end local ok, err = b.enable_keepalive(nil, 0) if not ok then ngx.log(ngx.ERR, "failed to set keepalive: ", err) return end } } --- config location = /t { content_by_lua_block { for i = 1, 100 do ngx.location.capture("/proxy/") end } } --- response_body --- grep_error_log: lua balancer: keepalive not saving connection --- grep_error_log_out === TEST 18: enable_keepalive: reaching 'idle_timeout > 0' closes keepalive connection (and frees empty pool) --- http_upstream upstream test_upstream { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" local ok, err = b.set_current_peer("127.0.0.1", $TEST_NGINX_SERVER_SSL_PORT) if not ok then ngx.log(ngx.ERR, "failed to set current peer: ", err) return end local ok, err = b.enable_keepalive(0.1) if not ok then ngx.log(ngx.ERR, "failed to set keepalive: ", err) return end } } --- config location = /t { echo_subrequest GET '/proxy/'; echo_sleep 0.15; echo_subrequest GET '/proxy/'; } --- response_body --- wait: 0.2 --- grep_error_log_out eval qr/^lua balancer: keepalive no free connection, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive saving connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive closing connection \S+ lua balancer: keepalive no free connection, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive saving connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive closing connection \S+$/ === TEST 19: enable_keepalive: reaching 'pool_size' closes extra connections --- http_upstream upstream test_upstream { server 0.0.0.1; balancer_keepalive 2; balancer_by_lua_block { local b = require "ngx.balancer" local ok, err = b.set_current_peer("127.0.0.1", $TEST_NGINX_SERVER_SSL_PORT) if not ok then ngx.log(ngx.ERR, "failed to set current peer: ", err) return end local ok, err = b.enable_keepalive() if not ok then ngx.log(ngx.ERR, "failed to set keepalive: ", err) return end } } --- config location = /t { echo_subrequest_async GET '/proxy/'; echo_subrequest_async GET '/proxy/'; echo_subrequest_async GET '/proxy/'; echo_sleep 0.3; echo_subrequest_async GET '/proxy/'; echo_subrequest_async GET '/proxy/'; echo_subrequest_async GET '/proxy/'; } --- response_body --- grep_error_log_out eval qr/^lua balancer: keepalive no free connection, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive no free connection, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive no free connection, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive saving connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive saving connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive closing connection \S+ lua balancer: keepalive saving connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive reusing connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive reusing connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive no free connection, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive saving connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive saving connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive closing connection \S+ lua balancer: keepalive saving connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: $/ === TEST 20: enable_keepalive: keepalive connections can be closed by upstream --- http_upstream upstream test_upstream { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" local ok, err = b.set_current_peer("127.0.0.1", $TEST_NGINX_SERVER_SSL_PORT) if not ok then ngx.log(ngx.ERR, "failed to set current peer: ", err) return end local ok, err = b.enable_keepalive() if not ok then ngx.log(ngx.ERR, "failed to set keepalive: ", err) return end } } --- config location = /t { echo_subrequest_async GET '/proxy/short_keepalive'; echo_subrequest_async GET '/proxy/short_keepalive'; } --- wait: 0.15 --- response_body --- grep_error_log_out eval qr/^lua balancer: keepalive no free connection, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive no free connection, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive saving connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive saving connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive closing connection \S+ lua balancer: keepalive closing connection \S+ $/ === TEST 21: enable_keepalive: does not save non-keepalive connections --- http_upstream upstream test_upstream { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" local ok, err = b.set_current_peer("127.0.0.1", $TEST_NGINX_SERVER_SSL_PORT) if not ok then ngx.log(ngx.ERR, "failed to set current peer: ", err) return end local ok, err = b.enable_keepalive() if not ok then ngx.log(ngx.ERR, "failed to set keepalive: ", err) return end } } --- config location = /t { echo_subrequest GET '/proxy/close'; echo_subrequest GET '/proxy/close'; } --- response_body --- grep_error_log_out eval qr/^lua balancer: keepalive no free connection, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive not saving connection \S+ lua balancer: keepalive no free connection, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive not saving connection \S+ $/ === TEST 22: enable_keepalive: does not save bad connections --- http_upstream upstream test_upstream { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" local ok, err = b.set_current_peer("127.0.0.3", $TEST_NGINX_SERVER_SSL_PORT) if not ok then ngx.log(ngx.ERR, "failed to set current peer: ", err) return end local ok, err = b.enable_keepalive() if not ok then ngx.log(ngx.ERR, "failed to set keepalive: ", err) return end } } --- config location = /t { echo_subrequest GET '/proxy/'; } --- response_body_like: 502 Bad Gateway --- no_error_log --- error_log eval qr/connect\(\) failed \(\d+: Connection refused\) while connecting to upstream/ --- grep_error_log_out eval qr/^lua balancer: keepalive no free connection, host: 127.0.0.3:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive not saving connection \S+$/ === TEST 23: enable_keepalive: does not save timed out connections --- http_upstream upstream test_upstream { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" local ok, err = b.set_current_peer("127.0.0.1", $TEST_NGINX_SERVER_SSL_PORT) if not ok then ngx.log(ngx.ERR, "failed to set current peer: ", err) return end local ok, err = b.set_timeouts(nil, nil, 0.1) if not ok then ngx.log(ngx.ERR, "failed to set timeouts: ", err) return end local ok, err = b.enable_keepalive() if not ok then ngx.log(ngx.ERR, "failed to set keepalive: ", err) return end } } --- config location = /t { echo_subrequest GET '/proxy/sleep'; } --- response_body_like: 504 Gateway Time-out --- no_error_log --- error_log upstream timed out --- grep_error_log_out eval qr/^lua balancer: keepalive no free connection, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive not saving connection \S+$/ === TEST 24: enable_keepalive: can be called again upon retry --- http_upstream upstream test_upstream { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" if not ngx.ctx.tries then ngx.ctx.tries = 0 else ngx.ctx.tries = ngx.ctx.tries + 1 end local ip = "127.0.0.3" local port = $TEST_NGINX_SERVER_SSL_PORT local pool_size = 1 if ngx.ctx.tries < 1 then local ok, err = b.set_more_tries(1) if not ok then ngx.log(ngx.ERR, "failed to set more tries: ", err) return end else ip = "127.0.0.1" pool_size = 2 end local ok, err = b.set_current_peer(ip, port) if not ok then ngx.log(ngx.ERR, "failed to set current peer: ", err) return end local ok, err = b.enable_keepalive() if not ok then ngx.log(ngx.ERR, "failed to set keepalive: ", err) return end } } --- config location = /t { echo_subrequest GET '/proxy/'; } --- response_body --- no_error_log [crit] --- grep_error_log_out eval qr/^lua balancer: keepalive no free connection, host: 127.0.0.3:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive not saving connection \S+ lua balancer: keepalive no free connection, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name:\s lua balancer: keepalive saving connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: $/ === TEST 25: enable_keepalive: must be called for each try --- http_upstream upstream test_upstream { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" local ip = "127.0.0.1" local port = $TEST_NGINX_SERVER_SSL_PORT if not ngx.ctx.tries then ngx.ctx.tries = 0 else ngx.ctx.tries = ngx.ctx.tries + 1 end if ngx.var.arg_sni == "one" and ngx.ctx.tries == 0 then ip = "127.0.0.3" local ok, err = b.set_more_tries(1) if not ok then ngx.log(ngx.ERR, "failed to set more tries: ", err) return end end local ok, err = b.set_current_peer(ip, port) if not ok then ngx.log(ngx.ERR, "failed to set current peer: ", err) return end if ngx.ctx.tries == 0 then local ok, err = b.enable_keepalive() if not ok then ngx.log(ngx.ERR, "failed to set keepalive: ", err) return end end } } --- config location = /t { echo_subrequest GET '/proxy/echo_sni' -q 'sni=one'; echo_subrequest GET '/proxy/echo_sni' -q 'sni=two'; } --- response_body SNI=one SNI=two --- no_error_log [crit] --- grep_error_log_out eval qr/^lua balancer: keepalive no free connection, host: 127.0.0.3:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: one lua balancer: keepalive not saving connection \S+ lua balancer: keepalive no free connection, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: two lua balancer: keepalive saving connection \S+, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: two $/ === TEST 26: enable_keepalive: bypasses previous 'keepalive' directive --- http_upstream upstream test_upstream { server 0.0.0.1; keepalive 10; balancer_by_lua_block { local b = require "ngx.balancer" local ok, err = b.set_current_peer("127.0.0.1", $TEST_NGINX_SERVER_SSL_PORT, { pool = ngx.var.arg_sni, }) if not ok then ngx.log(ngx.ERR, "failed to set current peer: ", err) return end local ok, err = b.enable_keepalive() if not ok then ngx.log(ngx.ERR, "failed to set keepalive: ", err) return end } } --- config location = /t { echo_subrequest GET '/proxy/echo_sni' -q 'sni=one'; echo_subrequest GET '/proxy/echo_sni' -q 'sni=two'; } --- response_body SNI=one SNI=two --- grep_error_log eval: qr/(?:lua balancer: keepalive .*|(?:get|free) keepalive peer)/ --- grep_error_log_out eval qr/^lua balancer: keepalive create pool, crc32: \S+, size: 30 lua balancer: keepalive no free connection, cpool: \S+ lua balancer: keepalive saving connection \S+, cpool: \S+, connections: 1 lua balancer: keepalive create pool, crc32: \d+, size: 30 lua balancer: keepalive no free connection, cpool: \S+ lua balancer: keepalive saving connection \S+, cpool: \S+, connections: 1$/ --- SKIP === TEST 27: enable_keepalive: is superseded by a subsequent 'keepalive' directive In this case, the upstream_keepalive_module pool gets queried but is always empty, as peers always get saved by the Lua pooling. --- http_upstream upstream test_upstream { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" local ok, err = b.set_current_peer("127.0.0.1", $TEST_NGINX_SERVER_SSL_PORT) if not ok then ngx.log(ngx.ERR, "failed to set current peer: ", err) return end local ok, err = b.enable_keepalive() if not ok then ngx.log(ngx.ERR, "failed to set keepalive: ", err) return end } keepalive 10; } --- config location = /t { echo_subrequest GET '/proxy/echo_sni' -q 'sni=one'; echo_subrequest GET '/proxy/echo_sni' -q 'sni=two'; } --- response_body SNI=one SNI=one --- grep_error_log eval: qr/(?:lua balancer: keepalive .*|(?:get|free) keepalive peer)/ --- grep_error_log_out eval qr/^get keepalive peer lua balancer: keepalive no free connection, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: one free keepalive peer free keepalive peer lua balancer: keepalive not saving connection \S+ get keepalive peer lua balancer: keepalive no free connection, host: 127.0.0.1:$ENV{TEST_NGINX_SERVER_SSL_PORT}, name: two get keepalive peer free keepalive peer free keepalive peer lua balancer: keepalive not saving connection \S+$/ lua-resty-core-0.1.31/t/balancer-timeout.t000066400000000000000000000220041474236722600203450ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: BEGIN { if (!defined $ENV{LD_PRELOAD}) { $ENV{LD_PRELOAD} = ''; } if ($ENV{LD_PRELOAD} !~ /\bmockeagain\.so\b/) { $ENV{LD_PRELOAD} = "mockeagain.so $ENV{LD_PRELOAD}"; } if (defined $ENV{MOCKEAGAIN} && $ENV{MOCKEAGAIN} eq 'r') { $ENV{MOCKEAGAIN} = 'rw'; } else { $ENV{MOCKEAGAIN} = 'w'; } $ENV{TEST_NGINX_EVENT_TYPE} = 'poll'; $ENV{TEST_NGINX_POSTPONE_OUTPUT} = 1; } use lib '.'; use t::TestCore; #worker_connections(1014); #master_on(); #workers(2); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 4); $ENV{TEST_NGINX_LUA_PACKAGE_PATH} = $t::TestCore::lua_package_path; #worker_connections(1024); #no_diff(); no_long_string(); run_tests(); __DATA__ === TEST 1: set_timeouts --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; upstream backend { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" assert(b.set_timeouts(1.234, 5.678, 7.689)) assert(b.set_current_peer("127.0.0.1", tonumber(ngx.var.server_port))) } } --- config location = /t { proxy_pass http://backend/back; } location = /back { echo "fake origin"; } --- request GET /t --- response_body fake origin --- grep_error_log eval: qr/event timer add: \d+: (?:1234|5678|7689):/ --- grep_error_log_out eval qr/\Aevent timer add: \d+: 1234: event timer add: \d+: 5678: event timer add: \d+: 7689: \z/ --- no_error_log [warn] === TEST 2: set_timeouts (nil connect timeout) --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; proxy_connect_timeout 1234ms; upstream backend { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" assert(b.set_timeouts(nil, 5.678, 7.689)) assert(b.set_current_peer("127.0.0.1", tonumber(ngx.var.server_port))) } } --- config location = /t { proxy_pass http://backend/back; } location = /back { echo "fake origin"; } --- request GET /t --- response_body fake origin --- grep_error_log eval: qr/event timer add: \d+: (?:1234|5678|7689):/ --- grep_error_log_out eval qr/\Aevent timer add: \d+: 1234: event timer add: \d+: 5678: event timer add: \d+: 7689: \z/ --- no_error_log [warn] === TEST 3: set_timeouts (nil send timeout) --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; proxy_send_timeout 5678ms; upstream backend { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" assert(b.set_timeouts(1.234, nil, 7.689)) assert(b.set_current_peer("127.0.0.1", tonumber(ngx.var.server_port))) } } --- config location = /t { proxy_pass http://backend/back; } location = /back { echo "fake origin"; } --- request GET /t --- response_body fake origin --- grep_error_log eval: qr/event timer add: \d+: (?:1234|5678|7689):/ --- grep_error_log_out eval qr/\Aevent timer add: \d+: 1234: event timer add: \d+: 5678: event timer add: \d+: 7689: \z/ --- no_error_log [warn] === TEST 4: set_timeouts (nil read timeout) --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; proxy_read_timeout 7689ms; upstream backend { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" assert(b.set_timeouts(1.234, 5.678, nil)) assert(b.set_current_peer("127.0.0.1", tonumber(ngx.var.server_port))) } } --- config location = /t { proxy_pass http://backend/back; } location = /back { echo "fake origin"; } --- request GET /t --- response_body fake origin --- grep_error_log eval: qr/event timer add: \d+: (?:1234|5678|7689):/ --- grep_error_log_out eval qr/\Aevent timer add: \d+: 1234: event timer add: \d+: 5678: event timer add: \d+: 7689: \z/ --- no_error_log [warn] === TEST 5: set connect timeout to 0 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; upstream backend { server 0.0.0.1; balancer_by_lua_block { print("hello from balancer by lua!") local b = require "ngx.balancer" assert(b.set_timeouts(0, 1.234, 5.678)) assert(b.set_current_peer("127.0.0.1", tonumber(ngx.var.server_port))) } } --- config location = /t { proxy_pass http://backend/back; } location = /back { echo "fake origin"; } --- request GET /t --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log eval qr/\[error\] .*? balancer_by_lua\(nginx.conf:\d+\):4: bad connect timeout/ --- no_error_log [warn] === TEST 6: set connect timeout to -1 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; upstream backend { server 0.0.0.1; balancer_by_lua_block { print("hello from balancer by lua!") local b = require "ngx.balancer" assert(b.set_timeouts(-1, 1.234, 5.678)) assert(b.set_current_peer("127.0.0.1", tonumber(ngx.var.server_port))) } } --- config location = /t { proxy_pass http://backend/back; } location = /back { echo "fake origin"; } --- request GET /t --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log eval qr/\[error\] .*? balancer_by_lua\(nginx.conf:\d+\):4: bad connect timeout/ --- no_error_log [warn] === TEST 7: set send timeout to 0 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; upstream backend { server 0.0.0.1; balancer_by_lua_block { print("hello from balancer by lua!") local b = require "ngx.balancer" assert(b.set_timeouts(1.234, 0, 5.678)) assert(b.set_current_peer("127.0.0.1", tonumber(ngx.var.server_port))) } } --- config location = /t { proxy_pass http://backend/back; } location = /back { echo "fake origin"; } --- request GET /t --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log eval qr/\[error\] .*? balancer_by_lua\(nginx.conf:\d+\):4: bad send timeout/ --- no_error_log [warn] === TEST 8: set send timeout to -1 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; upstream backend { server 0.0.0.1; balancer_by_lua_block { print("hello from balancer by lua!") local b = require "ngx.balancer" assert(b.set_timeouts(1.234, -1, 5.678)) assert(b.set_current_peer("127.0.0.1", tonumber(ngx.var.server_port))) } } --- config location = /t { proxy_pass http://backend/back; } location = /back { echo "fake origin"; } --- request GET /t --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log eval qr/\[error\] .*? balancer_by_lua\(nginx.conf:\d+\):4: bad send timeout/ --- no_error_log [warn] === TEST 9: set read timeout to -1 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; upstream backend { server 0.0.0.1; balancer_by_lua_block { print("hello from balancer by lua!") local b = require "ngx.balancer" assert(b.set_timeouts(1.234, 5.678, -1)) assert(b.set_current_peer("127.0.0.1", tonumber(ngx.var.server_port))) } } --- config location = /t { proxy_pass http://backend/back; } location = /back { echo "fake origin"; } --- request GET /t --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log eval qr/\[error\] .*? balancer_by_lua\(nginx.conf:\d+\):4: bad read timeout/ --- no_error_log [warn] === TEST 10: set_timeouts called in a wrong context --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; --- config location = /t { content_by_lua_block { local balancer = require "ngx.balancer" local ok, err = balancer.set_timeouts(1, 1, 1) if not ok then ngx.say("failed to call: ", err) return end ngx.say("unexpected success!") } } --- request GET /t --- response_body failed to call: no upstream found --- no_error_log [error] [alert] === TEST 11: set_timeouts called with a non-numerical parameter --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; upstream backend { server 0.0.0.1; balancer_by_lua_block { local balancer = require "ngx.balancer" local ok, err = balancer.set_timeouts("1.234", 1, 1) if not ok then ngx.log(ngx.ERR, "failed to call: ", err) end } } --- config location = /t { proxy_pass http://backend; } --- request GET /t --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log eval qr/\[error\] .*? bad connect timeout/ --- no_error_log [alert] lua-resty-core-0.1.31/t/balancer.t000066400000000000000000000575001474236722600166720ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(1014); #master_on(); #workers(2); #log_level('warn'); repeat_each(2); my $TestPlan = $ENV{TEST_NGINX_CHECK_LEAK} ? repeat_each() * (blocks() * 4 + 8) : repeat_each() * (blocks() * 4 + 6); plan tests => $TestPlan; $ENV{TEST_NGINX_LUA_PACKAGE_PATH} = "$t::TestCore::lua_package_path"; #worker_connections(1024); #no_diff(); no_long_string(); run_tests(); __DATA__ === TEST 1: set current peer (separate addr and port) --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; upstream backend { server 0.0.0.1; balancer_by_lua_block { print("hello from balancer by lua!") local b = require "ngx.balancer" assert(b.set_current_peer("127.0.0.3", 12345)) } } --- config location = /t { proxy_pass http://backend; } --- request GET /t --- response_body_like: 502 Bad Gateway --- error_code: 502 --- error_log eval [ '[lua] balancer_by_lua(nginx.conf:29):2: hello from balancer by lua! while connecting to upstream,', qr{connect\(\) failed .*?, upstream: "http://127\.0\.0\.3:12345/t"}, ] --- no_error_log [warn] === TEST 2: set current peer & next upstream (3 tries) --- skip_nginx: 4: < 1.7.5 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504 http_403 http_404; proxy_next_upstream_tries 10; upstream backend { server 0.0.0.1; balancer_by_lua_block { print("hello from balancer by lua!") local b = require "ngx.balancer" if not ngx.ctx.tries then ngx.ctx.tries = 0 end if ngx.ctx.tries < 2 then local ok, err = b.set_more_tries(1) if not ok then return error("failed to set more tries: ", err) elseif err then ngx.log(ngx.WARN, "set more tries: ", err) end end ngx.ctx.tries = ngx.ctx.tries + 1 assert(b.set_current_peer("127.0.0.3", 12345)) } } --- config location = /t { proxy_pass http://backend; } --- request GET /t --- response_body_like: 502 Bad Gateway --- error_code: 502 --- grep_error_log eval: qr{connect\(\) failed .*, upstream: "http://.*?"} --- grep_error_log_out eval qr#^(?:connect\(\) failed .*?, upstream: "http://127.0.0.3:12345/t"\n){3}$# --- no_error_log [warn] === TEST 3: set current peer & next upstream (no retries) --- skip_nginx: 4: < 1.7.5 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504 http_403 http_404; upstream backend { server 0.0.0.1; balancer_by_lua_block { print("hello from balancer by lua!") local b = require "ngx.balancer" if not ngx.ctx.tries then ngx.ctx.tries = 0 end ngx.ctx.tries = ngx.ctx.tries + 1 assert(b.set_current_peer("127.0.0.3", 12345)) } } --- config location = /t { proxy_pass http://backend; } --- request GET /t --- response_body_like: 502 Bad Gateway --- error_code: 502 --- grep_error_log eval: qr{connect\(\) failed .*, upstream: "http://.*?"} --- grep_error_log_out eval qr#^(?:connect\(\) failed .*?, upstream: "http://127.0.0.3:12345/t"\n){1}$# --- no_error_log [warn] === TEST 4: set current peer & next upstream (3 tries exceeding the limit) --- skip_nginx: 4: < 1.7.5 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504 http_403 http_404; proxy_next_upstream_tries 2; upstream backend { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" if not ngx.ctx.tries then ngx.ctx.tries = 0 end if ngx.ctx.tries < 2 then local ok, err = b.set_more_tries(1) if not ok then return error("failed to set more tries: ", err) elseif err then ngx.log(ngx.WARN, "set more tries: ", err) end end ngx.ctx.tries = ngx.ctx.tries + 1 assert(b.set_current_peer("127.0.0.3", 12345)) } } --- config location = /t { proxy_pass http://backend; } --- request GET /t --- response_body_like: 502 Bad Gateway --- error_code: 502 --- grep_error_log eval: qr{connect\(\) failed .*, upstream: "http://.*?"} --- grep_error_log_out eval qr#^(?:connect\(\) failed .*?, upstream: "http://127.0.0.3:12345/t"\n){2}$# --- error_log set more tries: reduced tries due to limit === TEST 5: get last peer failure status (404) --- skip_nginx: 4: < 1.7.5 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504 http_403 http_404; proxy_next_upstream_tries 10; upstream backend { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" local state, status = b.get_last_failure() print("last peer failure: ", state, " ", status) if not ngx.ctx.tries then ngx.ctx.tries = 0 end if ngx.ctx.tries < 2 then local ok, err = b.set_more_tries(1) if not ok then return error("failed to set more tries: ", err) elseif err then ngx.log(ngx.WARN, "set more tries: ", err) end end ngx.ctx.tries = ngx.ctx.tries + 1 assert(b.set_current_peer("127.0.0.1", tonumber(ngx.var.server_port))) } } --- config location = /t { proxy_pass http://backend/back; } location = /back { return 404; } --- request GET /t --- response_body_like: 404 Not Found --- error_code: 404 --- grep_error_log eval: qr{last peer failure: \S+ \S+} --- grep_error_log_out last peer failure: nil nil last peer failure: next 404 last peer failure: next 404 --- no_error_log [warn] === TEST 6: get last peer failure status (500) --- skip_nginx: 4: < 1.7.5 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504 http_403 http_404; proxy_next_upstream_tries 10; upstream backend { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" local state, status = b.get_last_failure() print("last peer failure: ", state, " ", status) if not ngx.ctx.tries then ngx.ctx.tries = 0 end if ngx.ctx.tries < 2 then local ok, err = b.set_more_tries(1) if not ok then return error("failed to set more tries: ", err) elseif err then ngx.log(ngx.WARN, "set more tries: ", err) end end ngx.ctx.tries = ngx.ctx.tries + 1 assert(b.set_current_peer("127.0.0.1", tonumber(ngx.var.server_port))) } } --- config location = /t { proxy_pass http://backend/back; } location = /back { return 500; } --- request GET /t --- response_body_like: 500 Internal Server Error --- error_code: 500 --- grep_error_log eval: qr{last peer failure: \S+ \S+} --- grep_error_log_out last peer failure: nil nil last peer failure: failed 500 last peer failure: failed 500 --- no_error_log [warn] === TEST 7: get last peer failure status (503) --- skip_nginx: 4: < 1.7.5 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504 http_403 http_404; proxy_next_upstream_tries 10; upstream backend { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" local state, status = b.get_last_failure() print("last peer failure: ", state, " ", status) if not ngx.ctx.tries then ngx.ctx.tries = 0 end if ngx.ctx.tries < 2 then local ok, err = b.set_more_tries(1) if not ok then return error("failed to set more tries: ", err) elseif err then ngx.log(ngx.WARN, "set more tries: ", err) end end ngx.ctx.tries = ngx.ctx.tries + 1 assert(b.set_current_peer("127.0.0.1", tonumber(ngx.var.server_port))) } } --- config location = /t { proxy_pass http://backend/back; } location = /back { return 503; } --- request GET /t --- response_body_like: 503 Service Temporarily Unavailable --- error_code: 503 --- grep_error_log eval: qr{last peer failure: \S+ \S+} --- grep_error_log_out eval qr{\Alast peer failure: nil nil last peer failure: failed 50[23] last peer failure: failed 50[23] \z} --- no_error_log [warn] === TEST 8: get last peer failure status (connect failed) --- skip_nginx: 4: < 1.7.5 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504 http_403 http_404; proxy_next_upstream_tries 10; upstream backend { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" local state, status = b.get_last_failure() print("last peer failure: ", state, " ", status) if not ngx.ctx.tries then ngx.ctx.tries = 0 end if ngx.ctx.tries < 2 then local ok, err = b.set_more_tries(1) if not ok then return error("failed to set more tries: ", err) elseif err then ngx.log(ngx.WARN, "set more tries: ", err) end end ngx.ctx.tries = ngx.ctx.tries + 1 assert(b.set_current_peer("127.0.0.3", 12345)) } } --- config location = /t { proxy_pass http://backend/back; } location = /back { return 404; } --- request GET /t --- response_body_like: 502 Bad Gateway --- error_code: 502 --- grep_error_log eval: qr{last peer failure: \S+ \S+} --- grep_error_log_out last peer failure: nil nil last peer failure: failed 502 last peer failure: failed 502 --- no_error_log [warn] === TEST 9: set current peer (port embedded in addr) --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; upstream backend { server 0.0.0.1; balancer_by_lua_block { print("hello from balancer by lua!") local b = require "ngx.balancer" assert(b.set_current_peer("127.0.0.3:12345")) } } --- config location = /t { proxy_pass http://backend; } --- request GET /t --- response_body_like: 502 Bad Gateway --- error_code: 502 --- error_log eval [ '[lua] balancer_by_lua(nginx.conf:29):2: hello from balancer by lua! while connecting to upstream,', qr{connect\(\) failed .*?, upstream: "http://127\.0\.0\.3:12345/t"}, ] --- no_error_log [warn] === TEST 10: keepalive before balancer --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; upstream backend { server 0.0.0.1; keepalive 10; balancer_by_lua_block { print("hello from balancer by lua!") local b = require "ngx.balancer" assert(b.set_current_peer("127.0.0.3:12345")) } } --- config location = /t { proxy_pass http://backend; } --- request GET /t --- response_body_like: 502 Bad Gateway --- grep_error_log eval: qr/load balancing method redefined in/ --- grep_error_log_out eval [ "load balancing method redefined in ", "", ] --- error_code: 502 --- error_log eval [ '[lua] balancer_by_lua(nginx.conf:30):2: hello from balancer by lua! while connecting to upstream,', qr{connect\(\) failed .*?, upstream: "http://127\.0\.0\.3:12345/t"}, ] --- no_error_log [crit] === TEST 11: keepalive after balancer --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; upstream backend { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" assert(b.set_current_peer("127.0.0.1", tonumber(ngx.var.server_port))) } keepalive 1; } --- config location = /t { content_by_lua_block { local res0 = ngx.location.capture("/tt") local res1 = ngx.location.capture("/tt") local res2 = ngx.location.capture("/tt") if res2.status == ngx.HTTP_OK then ngx.print(res2.body) end } } location = /tt { proxy_pass http://backend/back; proxy_http_version 1.1; proxy_set_header Connection ""; } location = /back { echo "hello keepalive!"; } --- request GET /t --- response_body hello keepalive! --- error_code: 200 --- grep_error_log eval: qr{\S+ keepalive peer:.*?connection} --- grep_error_log_out eval ["free keepalive peer: saving connection get keepalive peer: using connection free keepalive peer: saving connection get keepalive peer: using connection free keepalive peer: saving connection ", "get keepalive peer: using connection free keepalive peer: saving connection get keepalive peer: using connection free keepalive peer: saving connection get keepalive peer: using connection free keepalive peer: saving connection ", ] --- no_error_log [warn] === TEST 12: set_current_peer called in a wrong context --- wait: 0.2 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; upstream backend { server 127.0.0.1:$TEST_NGINX_SERVER_PORT; balancer_by_lua_block { print("hello from balancer by lua!") } } --- config location = /fake { echo ok; } location = /t { proxy_pass http://backend/fake; log_by_lua_block { local balancer = require "ngx.balancer" local ok, err = balancer.set_current_peer("127.0.0.1", 1234) if not ok then ngx.log(ngx.ERR, "failed to call: ", err) return end ngx.log(ngx.ALERT, "unexpected success") } } --- request GET /t --- response_body ok --- error_log eval qr/\[error\] .*? log_by_lua.*? failed to call: API disabled in the current context/ --- no_error_log [alert] === TEST 13: get_last_failure called in a wrong context --- wait: 0.2 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; upstream backend { server 127.0.0.1:$TEST_NGINX_SERVER_PORT; balancer_by_lua_block { print("hello from balancer by lua!") } } --- config location = /fake { echo ok; } location = /t { proxy_pass http://backend/fake; log_by_lua_block { local balancer = require "ngx.balancer" local state, status, err = balancer.get_last_failure() if not state and err then ngx.log(ngx.ERR, "failed to call: ", err) return end ngx.log(ngx.ALERT, "unexpected success") } } --- request GET /t --- response_body ok --- error_log eval qr/\[error\] .*? log_by_lua.*? failed to call: API disabled in the current context/ --- no_error_log [alert] === TEST 14: set_more_tries called in a wrong context --- wait: 0.2 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; upstream backend { server 127.0.0.1:$TEST_NGINX_SERVER_PORT; balancer_by_lua_block { print("hello from balancer by lua!") } } --- config location = /fake { echo ok; } location = /t { proxy_pass http://backend/fake; log_by_lua_block { local balancer = require "ngx.balancer" local ok, err = balancer.set_more_tries(1) if not ok then ngx.log(ngx.ERR, "failed to call: ", err) return end ngx.log(ngx.ALERT, "unexpected success") } } --- request GET /t --- response_body ok --- error_log eval qr/\[error\] .*? log_by_lua.*? failed to call: API disabled in the current context/ --- no_error_log [alert] === TEST 15: hot loop when proxy_upstream_next error is hit and keepalive is used. github issue openresty/lua-nginx-module#693 --- skip_nginx: 4: < 1.7.5 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; upstream backend { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" print("hello from balancer by lua!") assert(b.set_current_peer("127.0.0.1", $TEST_NGINX_SERVER_PORT)) } keepalive 1; } --- config location /t { rewrite ^/t(.*) $1 break; proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Connection ""; } location = /back { return 200; } location = /main { echo_location /t/back; echo_location /t/bad; } location = /bad { content_by_lua_block { ngx.exit(444) } } --- request GET /main --- no_error_log [alert] --- ignore_response --- grep_error_log eval: qr{hello from balancer by lua!} --- grep_error_log_out hello from balancer by lua! hello from balancer by lua! --- error_log eval qr/\[error] .*? upstream prematurely closed connection while reading response header from upstream/ === TEST 16: https (keepalive) --- skip_nginx: 5: < 1.7.5 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; upstream backend { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" print("hello from balancer by lua!") assert(b.set_current_peer("127.0.0.1", $TEST_NGINX_RAND_PORT_1)) } keepalive 1; } server { listen $TEST_NGINX_RAND_PORT_1 ssl; ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location = /back { return 200 "ok"; } } --- config location /t { proxy_pass https://backend/back; proxy_http_version 1.1; proxy_set_header Connection ""; } --- request GET /t --- no_error_log [alert] [error] --- response_body chomp ok --- grep_error_log eval: qr{hello from balancer by lua!} --- grep_error_log_out hello from balancer by lua! --- no_check_leak === TEST 17: https (no keepalive) --- skip_nginx: 5: < 1.7.5 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; upstream backend { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" print("hello from balancer by lua!") assert(b.set_current_peer("127.0.0.1", $TEST_NGINX_RAND_PORT_2)) } } server { listen $TEST_NGINX_RAND_PORT_2 ssl; ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location = /back { return 200 "ok"; } } --- config location /t { proxy_pass https://backend/back; proxy_http_version 1.1; proxy_set_header Connection ""; } --- request GET /t --- no_error_log [alert] [error] --- response_body chomp ok --- grep_error_log eval: qr{hello from balancer by lua!} --- grep_error_log_out hello from balancer by lua! --- no_check_leak === TEST 18: test ngx.var.upstream_addr after using more than one set_current_peer --- wait: 0.2 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; proxy_next_upstream_tries 3; upstream backend { server 127.0.0.1:$TEST_NGINX_SERVER_PORT; balancer_by_lua_block { local balancer = require "ngx.balancer" if ngx.ctx.tries == nil then balancer.set_more_tries(1) ngx.ctx.tries = 1 balancer.set_current_peer("127.0.0.3", 12345) else balancer.set_current_peer("127.0.0.3", 12346) end } } --- config location = /t { proxy_pass http://backend; log_by_lua_block { ngx.log(ngx.INFO, "ngx.var.upstream_addr is " .. ngx.var.upstream_addr) } } --- request GET /t --- response_body_like: 502 Bad Gateway --- error_code: 502 --- error_log eval qr/log_by_lua\(nginx.conf:\d+\):\d+: ngx.var.upstream_addr is 127.0.0.3:12345, 127.0.0.3:12346/ --- no_error_log [alert] === TEST 19: no 'server' directive --- http_config upstream backend { balancer_by_lua_block { print("hello from balancer by lua!") } } --- config location = /t { proxy_pass http://backend; } --- request GET /t --- error_code: 500 --- ignore_response_body --- error_log eval [ '[lua] balancer_by_lua(nginx.conf:26):2: hello from balancer by lua! while connecting to upstream,', qr/\[error\] .*? lua balancer: no peer set/, ] --- no_error_log [warn] === TEST 20: set current peer: no 'server' directive --- http_config upstream backend { balancer_by_lua_block { print("hello from balancer by lua!") local b = require "ngx.balancer" assert(b.set_current_peer("127.0.0.3", 12345)) } } --- config location = /t { proxy_pass http://backend; } --- request GET /t --- error_code: 502 --- ignore_response_body --- error_log eval [ '[lua] balancer_by_lua(nginx.conf:26):2: hello from balancer by lua! while connecting to upstream,', qr{connect\(\) failed .*?, upstream: "http://127\.0\.0\.3:12345/t"}, ] --- no_error_log [warn] [crit] === TEST 21: set_upstream_tls off --- skip_nginx: 5: < 1.7.5 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; upstream backend { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" b.set_current_peer("127.0.0.1", tonumber(ngx.var.server_port)) b.set_upstream_tls(false) } keepalive 1; } server { listen $TEST_NGINX_RAND_PORT_1 ssl; ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location = /back { return 200 "ok"; } } --- config location /t { proxy_pass https://backend/back; proxy_http_version 1.1; proxy_set_header Connection ""; } location /back { echo "Hello world!"; } --- request GET /t --- no_error_log [alert] [error] --- response_body Hello world! --- no_check_leak === TEST 22: set_upstream_tls on --- skip_nginx: 5: < 1.7.5 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; upstream backend { server 0.0.0.1; balancer_by_lua_block { local b = require "ngx.balancer" b.set_current_peer("127.0.0.1", $TEST_NGINX_RAND_PORT_1) b.set_upstream_tls(false) b.set_upstream_tls(true) } keepalive 1; } server { listen $TEST_NGINX_RAND_PORT_1 ssl; ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location = /back { return 200 "ok"; } } --- config location /t { proxy_pass https://backend/back; proxy_http_version 1.1; proxy_set_header Connection ""; } location /back { echo "Hello world!"; } --- request GET /t --- no_error_log [alert] [error] --- response_body chomp ok --- no_check_leak lua-resty-core-0.1.31/t/cert/000077500000000000000000000000001474236722600156645ustar00rootroot00000000000000lua-resty-core-0.1.31/t/cert/chain/000077500000000000000000000000001474236722600167465ustar00rootroot00000000000000lua-resty-core-0.1.31/t/cert/chain/chain-bad0.pem000066400000000000000000000045751474236722600213520ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIICijCCAfOgAwIBAgICEAQwDQYJKoZIhvcNAQEFBQAwTTELMAkGA1UEBhMCVVMx EzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAoMCU9wZW5SZXN0eTEVMBMGA1UE AwwMU2lnbmluZy1DQS0yMCAXDTE0MDkyMDA1Mjc0NloYDzIxMTQwODI3MDUyNzQ2 WjBJMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UECgwJ T3BlblJlc3R5MREwDwYDVQQDDAh0ZXN0LmNvbTCBnzANBgkqhkiG9w0BAQEFAAOB jQAwgYkCgYEA2FOsrFw/+YColkuwWNtaht7KMALZGcj2FMVAyUHru3rR4fmWO1TV 6L+sUFpJEdqZYETgJWhANnz2zrScuVjW6udEmGPronL46Wm0Sk1ohkHKZ1hh5nDo CP6twnVZJA7wLxpwg4yjd2ToTdXFKGKpU9GhIvU2Q6dGAKqXVHLUckcCAwEAAaN7 MHkwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYBAD=BAD=BAD= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICdjCCAd+gAwIBAgICEAIwDQYJKoZIhvcNAQEFBQAwYDELMAkGA1UEBhMCVVMx EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xEjAQ BgNVBAoMCU9wZW5SZXN0eTEQMA4GA1UEAwwHUm9vdCBDQTAgFw0xNDA5MjAwNTA5 MDVaGA8yMTE0MDgyNzA1MDkwNVowTTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNh bGlmb3JuaWExEjAQBgNVBAoMCU9wZW5SZXN0eTEVMBMGA1UEAwwMU2lnbmluZy1D QS0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5mj22Md22ivGfYSV5cPbq S2oPDHLqRfxNUc/1cYiUnPkEQJn9LRcVOt5fcEoGeRP7gUmt2llEEoF0ndgZPk7o xwDu+ZaBer8J5oiw47LoyuNyI+SGg0HKs0nA9XaK17X8oxIbKwu0VxAkl0C+yxfn xd6TG1mU/zQ/zU0UdgkO8wIDAQABo1AwTjAdBgNVHQ4EFgQUEleOLJvKyY34iLFN 7qZt85nDr+EwHwYDVR0jBBgwFoAUVmXJi2VVJy6rFPAmRr27nqErQVgwDAYDVR0T BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQAe+28+Er1FEVlS1WD/fHOeMs52+gu2 Slho25KkoNJjJCecasVs+oTUtYCTsHmPM8YGmUmBmfRSur3/bvVpP2XgWVHOFmYv ObUx/xgqpI4Ud3uiLFRL8KUsgxLE1RxKX3sxJu1jutWD4rUdw/M0oLrd7ofucHGu G8WXmwimnK3Awg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICYzCCAcygAwIBAgICEAMwDQYJKoZIhvcNAQEFBQAwTTELMAkGA1UEBhMCVVMx EzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAoMCU9wZW5SZXN0eTEVMBMGA1UE AwwMU2lnbmluZy1DQS0xMCAXDTE0MDkyMDA1MjUwNFoYDzIxMTQwODI3MDUyNTA0 WjBNMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UECgwJ T3BlblJlc3R5MRUwEwYDVQQDDAxTaWduaW5nLUNBLTIwgZ8wDQYJKoZIhvcNAQEB BQADgY0AMIGJAoGBAKTQrhaoj50s7hL1DF4pZZvMm2dvQCTXRP/U3o3UNhzhNyvf /2k1bQtPrpoW56nGJNOOpMMvJdjzZnOOhI6cpsf5zoy3nWAmhUyP9EMXr52UGvUh exwrnO7+Ssptx8/uKgIoH24TlIU/UKMDGL1s+bWdN7knYSl10zl3XoNBqowhAgMB AAGjUDBOMB0GA1UdDgQWBBQ5d3ejTpKL4iUgcmQ1CnqHqFip+DAfBgNVHSMEGDAW gBQSV44sm8rJjfiIsU3upm3zmcOv4TAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB BQUAA4GBADtLtjFRcprvQmBemGBx1yZKRvEOHwi+5htf4v0oVI2xxQlvBMtp3Dle Z+CRnxCUvDWQSmX+WL3pnRjwssQsbgUApGNZaoXPDig6rTQcHowIz6x5GOYrFkmc CwlmUClTeASePSdAxAxy1ozWsZz18viMnAsN4Uub7MllDB7+JweW -----END CERTIFICATE----- lua-resty-core-0.1.31/t/cert/chain/chain-bad2.pem000066400000000000000000000042061474236722600213430ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIICijCCAfOgAwIBAgICEAQwDQYJKoZIhvcNAQEFBQAwTTELMAkGA1UEBhMCVVMx EzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAoMCU9wZW5SZXN0eTEVMBMGA1UE AwwMU2lnbmluZy1DQS0yMCAXDTE0MDkyMDA1Mjc0NloYDzIxMTQwODI3MDUyNzQ2 WjBJMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UECgwJ T3BlblJlc3R5MREwDwYDVQQDDAh0ZXN0LmNvbTCBnzANBgkqhkiG9w0BAQEFAAOB jQAwgYkCgYEA2FOsrFw/+YColkuwWNtaht7KMALZGcj2FMVAyUHru3rR4fmWO1TV 6L+sUFpJEdqZYETgJWhANnz2zrScuVjW6udEmGPronL46Wm0Sk1ohkHKZ1hh5nDo CP6twnVZJA7wLxpwg4yjd2ToTdXFKGKpU9GhIvU2Q6dGAKqXVHLUckcCAwEAAaN7 MHkwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQg Q2VydGlmaWNhdGUwHQYDVR0OBBYEFB/bwNk8S3eomqwzH3twxM+6yAfdMB8GA1Ud IwQYMBaAFDl3d6NOkoviJSByZDUKeoeoWKn4MA0GCSqGSIb3DQEBBQUAA4GBAB7N g2ax2+pcN368MURScgOum0QgLK0AIKXcz53IyI/fzyQmnEOD9NL/69nkfSXPH7iq Y1gDudpSQvj+LnHMj94mNM3aXHo7ZAcYJ6FhtlgylhCX8n8AxERDt53iMWlPwpXF ozLRwADG71i5D+YIOg3JwBT3JoxDE1Ubk3Fyx60v -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICdjCCAd+gAwIBAgICEAIwDQYJKoZIhvcNAQEFBQAwYDELMAkGA1UEBhMCVVMx EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xEjAQ BgNVBAoMCU9wZW5SZXN0eTEQMA4GA1UEAwwHUm9vdCBDQTAgFw0xNDA5MjAwNTA5 MDVaGA8yMTE0MDgyNzA1MDkwNVowTTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNh bGlmb3JuaWExEjAQBgNVBAoMCU9wZW5SZXN0eTEVMBMGA1UEAwwMU2lnbmluZy1D QS0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5mj22Md22ivGfYSV5cPbq S2oPDHLqRfxNUc/1cYiUnPkEQJn9LRcVOt5fcEoGeRP7gUmt2llEEoF0ndgZPk7o xwDu+ZaBer8J5oiw47LoyuNyI+SGg0HKs0nA9XaK17X8oxIbKwu0VxAkl0C+yxfn xd6TG1mU/zQ/zU0UdgkO8wIDAQABo1AwTjAdBgNVHQ4EFgQUEleOLJvKyY34iLFN 7qZt85nDr+EwHwYDVR0jBBgwFoAUVmXJi2VVJy6rFPAmRr27nqErQVgwDAYDVR0T BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQAe+28+Er1FEVlS1WD/fHOeMs52+gu2 Slho25KkoNJjJCecasVs+oTUtYCTsHmPM8YGmUmBmfRSur3/bvVpP2XgWVHOFmYv ObUx/xgqpI4Ud3uiLFRL8KUsgxLE1RxKX3sxJu1jutWD4rUdw/M0oLrd7ofucHGu G8WXmwimnK3Awg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICYzCCAcygAwIBAgICEAMwDQYJKoZIhvcNAQEFBQAwTTELMAkGA1UEBhMCVVMx EzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAoMCU9wZW5SZXN0eTEVMBMGA1UE AwwMU2lnbmluZy1DQS0xMCAXDTE0MDkyMDA1MjUwNFoYDzIxMTQwODI3MDUyNTA0 WjBNMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UECgwJ BAD=BAD=BAD -----END CERTIFICATE----- lua-resty-core-0.1.31/t/cert/chain/chain.der000066400000000000000000000035571474236722600205360ustar00rootroot00000000000000000  *H 0M1 0 UUS10U California10U OpenResty10U Signing-CA-20  140920052746Z21140827052746Z0I1 0 UUS10U California10U OpenResty10U test.com00  *H 0S\?KXZ0@Az;T迬PZIڙ`D%h@6|δXDcriJMhAgXapuY$/pwdM(bSѡ"6CFTrrG{0y0 U00, `HB OpenSSL Generated Certificate0UNz 戰r#䆃AʳIv׵+ W$@ޓY4?Mv P0N0UW,ɍMmï0U#0VeɋeU'.&F+AX0 U00  *H o>EYR`|s2v JXhےc$'jlԵy3IRni?eYQf/91*w{,TK,J_{1&cՃ4pqŗlua-resty-core-0.1.31/t/cert/chain/chain.pem000066400000000000000000000052671474236722600205450ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIICijCCAfOgAwIBAgICEAQwDQYJKoZIhvcNAQEFBQAwTTELMAkGA1UEBhMCVVMx EzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAoMCU9wZW5SZXN0eTEVMBMGA1UE AwwMU2lnbmluZy1DQS0yMCAXDTE0MDkyMDA1Mjc0NloYDzIxMTQwODI3MDUyNzQ2 WjBJMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UECgwJ T3BlblJlc3R5MREwDwYDVQQDDAh0ZXN0LmNvbTCBnzANBgkqhkiG9w0BAQEFAAOB jQAwgYkCgYEA2FOsrFw/+YColkuwWNtaht7KMALZGcj2FMVAyUHru3rR4fmWO1TV 6L+sUFpJEdqZYETgJWhANnz2zrScuVjW6udEmGPronL46Wm0Sk1ohkHKZ1hh5nDo CP6twnVZJA7wLxpwg4yjd2ToTdXFKGKpU9GhIvU2Q6dGAKqXVHLUckcCAwEAAaN7 MHkwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQg Q2VydGlmaWNhdGUwHQYDVR0OBBYEFB/bwNk8S3eomqwzH3twxM+6yAfdMB8GA1Ud IwQYMBaAFDl3d6NOkoviJSByZDUKeoeoWKn4MA0GCSqGSIb3DQEBBQUAA4GBAB7N g2ax2+pcN368MURScgOum0QgLK0AIKXcz53IyI/fzyQmnEOD9NL/69nkfSXPH7iq Y1gDudpSQvj+LnHMj94mNM3aXHo7ZAcYJ6FhtlgylhCX8n8AxERDt53iMWlPwpXF ozLRwADG71i5D+YIOg3JwBT3JoxDE1Ubk3Fyx60v -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICdjCCAd+gAwIBAgICEAIwDQYJKoZIhvcNAQEFBQAwYDELMAkGA1UEBhMCVVMx EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xEjAQ BgNVBAoMCU9wZW5SZXN0eTEQMA4GA1UEAwwHUm9vdCBDQTAgFw0xNDA5MjAwNTA5 MDVaGA8yMTE0MDgyNzA1MDkwNVowTTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNh bGlmb3JuaWExEjAQBgNVBAoMCU9wZW5SZXN0eTEVMBMGA1UEAwwMU2lnbmluZy1D QS0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5mj22Md22ivGfYSV5cPbq S2oPDHLqRfxNUc/1cYiUnPkEQJn9LRcVOt5fcEoGeRP7gUmt2llEEoF0ndgZPk7o xwDu+ZaBer8J5oiw47LoyuNyI+SGg0HKs0nA9XaK17X8oxIbKwu0VxAkl0C+yxfn xd6TG1mU/zQ/zU0UdgkO8wIDAQABo1AwTjAdBgNVHQ4EFgQUEleOLJvKyY34iLFN 7qZt85nDr+EwHwYDVR0jBBgwFoAUVmXJi2VVJy6rFPAmRr27nqErQVgwDAYDVR0T BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQAe+28+Er1FEVlS1WD/fHOeMs52+gu2 Slho25KkoNJjJCecasVs+oTUtYCTsHmPM8YGmUmBmfRSur3/bvVpP2XgWVHOFmYv ObUx/xgqpI4Ud3uiLFRL8KUsgxLE1RxKX3sxJu1jutWD4rUdw/M0oLrd7ofucHGu G8WXmwimnK3Awg== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIICYzCCAcygAwIBAgICEAMwDQYJKoZIhvcNAQEFBQAwTTELMAkGA1UEBhMCVVMx EzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAoMCU9wZW5SZXN0eTEVMBMGA1UE AwwMU2lnbmluZy1DQS0xMCAXDTE0MDkyMDA1MjUwNFoYDzIxMTQwODI3MDUyNTA0 WjBNMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UECgwJ T3BlblJlc3R5MRUwEwYDVQQDDAxTaWduaW5nLUNBLTIwgZ8wDQYJKoZIhvcNAQEB BQADgY0AMIGJAoGBAKTQrhaoj50s7hL1DF4pZZvMm2dvQCTXRP/U3o3UNhzhNyvf /2k1bQtPrpoW56nGJNOOpMMvJdjzZnOOhI6cpsf5zoy3nWAmhUyP9EMXr52UGvUh exwrnO7+Ssptx8/uKgIoH24TlIU/UKMDGL1s+bWdN7knYSl10zl3XoNBqowhAgMB AAGjUDBOMB0GA1UdDgQWBBQ5d3ejTpKL4iUgcmQ1CnqHqFip+DAfBgNVHSMEGDAW gBQSV44sm8rJjfiIsU3upm3zmcOv4TAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEB BQUAA4GBADtLtjFRcprvQmBemGBx1yZKRvEOHwi+5htf4v0oVI2xxQlvBMtp3Dle Z+CRnxCUvDWQSmX+WL3pnRjwssQsbgUApGNZaoXPDig6rTQcHowIz6x5GOYrFkmc CwlmUClTeASePSdAxAxy1ozWsZz18viMnAsN4Uub7MllDB7+JweW -----END CERTIFICATE----- lua-resty-core-0.1.31/t/cert/chain/root-ca.crt000066400000000000000000000016641474236722600210330ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIICkDCCAfmgAwIBAgIJAK3s1yAQ5tdfMA0GCSqGSIb3DQEBBQUAMGAxCzAJBgNV BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNp c2NvMRIwEAYDVQQKDAlPcGVuUmVzdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwIBcNMTQw OTIwMDM1NTU0WhgPMjExNDA4MjcwMzU1NTRaMGAxCzAJBgNVBAYTAlVTMRMwEQYD VQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMRIwEAYDVQQK DAlPcGVuUmVzdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQAD gY0AMIGJAoGBAN7CcpCjiafBdl1KaExRcuutAF0/eq4/ht7L4/i0nPDzikscFJ/O aVyH3UpUF/KMq+72vom2bEbUeRROr1rL/JRe9raGlQtvdovHZt6f4c3/Coihtupp 9BXYrBCU4P+Bxai5gtTXGFvLC2a72qKcXDNeH+NxpIaemfPxSvemCYUXAgMBAAGj UDBOMB0GA1UdDgQWBBRWZcmLZVUnLqsU8CZGvbueoStBWDAfBgNVHSMEGDAWgBRW ZcmLZVUnLqsU8CZGvbueoStBWDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUA A4GBAGjMH6qkY+61311DERFhDuYzMSSZjH53qzFseq/chlIMGjrgJIMy6rl7T0AU 2hjvW+FOyhf5NqRrAQDTTuLbtXZ/ygiUformE8lR/SNRY/DVj1yarQkWUC5UpqOs GWG1VW9DHQAMFVkYwPO3XKeTXpEFOxPLHtXBYcVemCT4zo42 -----END CERTIFICATE----- lua-resty-core-0.1.31/t/cert/chain/test-com-bad.key.pem000066400000000000000000000007211474236722600225170ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQDYU6ysXD/5gKiWS7BY21qG3sowAtkZyPYUxUDJQeu7etHh+ZY7 VNXov6xQWkkR2plgROAlaEA2fPbOtJy5WNbq50SYY+uicvjpabRKTWiGQcpnWGHm cOgI/q3CdVkkDvAvGnCDjKN3ZOhN1cUoYqlT0aEi9TZDp0YAqpdUctRyRwIDAQAB AoGBAIl/5elIWYGFPaMKSPSxuECxq2II7WVuTru1BRDnTabE0lMICW185tohuqz4 NimbAJIoNTCRqv73Pwjz1AobZb6Nm7TDaahhstak6IlTYKcjXVBuM/UU4G13Kz/f hNVblv2cCn9CkeTNOvPZjYJXw/c4XlHasjDMMh8S83Q9095BAkEA+6oPzEiSsdo5 BAD=BAD=BAD= -----END RSA PRIVATE KEY----- lua-resty-core-0.1.31/t/cert/chain/test-com.key.der000066400000000000000000000011401474236722600217600ustar00rootroot000000000000000\S\?KXZ0@Az;T迬PZIڙ`D%h@6|δXDcriJMhAgXapuY$/pwdM(bSѡ"6CFTrrGHY= H@benNMS m|!6)(50? eia֤S`#]Pn3mw+?߄[ B:ٍW8^Qڲ02t=AAH9ECE~RO#qFn~CИ:Q: xj.Ŵl A k{t&bB"(=RUI R$9FI~'`o1K8n&a;`" lua-resty-core-0.1.31/t/cert/chain/test-com.key.pem000066400000000000000000000015671474236722600220040ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQDYU6ysXD/5gKiWS7BY21qG3sowAtkZyPYUxUDJQeu7etHh+ZY7 VNXov6xQWkkR2plgROAlaEA2fPbOtJy5WNbq50SYY+uicvjpabRKTWiGQcpnWGHm cOgI/q3CdVkkDvAvGnCDjKN3ZOhN1cUoYqlT0aEi9TZDp0YAqpdUctRyRwIDAQAB AoGBAIl/5elIWYGFPaMKSPSxuECxq2II7WVuTru1BRDnTabE0lMICW185tohuqz4 NimbAJIoNTCRqv73Pwjz1AobZb6Nm7TDaahhstak6IlTYKcjXVBuM/UU4G13Kz/f hNVblv2cCn9CkeTNOvPZjYJXw/c4XlHasjDMMh8S83Q9095BAkEA+6oPzEiSsdo5 RX9D0EV+Uv4ID08johKbcZdGbsp+mo+PQ9CYOlE67QcKf8J4Hp2SFmq7mpTvvS7F tA/a2WwJswJBANwNwsJre3QPJmJCBAGsIrPrw9rFKLiT0/ajyhT7kKfG4Rw9t55S lY9VPFOxAJF9lDo4QiFUHi/8Htvd0B78wx0CQFh5cRRgbzIXhgrosu6Ff+Otayf2 qpBP+lX02M4aYmf0EGnG672U0SKDVy2TMKeSvckjvNCbi6z2xIqJCGdnlAECQFTh +f6E91oNfgDo9iKvA7PjfeklpE+OtnStOYZeg640SSFbrTilIovnlR2zaUS17DeI +/lfOUXJOx4UsfNCDQECQD7nndBJDJeSggFSJKcZ0RI59NVG8eGRSX7/3ycbq6+t guGI7WBvhDH4jNNL8jhuE+XuJuhhzOwP85872AFgIgw= -----END RSA PRIVATE KEY----- lua-resty-core-0.1.31/t/cert/mtls_ca.crt000066400000000000000000000104241474236722600200210ustar00rootroot00000000000000Certificate: Data: Version: 3 (0x2) Serial Number: 32:ed:21:56:d8:4e:aa:03:89:a9:4a:a4:e2:85:2d:8a:3b:2b:89:22 Signature Algorithm: sha256WithRSAEncryption Issuer: C = US, ST = California, O = OpenResty, CN = OpenResty Testing Root CA Validity Not Before: Mar 13 15:49:00 2022 GMT Not After : Mar 8 15:49:00 2042 GMT Subject: C = US, ST = California, O = OpenResty, CN = OpenResty Testing Root CA Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public-Key: (2048 bit) Modulus: 00:e6:37:d2:c6:17:36:c7:b2:7f:7d:cf:d0:62:87: 99:d9:21:b8:de:ff:d8:e2:3a:1c:68:90:8f:ce:17: 68:22:b0:60:30:cc:29:e8:34:ee:ff:b2:25:de:6e: 1a:d4:df:10:19:11:4b:40:61:d3:a9:4d:80:ed:97: 81:4e:c5:74:e8:4d:63:e3:5f:21:bc:5a:6e:22:a0: 17:91:c1:cb:25:53:9b:9d:4e:e1:51:5b:f6:52:e7: 0a:27:f6:16:c2:31:cb:6c:47:f4:89:51:15:cc:06: be:31:3e:1c:ea:ee:81:9b:c4:97:96:fd:e5:1c:95: 9e:c0:65:cd:a9:9a:cb:68:67:f2:62:a0:21:eb:5a: c5:a1:92:ed:32:41:28:f9:47:34:eb:44:ae:d6:e7: 76:71:11:98:c9:2e:ce:6c:7c:10:1b:c7:4c:c3:14: 89:4e:d9:4c:d9:c7:43:e9:3c:29:ca:62:a9:91:b3: 87:e7:d7:b4:18:ab:65:f9:6b:ed:82:ca:a1:36:35: 18:05:cb:5c:24:26:13:13:f8:99:ac:99:be:9b:a6: 73:df:0d:16:95:b1:dc:be:fe:7a:c2:b6:dc:c8:93: cf:10:e0:29:03:0e:28:78:18:84:ee:14:92:ab:be: 5a:a0:14:a2:4a:2f:d3:d0:b8:0e:00:d2:5a:cd:e4: bd:a1 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Key Usage: critical Certificate Sign, CRL Sign X509v3 Basic Constraints: critical CA:TRUE X509v3 Subject Key Identifier: F0:D7:4B:14:73:E1:67:00:6B:54:B4:19:20:76:12:9F:9D:8E:C8:09 Signature Algorithm: sha256WithRSAEncryption 6d:52:21:6d:6e:8c:e5:4a:28:07:65:6d:d8:7c:23:2e:c6:c1: d0:ec:27:b3:b0:c3:d3:e8:fa:72:b9:de:32:4e:ff:97:8d:86: a9:6d:b3:a9:b4:2d:77:ca:28:97:6a:3d:7b:a2:15:ed:34:dc: 72:9f:6f:e7:01:0c:d3:28:6a:80:1b:50:09:fd:d7:2c:d8:92: d5:10:c4:73:15:20:7d:99:dc:de:30:7b:3c:6e:e9:66:b2:0e: 4e:1a:c1:51:57:6e:5b:b0:a9:f6:ff:0b:8f:07:67:31:40:5b: 11:a9:06:d3:d3:76:c5:d2:56:95:9a:9e:4a:16:44:4b:32:e5: af:dd:4b:4d:5d:57:b8:85:69:36:93:2a:c6:0c:8f:e1:42:35: be:8e:f3:e7:35:d3:2c:3a:03:31:40:75:8e:e8:dd:57:35:20: 5e:18:a9:76:ce:85:be:7e:3a:cf:6e:08:58:5b:47:d5:e9:c4: ec:0e:e9:8e:3c:2d:5c:7b:59:20:5b:24:92:a0:e0:1e:a3:5a: 67:d8:ff:7f:a5:82:f1:df:db:05:65:79:88:b1:3c:e6:01:d1: 5a:c7:d2:6e:9a:e6:a2:da:4a:c7:19:78:d9:14:71:6e:1f:70: f3:41:e5:b3:78:31:d5:22:0e:7c:1a:b2:43:d9:86:ff:53:ea: 2b:ba:d2:27 -----BEGIN CERTIFICATE----- MIIDhDCCAmygAwIBAgIUMu0hVthOqgOJqUqk4oUtijsriSIwDQYJKoZIhvcNAQEL BQAwWjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAoT CU9wZW5SZXN0eTEiMCAGA1UEAxMZT3BlblJlc3R5IFRlc3RpbmcgUm9vdCBDQTAe Fw0yMjAzMTMxNTQ5MDBaFw00MjAzMDgxNTQ5MDBaMFoxCzAJBgNVBAYTAlVTMRMw EQYDVQQIEwpDYWxpZm9ybmlhMRIwEAYDVQQKEwlPcGVuUmVzdHkxIjAgBgNVBAMT GU9wZW5SZXN0eSBUZXN0aW5nIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQDmN9LGFzbHsn99z9Bih5nZIbje/9jiOhxokI/OF2gisGAwzCno NO7/siXebhrU3xAZEUtAYdOpTYDtl4FOxXToTWPjXyG8Wm4ioBeRwcslU5udTuFR W/ZS5won9hbCMctsR/SJURXMBr4xPhzq7oGbxJeW/eUclZ7AZc2pmstoZ/JioCHr WsWhku0yQSj5RzTrRK7W53ZxEZjJLs5sfBAbx0zDFIlO2UzZx0PpPCnKYqmRs4fn 17QYq2X5a+2CyqE2NRgFy1wkJhMT+Jmsmb6bpnPfDRaVsdy+/nrCttzIk88Q4CkD Dih4GITuFJKrvlqgFKJKL9PQuA4A0lrN5L2hAgMBAAGjQjBAMA4GA1UdDwEB/wQE AwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTw10sUc+FnAGtUtBkgdhKf nY7ICTANBgkqhkiG9w0BAQsFAAOCAQEAbVIhbW6M5UooB2Vt2HwjLsbB0Owns7DD 0+j6crneMk7/l42GqW2zqbQtd8ool2o9e6IV7TTccp9v5wEM0yhqgBtQCf3XLNiS 1RDEcxUgfZnc3jB7PG7pZrIOThrBUVduW7Cp9v8LjwdnMUBbEakG09N2xdJWlZqe ShZESzLlr91LTV1XuIVpNpMqxgyP4UI1vo7z5zXTLDoDMUB1jujdVzUgXhipds6F vn46z24IWFtH1enE7A7pjjwtXHtZIFskkqDgHqNaZ9j/f6WC8d/bBWV5iLE85gHR WsfSbprmotpKxxl42RRxbh9w80Hls3gx1SIOfBqyQ9mG/1PqK7rSJw== -----END CERTIFICATE----- lua-resty-core-0.1.31/t/cert/mtls_ca.key000066400000000000000000000032171474236722600200230ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA5jfSxhc2x7J/fc/QYoeZ2SG43v/Y4jocaJCPzhdoIrBgMMwp 6DTu/7Il3m4a1N8QGRFLQGHTqU2A7ZeBTsV06E1j418hvFpuIqAXkcHLJVObnU7h UVv2UucKJ/YWwjHLbEf0iVEVzAa+MT4c6u6Bm8SXlv3lHJWewGXNqZrLaGfyYqAh 61rFoZLtMkEo+Uc060Su1ud2cRGYyS7ObHwQG8dMwxSJTtlM2cdD6TwpymKpkbOH 59e0GKtl+WvtgsqhNjUYBctcJCYTE/iZrJm+m6Zz3w0WlbHcvv56wrbcyJPPEOAp Aw4oeBiE7hSSq75aoBSiSi/T0LgOANJazeS9oQIDAQABAoIBAQDhH9+uNE8uUv/X MNvvLfklWpOlBf25o+fZ3NuzRjJgEafOsCee2fyI8FWVwIfeeE8OpFm5GLDZk1+r dwdM10xuSheO5Z1gyfF/TJwfvamA09SNrPArFkm3YhUNZNl2hykMtwSLL06oWEOu dbXjit4VS9aNIbTlEe7O5/6Ih0W3zmr1yvUua2swmAZMx3GFA4kbjZZ9vDs27sdu K+VY3DYRbq1HkiNFT0otfke5bObFBCG7Yp8JLyhYaIkGYFoBXuZ6JNY8EuU2+YyP 6r40tJ7StR1Q6eZJh9/1leaYGZLCh5oFyKpilTuxHbRbr5A28RJKjKvPsdDgTtQn yHGg70FRAoGBAOhC3TQlFcT2WCCZHHql9JEEHnHVBWnL3Jg7VJuL1i6pEIz7qQkW AtBEIY/nnTcVNfJ6eXznYtutYvvRSgQTUsBNRoj3s1z9wKOo4uw4LoIUXDEmHCr+ 49DiQyIO21SNMHA+dVxvGRDDjLI9Uc+Scb64QOodoX75HLRZG++24mtdAoGBAP2/ gCjga2p8Jx9UnhIcrEIIGANyxEQeBdhF56Nt9CJy/Iwi3a6qQ/GkbeoDm5FhXnXo xcBaHyv2lwi4uO/hONY8eRnYxAWMwAKMZe6VnU1hWI2Ytkh+OcMPMh7NIGQf6X1o JZrBtnTms060TuuDjLeIlaubDR/xDrMWTMKjKbsVAoGAVLuYAZ8J6xpIGlRhbGlA 6OrMxJCHcgpahvsWKc0BLXKmRBjHmTX7fslsSRihZWgKj1SZH7U2fpgpxV6cFxKJ nPhUJEHhoKo+bjZ92tnANdqBq7iQjCsDJ8Bz52fuIlGD+1795+PsDA6bNKdkQkrV zlNf80kuEqmFDFJ5+6EHx00CgYAf+jkpbZa71aeMgDpnZ+uhaqm0DYuEVhBAgBa/ 9sRUbw86jc5IC7cCRcmAOzIosQ+ZZls9cV4KSUohVD4iJMzn2rkcM8AIPwOXjp/t 4DbxoHnrZjpaimW3Gjwju5AAbjEbl7tddFoNA2HHYlurvGlIW9MYzDJsOxGyKfZE dRF2PQKBgQDUKNHgDYEjLJ99S5Fm5zN/64bKzzDtktGdqOxik5pBKcs/BvOdLM0i eCjGz/3qrEoenFIBwF/IRz3ug90Zr8bWOu6DudReflAKI/N13dZ2gOTAfaX4ljJF w0ohSi6xs+mu1GmtipGtNxHi/J3na2BeSnSRFSUg6Zd+oh8BZQKmNg== -----END RSA PRIVATE KEY----- lua-resty-core-0.1.31/t/cert/mtls_cert_gen/000077500000000000000000000000001474236722600205115ustar00rootroot00000000000000lua-resty-core-0.1.31/t/cert/mtls_cert_gen/.gitignore000066400000000000000000000000341474236722600224760ustar00rootroot00000000000000*.pem *.csr cfssl cfssljson lua-resty-core-0.1.31/t/cert/mtls_cert_gen/generate.sh000077500000000000000000000017151474236722600226460ustar00rootroot00000000000000#!/bin/bash rm *.pem *.csr cfssl cfssljson wget -O cfssl https://github.com/cloudflare/cfssl/releases/download/v1.6.1/cfssl_1.6.1_linux_amd64 wget -O cfssljson https://github.com/cloudflare/cfssl/releases/download/v1.6.1/cfssljson_1.6.1_linux_amd64 chmod +x cfssl cfssljson ./cfssl gencert -initca -config profile.json mtls_ca.json | ./cfssljson -bare mtls_ca ./cfssl gencert -ca mtls_ca.pem -ca-key mtls_ca-key.pem -config profile.json -profile=client mtls_client.json | ./cfssljson -bare mtls_client ./cfssl gencert -ca mtls_ca.pem -ca-key mtls_ca-key.pem -config profile.json -profile=server mtls_server.json | ./cfssljson -bare mtls_server openssl x509 -in mtls_ca.pem -text > ../mtls_ca.crt mv mtls_ca-key.pem ../mtls_ca.key openssl x509 -in mtls_client.pem -text > ../mtls_client.crt mv mtls_client-key.pem ../mtls_client.key openssl x509 -in mtls_server.pem -text > ../mtls_server.crt mv mtls_server-key.pem ../mtls_server.key rm *.pem *.csr cfssl cfssljson lua-resty-core-0.1.31/t/cert/mtls_cert_gen/mtls_ca.json000066400000000000000000000003521474236722600230260ustar00rootroot00000000000000{ "CA": { "expiry": "175200h", "pathlen": 0 }, "CN": "OpenResty Testing Root CA", "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "US", "O": "OpenResty", "ST": "California" } ] } lua-resty-core-0.1.31/t/cert/mtls_cert_gen/mtls_client.json000066400000000000000000000003471474236722600237250ustar00rootroot00000000000000{ "CN": "foo@example.com", "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "US", "O": "OpenResty", "ST": "California" } ], "hosts": [ "foo@example.com", "bar@example.com" ] } lua-resty-core-0.1.31/t/cert/mtls_cert_gen/mtls_server.json000066400000000000000000000003101474236722600237430ustar00rootroot00000000000000{ "CN": "example.com", "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "US", "O": "OpenResty", "ST": "California" } ], "hosts": [ "example.com" ] } lua-resty-core-0.1.31/t/cert/mtls_cert_gen/profile.json000066400000000000000000000007361474236722600230520ustar00rootroot00000000000000{ "signing": { "default": { "expiry": "175200h" }, "profiles": { "server": { "usages": [ "signing", "digital signing", "key encipherment", "server auth" ], "expiry": "175199h" }, "client": { "usages": [ "signing", "digital signature", "key encipherment", "client auth" ], "expiry": "175199h" } } } } lua-resty-core-0.1.31/t/cert/mtls_client.crt000066400000000000000000000113141474236722600207130ustar00rootroot00000000000000Certificate: Data: Version: 3 (0x2) Serial Number: 19:0a:a3:a8:9c:d4:0f:dc:c6:fa:23:7b:f8:fc:bd:f4:73:4e:7e:b1 Signature Algorithm: sha256WithRSAEncryption Issuer: C = US, ST = California, O = OpenResty, CN = OpenResty Testing Root CA Validity Not Before: Mar 13 15:49:00 2022 GMT Not After : Mar 8 14:49:00 2042 GMT Subject: C = US, ST = California, O = OpenResty, CN = foo@example.com Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public-Key: (2048 bit) Modulus: 00:be:5b:09:4c:94:71:d3:82:54:4a:42:6a:76:aa: 34:5d:28:d9:45:e6:44:9a:74:9f:a6:e6:78:49:9e: c6:20:75:32:5f:92:3b:ec:6e:4b:7b:b0:75:1c:75: 09:00:05:77:d6:59:ca:55:5b:13:b6:76:3a:c6:18: dc:37:6a:20:93:e6:26:56:5d:0b:96:8c:01:f2:96: 38:08:08:36:a2:64:12:21:a0:8d:48:cd:9a:26:78: 92:29:b6:63:eb:14:d9:b6:e5:87:f7:d5:55:a4:cc: 53:1c:a3:7c:b8:bd:ad:7c:a4:d4:86:1f:a7:1c:43: c5:1a:b5:f1:03:bd:fe:19:98:1d:b7:13:2b:93:a2: 2a:0e:21:7e:42:a9:bb:28:69:49:59:e7:89:0e:7d: 5a:ce:fb:d4:0c:20:6a:e1:db:b2:6a:e5:a7:55:e0: d0:58:4a:e2:08:78:82:b9:06:0c:65:f9:24:06:e6: 8a:13:b2:9a:ef:1b:4a:b2:3a:b4:98:7f:dd:3c:0e: 85:0b:a6:c6:47:2f:63:c2:73:52:41:db:7c:06:c3: 2a:b5:2d:d1:e1:30:d5:c4:79:c9:b9:35:68:46:ad: c4:45:57:ea:11:88:27:37:ed:ac:49:2d:c4:d6:c6: a6:74:8d:d3:bc:e0:d9:69:25:0c:0c:b0:e3:b7:cb: 8d:99 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Key Usage: critical Digital Signature, Key Encipherment X509v3 Extended Key Usage: TLS Web Client Authentication X509v3 Basic Constraints: critical CA:FALSE X509v3 Subject Key Identifier: 22:70:5E:30:8C:4D:66:39:E7:60:C9:29:A2:ED:95:32:34:63:5C:C0 X509v3 Authority Key Identifier: keyid:F0:D7:4B:14:73:E1:67:00:6B:54:B4:19:20:76:12:9F:9D:8E:C8:09 X509v3 Subject Alternative Name: email:foo@example.com, email:bar@example.com Signature Algorithm: sha256WithRSAEncryption 96:e7:2a:fc:2a:56:16:80:e2:d3:79:0c:46:db:c3:88:ab:d3: ef:39:66:4b:a9:ab:6c:0e:30:08:07:7c:fc:03:6c:f7:dd:fb: 3e:a8:c8:68:28:ab:4e:73:97:80:27:5d:c5:9d:52:00:aa:08: 25:c8:f9:dc:df:64:73:a4:58:5b:bd:5f:1a:53:a4:33:a3:b1: 45:38:2d:be:d7:f3:a4:c4:f4:7a:07:71:44:f1:a2:65:02:e4: 71:84:01:b5:83:4b:de:83:b5:ad:ac:b9:3c:17:42:0c:9a:7d: eb:7f:ab:26:dd:9b:3a:fd:95:37:55:cc:01:c3:3f:20:df:e5: ed:49:51:7a:42:ea:f3:8a:3f:da:6e:c1:1a:11:b9:45:4d:6e: c9:21:f4:e3:4f:31:72:5b:bb:01:92:b6:7f:f1:8a:9e:6c:d0: 7f:96:d7:eb:29:09:53:38:26:41:00:f2:33:04:77:bd:a9:ee: 60:9e:06:b7:7d:26:ae:1c:4f:56:bd:a5:b6:50:40:be:be:84: 2a:54:21:59:47:7d:a5:1e:63:6d:28:36:4d:a6:e4:62:69:9b: 9b:fa:2b:48:e8:64:d7:14:f4:62:a2:26:17:a5:05:58:4a:38: d2:44:e7:33:90:b9:c1:8c:85:02:99:b8:03:1a:03:d2:cf:ac: a5:6b:44:98 -----BEGIN CERTIFICATE----- MIID3DCCAsSgAwIBAgIUGQqjqJzUD9zG+iN7+Py99HNOfrEwDQYJKoZIhvcNAQEL BQAwWjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAoT CU9wZW5SZXN0eTEiMCAGA1UEAxMZT3BlblJlc3R5IFRlc3RpbmcgUm9vdCBDQTAe Fw0yMjAzMTMxNTQ5MDBaFw00MjAzMDgxNDQ5MDBaMFAxCzAJBgNVBAYTAlVTMRMw EQYDVQQIEwpDYWxpZm9ybmlhMRIwEAYDVQQKEwlPcGVuUmVzdHkxGDAWBgNVBAMM D2Zvb0BleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB AL5bCUyUcdOCVEpCanaqNF0o2UXmRJp0n6bmeEmexiB1Ml+SO+xuS3uwdRx1CQAF d9ZZylVbE7Z2OsYY3DdqIJPmJlZdC5aMAfKWOAgINqJkEiGgjUjNmiZ4kim2Y+sU 2bblh/fVVaTMUxyjfLi9rXyk1IYfpxxDxRq18QO9/hmYHbcTK5OiKg4hfkKpuyhp SVnniQ59Ws771AwgauHbsmrlp1Xg0FhK4gh4grkGDGX5JAbmihOymu8bSrI6tJh/ 3TwOhQumxkcvY8JzUkHbfAbDKrUt0eEw1cR5ybk1aEatxEVX6hGIJzftrEktxNbG pnSN07zg2WklDAyw47fLjZkCAwEAAaOBozCBoDAOBgNVHQ8BAf8EBAMCBaAwEwYD VR0lBAwwCgYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUInBeMIxN ZjnnYMkpou2VMjRjXMAwHwYDVR0jBBgwFoAU8NdLFHPhZwBrVLQZIHYSn52OyAkw KwYDVR0RBCQwIoEPZm9vQGV4YW1wbGUuY29tgQ9iYXJAZXhhbXBsZS5jb20wDQYJ KoZIhvcNAQELBQADggEBAJbnKvwqVhaA4tN5DEbbw4ir0+85Zkupq2wOMAgHfPwD bPfd+z6oyGgoq05zl4AnXcWdUgCqCCXI+dzfZHOkWFu9XxpTpDOjsUU4Lb7X86TE 9HoHcUTxomUC5HGEAbWDS96Dta2suTwXQgyafet/qybdmzr9lTdVzAHDPyDf5e1J UXpC6vOKP9puwRoRuUVNbskh9ONPMXJbuwGStn/xip5s0H+W1+spCVM4JkEA8jME d72p7mCeBrd9Jq4cT1a9pbZQQL6+hCpUIVlHfaUeY20oNk2m5GJpm5v6K0joZNcU 9GKiJhelBVhKONJE5zOQucGMhQKZuAMaA9LPrKVrRJg= -----END CERTIFICATE----- lua-resty-core-0.1.31/t/cert/mtls_client.key000066400000000000000000000032131474236722600207120ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEogIBAAKCAQEAvlsJTJRx04JUSkJqdqo0XSjZReZEmnSfpuZ4SZ7GIHUyX5I7 7G5Le7B1HHUJAAV31lnKVVsTtnY6xhjcN2ogk+YmVl0LlowB8pY4CAg2omQSIaCN SM2aJniSKbZj6xTZtuWH99VVpMxTHKN8uL2tfKTUhh+nHEPFGrXxA73+GZgdtxMr k6IqDiF+Qqm7KGlJWeeJDn1azvvUDCBq4duyauWnVeDQWEriCHiCuQYMZfkkBuaK E7Ka7xtKsjq0mH/dPA6FC6bGRy9jwnNSQdt8BsMqtS3R4TDVxHnJuTVoRq3ERVfq EYgnN+2sSS3E1samdI3TvODZaSUMDLDjt8uNmQIDAQABAoIBACqRsUKu78WdH7x7 ndNrvMoYmH5JQI5KBmoMoFnWZ/haPSmiSkRVZgwDKi1y/tBCaMpGyjjMZVwolHw4 kwbRdPeeQHSP2keQh974OQ+SxqUKPAPJI89kK1TvIcCySSYJQ6bjLcT+sGhqSSve Y8XspR96vQxBh92KSknu5jcwBeMy/eG0mmszzP3y2R0BPztuZdE6dq/KxWQ/R4/P JG9V1rNkIY+1JZvIICIH1Ehn4UKjiE+FJmyDbDlPKEi7W4CpRnShMLOF4cCFnQLW RQds3Dj9GcVY+8Q/GLZF0ATjekIyEsKZEgrMAUF5ZSGRpjJQEHX7oseAiQGQxtHT nj5b1AECgYEAwewXbbd1MqRQ6ohfsQ8j5HSMY6ahvUzs1dZUckr2jw8B98tfi/uj a6Jq1KZe12+4dfwruRSaYdTsSVuvNiSJOxElY0C1p+lXdprFf7XfoQ6UNtg22jcH 9f8cftnlJoV5whh3YKjqnnnAWUQZ61FTNJ258/t+x0ZgpBJvqBoHwDUCgYEA+0qp FZ5xS4FLJMc+Xf/hUeXo+04e4OD/se3atYqyuh1ghmQZfRRPOC110HG99H+rzq/x xPMvRFahkAMyi+/3oIcBEuXvoQyqscIsAhkWD/e9t3Qc9OsWe1hlAgWKZxr6oR2U KKR1FD7UVecOH+FKCKaL5UpEt4yEigc1NtSlTFUCgYBnV5agrIyzQSex5J0CMWxS Od362PkGdXEc/8we4F4GnNvSnrm7Uo2jNXmy+zo9mtb1YT43sogXLK4C5e44bz4G kTuYagqkgdBPb2lihpy3KprHo2+P2JXQfXRFEX9xiN37Fqi/hSUK8R0VNRqO8dbi ik9nexXzwkiMBxsjvUN2JQKBgFy62FpZ9YTfWVNhEuqtGgCWzrqtwUdKwBBwrVyA qiNz48Kz/ZPigrlATVF2J5qp4kSLOLRs6OxW65exFl39V2utZgALSbosanDeLk83 4qRRz3h7KJRYjBtIKz3rvX7+va3mtF2rEmk+Jizs7pFlGWTH0Kf0GBeDiwVEU6bA IZ9hAoGAQTjnRGMjvyhq0aPYP+mRFiMKSkcL1nyXizYInfAnbfbL/uEODH7D+iMf kak+UgmeD9ce5d/APmZp3/FzYH/M8ivBgG+MnaI+MLVMhmQdLZyMtbSKKaDpiim7 DdN1wCXYbur0HlO2t+wemMZPpQu7wybgEOLlIG7Yj/0OWDcal1c= -----END RSA PRIVATE KEY----- lua-resty-core-0.1.31/t/cert/mtls_server.crt000066400000000000000000000112131474236722600207410ustar00rootroot00000000000000Certificate: Data: Version: 3 (0x2) Serial Number: 2f:d5:41:13:5a:ff:c7:1c:5b:ce:28:cd:a6:f7:a5:5a:0d:c0:e2:d2 Signature Algorithm: sha256WithRSAEncryption Issuer: C = US, ST = California, O = OpenResty, CN = OpenResty Testing Root CA Validity Not Before: Mar 13 15:49:00 2022 GMT Not After : Mar 8 14:49:00 2042 GMT Subject: C = US, ST = California, O = OpenResty, CN = example.com Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public-Key: (2048 bit) Modulus: 00:d7:03:80:a7:42:7d:06:5a:7b:70:d8:11:96:dd: 63:35:53:07:28:71:52:05:40:55:83:61:a7:14:ac: cf:4b:9b:ab:b7:4e:9d:79:e9:13:3d:bc:c3:67:8f: dd:88:d9:8b:c2:31:aa:b8:28:9e:13:70:db:76:b0: 12:1c:f8:35:c6:2e:33:9c:b9:04:e3:47:e0:f9:e4: 7f:a5:55:03:0c:2d:b2:54:17:29:12:dd:61:6e:5c: 33:9f:e5:8f:8a:2b:41:53:dc:e1:98:49:63:df:e3: 00:30:2d:1b:bb:f0:8f:cb:04:ec:c9:98:c4:09:5b: b4:ba:a9:a0:0a:77:d2:42:76:7c:ac:64:c3:97:85: 50:5d:7d:02:61:2a:00:93:d0:69:5e:87:22:f0:c1: 1e:53:46:02:40:37:c9:55:77:99:7d:9d:3d:35:14: 74:84:e3:73:ca:e7:4a:ab:33:98:26:aa:41:4b:b5: e6:63:7c:a4:1e:25:6a:88:f4:56:d9:2c:63:dd:89: 19:fa:25:41:44:95:87:40:a7:9b:4e:3a:91:29:32: 79:66:05:f4:2f:68:2c:06:53:df:4d:60:be:ac:09: 20:61:9c:6f:1a:a6:07:5a:e7:41:91:9d:36:77:38: 18:3a:69:7b:67:29:9f:1d:e0:c2:d2:8f:16:5b:14: e8:e1 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Key Usage: critical Digital Signature, Key Encipherment X509v3 Extended Key Usage: TLS Web Server Authentication X509v3 Basic Constraints: critical CA:FALSE X509v3 Subject Key Identifier: 16:07:B5:C2:4C:B5:2D:4F:B8:E9:D6:FA:2F:3F:C0:1B:B6:4F:20:E6 X509v3 Authority Key Identifier: keyid:F0:D7:4B:14:73:E1:67:00:6B:54:B4:19:20:76:12:9F:9D:8E:C8:09 X509v3 Subject Alternative Name: DNS:example.com Signature Algorithm: sha256WithRSAEncryption d9:c0:c0:d6:8b:44:04:26:b3:98:24:2c:12:82:6d:15:79:92: 76:c9:77:94:c1:be:8f:8a:18:78:96:04:68:c9:0a:d1:84:c5: de:cd:ba:b5:a2:3b:d4:0a:70:be:00:49:19:c0:6e:ca:e9:e5: 8b:b6:e3:a2:39:0d:d8:ee:55:1a:08:73:39:19:d3:07:07:33: 8c:d8:1b:0f:1b:73:0e:84:72:cf:e6:c1:a1:da:39:aa:c0:2e: 3d:b9:a6:8f:ec:98:3a:07:58:34:c2:5e:4c:1a:6b:db:ce:51: 92:25:1d:ba:78:4b:11:b6:f1:69:02:cb:ac:32:bb:80:f9:15: 91:bf:4e:6a:ab:51:51:7c:7b:1a:72:80:96:eb:0c:fa:56:0e: f2:87:3c:16:8a:04:aa:8a:9d:0c:d9:e0:c4:2a:20:42:5a:12: 41:52:30:50:3d:85:f8:07:31:6b:af:a4:d2:44:38:69:ab:88: 05:d4:5b:68:34:02:dc:99:5a:6c:b7:ea:fc:79:76:fe:68:29: df:94:22:58:46:f2:40:cb:e1:92:17:d8:1e:3d:fa:a2:56:4f: ac:3c:3d:ae:f7:90:12:ac:3b:6c:1e:1f:26:48:08:87:9a:0e: 8d:9d:75:ef:86:1e:63:ac:e9:14:47:ad:3f:4f:10:57:2a:d1: 95:ec:6f:24 -----BEGIN CERTIFICATE----- MIIDwzCCAqugAwIBAgIUL9VBE1r/xxxbzijNpvelWg3A4tIwDQYJKoZIhvcNAQEL BQAwWjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAoT CU9wZW5SZXN0eTEiMCAGA1UEAxMZT3BlblJlc3R5IFRlc3RpbmcgUm9vdCBDQTAe Fw0yMjAzMTMxNTQ5MDBaFw00MjAzMDgxNDQ5MDBaMEwxCzAJBgNVBAYTAlVTMRMw EQYDVQQIEwpDYWxpZm9ybmlhMRIwEAYDVQQKEwlPcGVuUmVzdHkxFDASBgNVBAMT C2V4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1wOA p0J9Blp7cNgRlt1jNVMHKHFSBUBVg2GnFKzPS5urt06deekTPbzDZ4/diNmLwjGq uCieE3DbdrASHPg1xi4znLkE40fg+eR/pVUDDC2yVBcpEt1hblwzn+WPiitBU9zh mElj3+MAMC0bu/CPywTsyZjECVu0uqmgCnfSQnZ8rGTDl4VQXX0CYSoAk9BpXoci 8MEeU0YCQDfJVXeZfZ09NRR0hONzyudKqzOYJqpBS7XmY3ykHiVqiPRW2Sxj3YkZ +iVBRJWHQKebTjqRKTJ5ZgX0L2gsBlPfTWC+rAkgYZxvGqYHWudBkZ02dzgYOml7 ZymfHeDC0o8WWxTo4QIDAQABo4GOMIGLMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUE DDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBQWB7XCTLUtT7jp 1vovP8Abtk8g5jAfBgNVHSMEGDAWgBTw10sUc+FnAGtUtBkgdhKfnY7ICTAWBgNV HREEDzANggtleGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEA2cDA1otEBCaz mCQsEoJtFXmSdsl3lMG+j4oYeJYEaMkK0YTF3s26taI71ApwvgBJGcBuyunli7bj ojkN2O5VGghzORnTBwczjNgbDxtzDoRyz+bBodo5qsAuPbmmj+yYOgdYNMJeTBpr 285RkiUdunhLEbbxaQLLrDK7gPkVkb9OaqtRUXx7GnKAlusM+lYO8oc8FooEqoqd DNngxCogQloSQVIwUD2F+Acxa6+k0kQ4aauIBdRbaDQC3JlabLfq/Hl2/mgp35Qi WEbyQMvhkhfYHj36olZPrDw9rveQEqw7bB4fJkgIh5oOjZ1174YeY6zpFEetP08Q VyrRlexvJA== -----END CERTIFICATE----- lua-resty-core-0.1.31/t/cert/mtls_server.key000066400000000000000000000032131474236722600207420ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEA1wOAp0J9Blp7cNgRlt1jNVMHKHFSBUBVg2GnFKzPS5urt06d eekTPbzDZ4/diNmLwjGquCieE3DbdrASHPg1xi4znLkE40fg+eR/pVUDDC2yVBcp Et1hblwzn+WPiitBU9zhmElj3+MAMC0bu/CPywTsyZjECVu0uqmgCnfSQnZ8rGTD l4VQXX0CYSoAk9BpXoci8MEeU0YCQDfJVXeZfZ09NRR0hONzyudKqzOYJqpBS7Xm Y3ykHiVqiPRW2Sxj3YkZ+iVBRJWHQKebTjqRKTJ5ZgX0L2gsBlPfTWC+rAkgYZxv GqYHWudBkZ02dzgYOml7ZymfHeDC0o8WWxTo4QIDAQABAoIBAEnmZUiXnJsbbEPr r5f3vYptYA9xa2xsoTeHz8JWZuUouwtE1PE6v6c/grXMh6rqgpObOH8VTseFyZhw ibk1Ql48MPcTzG9FnDinZYvwvRxpdFpcn3xhZIRm4kN5xi0KEuj9CPireM1RmxXz 2w1scC+qIKxlejNxNpvVgzE136mBqEFKJzecP+yZuH/A86MQCgwqqa3jSz5ApNg+ 1aJE34cGFieDbAN+9sdqWA3OkRrHoy8EakUf4JEvwX1AwUN832mj+N/LfmcCGMeD YhzybzlPBV2q2T1+pHIdNT99JVNPkgdTe1903EjnG5oSDGHt2i9MdnNkMsffDWNt pJiqSHECgYEA2hL6l8Py4oa5AJ2WXriuHRJykAs90K0akftQt4i4lWCbeRhaGh7h kPgpDS33RkE4SymVVr0c05abMCKabQBwbu4PNCqetCFtfmIQdQCTUbLbXjL8UuD2 QnF7nbHiwyGBKRMU/F74oX3z7lXLgRtIiyyo5yYgIAQqpz3oJAaXNTUCgYEA/GhE Ziez8FXVAg3XwwrE3SexRFKv1JqipYE4mr+ouzfpn9yn8mttxbOORiAAEBl3ZPhd ZUBzLy19fdFZ8RJ0zPsqoZxsd09/XetaBU56C/g9u0fycj1L2elh9rQAlOW0Grus l8jBh01TGtlg0xobK0zjwdGPcbYkp1IzIqyD9n0CgYEAicBvVyrJ5FnhxwfEkrTq FycuAtt3Arg2DnzH8geFQaayzv2Y/OMA7Yg0tkSQ7GoKW0A7O31eFjIOeYuCLNSY MRpjtDov4e0zsx/S8XWZmYP3mjtutBOyuyngQi655TTm18FcAkcjmy9qxOShFj7b xj5BuzGUHWVEZDxwxUD8hvkCgYBnrcyqyZQ4HImqllUSYNIMpclC71QaWIqGwVWm +yMsBAOLDvBNu6MTmnXOiEZ+VnecmgiDFr45ms35aI0xYQtpR6JzT/Wd7KG8ynfn xhyL3iQ9UYhdNKB7mkoLNFUo1FHuyThUALq+AR0p4jDLheWzG5pSeuoZI2Ba+oDW tVZfYQKBgC5phtERR5LKU5Wkzm+uY2j+Nzh4kuKkdLosB9pUW8VnrwFDLZ+r1CxG L6CxOZ0AylCMIlrFeUXMa91kLDJYch0NUPHuGBkdIBDXi2kqN7GflTdV3Z8uev20 uMjErA93yVOWHTR3Wo8WIHy5mdsNRQgGAPw1RVW7rnYIyXJW/mTs -----END RSA PRIVATE KEY----- lua-resty-core-0.1.31/t/cert/ocsp/000077500000000000000000000000001474236722600166305ustar00rootroot00000000000000lua-resty-core-0.1.31/t/cert/ocsp/cfssl/000077500000000000000000000000001474236722600177425ustar00rootroot00000000000000lua-resty-core-0.1.31/t/cert/ocsp/cfssl/README.md000066400000000000000000000024111474236722600212170ustar00rootroot00000000000000Following steps require https://github.com/cloudflare/cfssl Initiate CA by creating root certificate pair: ``` cfssl gencert -initca ca_csr.json | cfssljson -bare ca ``` Continue with intermediate certificate pair for signing: ``` cfssl gencert -ca ca.pem -ca-key ca-key.pem -config=cfssl_config.json -profile=intermediate intermediate_ca_csr.json | cfssljson -bare intermediate_ca ``` Also create OCSP certificate pair to sign OCSP responses: ``` cfssl gencert -ca intermediate_ca.pem -ca-key intermediate_ca-key.pem -config=cfssl_config.json -profile=ocsp ocsp_csr.json | cfssljson -bare ocsp ``` Create a leaf certificate: ``` cfssl gencert -ca intermediate_ca.pem -ca-key intermediate_ca-key.pem -config cfssl_config.json -profile server leaf_csr.json | cfssljson -bare leaf ``` Create an OCSP response for the certificate: ``` cfssl ocspsign -ca intermediate_ca.pem -responder ocsp.pem -responder-key ocsp-key.pem -cert leaf.pem -status good | cfssljson -bare ocsp-response-good ``` Bundle certificate to be installed at Nginx: ``` cat leaf.pem intermediate_ca.pem ca.pem > leaf-bundle.pem ``` Inspect OCSP response to see what is the Next Update: ``` openssl ocsp -text -no_cert_verify -respin t/cert/ocsp/cfssl/ocsp-response-good-response.der | grep "Next Update" ``` lua-resty-core-0.1.31/t/cert/ocsp/cfssl/ca-key.pem000066400000000000000000000032171474236722600216210ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA4U+dsu8CAV+Tyhn+z1UFSJ6H7CUQuq7AeGH5df3D8nEyW83N 8NjImED3SJkns8vzwHLP/7/UqPPDWZLu/KlIaI2740W3Zin4Eq4b9Tfbu+HTI+Cf Vo461WlKMnKGG7nzmElSRA04cQm/M/LhajQS7EwM0Hto+GEGGLjJSVMOPY3zvnqu bRMWfzGn5cMON9bVclZHnVwhwNeR9EMYwCpN/mgXjFlC2O5vHPjM7etRn2c3EIXP 370YQ0iC2UkUB4ttX9d13obwqqprTyZH9Fl1X1XuyJLIMB5ahawyck7Jf9NB2dAJ 9udilGEO1uLiY6StbYF/9IxvW47QtFN5z+ukFwIDAQABAoIBAQDZ5TlJlsOFuH0g 8sruj/awKECjK6VmJSKWSYoLhgM+MCLXjc0go0Y7mHiNiTBQPWnaMC7f0xFC45uE wQjG6J/SHWAbh4y6DNSQnDkFiaPDq72Z8N2nw506Tr0m1ILFxavDFwWsMmznRNnY z4cYQowaYeHyrabyrkJLHknr05ruAs2hflAbRqVXICdF7NoubPmKEb+LCd0jyzPo hITUtkIEssBW1zXacnAoMG+IWZOWJsbW8QtGsEfuABeHdKq1VX07XSe5tO/9KnYw E2QZq0bncytKiiN6OzTCFROnzc8F4YYxxlOm5klNsRKFBNh6wm7KwEMT/eA6gcbo WkT/EpMhAoGBAOwL3YqD6fxTOnEXhKgEo+dKzAUutsdRPvV1a+OSgfn/KDCaPm90 UbUARyz+x+DNBmS7muClCALCoQNkb5IRgSzVAckuRpanadtT5TLSSxQFP8LCoHSQ evPgwtPFHUWdgudEh5Oz20sblGyml0jtkDbmh0bRDz5xdQudr9q8IPBFAoGBAPRb bvmCeYsEke9zN6lZceBP6wfQLVeJhqV+63JG/qAMzUR4KD+/gfH0XWLDLA1pbp2C VYrZl6LhBx9DKuU8HCzsxA0uBvTx+JJUfxcuPZ6fX5/kD4Npvta7nsjJ+nmDR29l Q4dJMe3u/abNDGOc+RqPQN5F+rXM3Yx/7SkQj+6rAoGAeB8Fq8K7pUuZdwnX2UUb P83hi1WdcEsZNgJ+V/4rpNRDWJB163QPTIQKtIwnnW/YrBSImX+CVx1CoR5QZM4B pZX0ZbPl+i7SAOptvfIkgNi2/N7cltUbrNYZb3llDxM8FYLbV7/0fgFYA/63CEbU 2Atylgg3sLg+Lx4c6rxIKt0CgYEAjCA6vV5y8KOIRHYf/z9JrEZoEyzwM3ir/A+S WRAZSBLPS2pUOmpJzERDoTUm9/Hz+uMYxu0MpdzBRs4vtREJX0HPE3fHiYOQ9ej6 kIJ115axMXGI6+UiCOXCooYg2rnLpze8x8HTngwk7Rg8+Iq11uM7YbtjkAmRKtbZ W2kiAM0CgYBsDwsSIHT6FsogaxHMejv88UKmqIiAIKudtU3jdfRVGE938WPpfyuL 1+iYI3eWyHzBvco4Ghv2icnWOC+DS5XBP3s9D3ueVEh8j/49bd/4mUeyiZMB5Pdr /tAqEyeNU5iYf5XwQwPUm6QMRkCCVwM3kSLkhyWF2wPE/XhVsIKxZQ== -----END RSA PRIVATE KEY----- lua-resty-core-0.1.31/t/cert/ocsp/cfssl/ca.csr000066400000000000000000000020111474236722600210300ustar00rootroot00000000000000-----BEGIN CERTIFICATE REQUEST----- MIICwTCCAakCAQAwfDELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8xDzAN BgNVBAcTBk90dGF3YTESMBAGA1UEChMJTHVhIE5naW54MRowGAYDVQQLExFMdWEg TmdpbnggUm9vdCBDQTEaMBgGA1UEAxMRTHVhIE5naW54IFJvb3QgQ0EwggEiMA0G CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDhT52y7wIBX5PKGf7PVQVInofsJRC6 rsB4Yfl1/cPycTJbzc3w2MiYQPdImSezy/PAcs//v9So88NZku78qUhojbvjRbdm KfgSrhv1N9u74dMj4J9WjjrVaUoycoYbufOYSVJEDThxCb8z8uFqNBLsTAzQe2j4 YQYYuMlJUw49jfO+eq5tExZ/Maflww431tVyVkedXCHA15H0QxjAKk3+aBeMWULY 7m8c+Mzt61GfZzcQhc/fvRhDSILZSRQHi21f13XehvCqqmtPJkf0WXVfVe7Iksgw HlqFrDJyTsl/00HZ0An252KUYQ7W4uJjpK1tgX/0jG9bjtC0U3nP66QXAgMBAAGg ADANBgkqhkiG9w0BAQsFAAOCAQEACSfvzpO2ENkOEPDznNPHLXIPpNwdxBXoJPNs 61vIMK4t5qBraAqUTrw2hCs/7CEez0TDCCiZkHNzwpSzKmFBh98D4rdaGTdrN3XG NaZd7yacQ2ZB+vY45GbM5LNqXfKA4uwISqEKL8nFWkwQceTF52L9rIJTwcBjUcQg 23iU1fjsDFXuSP+RxL4hsO2imcrQHuouIW0/iQW3ZB7gYLqN+OqOm0Fj369UeFUo I0NAGt1u3p+oxQ22FfoZJ2F9jDVvzRJe9TE+KrZv7QhRNQftSOu86m6EqjZKP88k zGIuY6NB4N1K1fua6Rh/or68ERvT4aPIvzLklzCSbzS1qsR0Bw== -----END CERTIFICATE REQUEST----- lua-resty-core-0.1.31/t/cert/ocsp/cfssl/ca.pem000066400000000000000000000025331474236722600210330ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDyDCCArCgAwIBAgIUUw9rlqc2DnJNFZ9gw/zRLPRQ4zMwDQYJKoZIhvcNAQEL BQAwfDELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8xDzANBgNVBAcTBk90 dGF3YTESMBAGA1UEChMJTHVhIE5naW54MRowGAYDVQQLExFMdWEgTmdpbnggUm9v dCBDQTEaMBgGA1UEAxMRTHVhIE5naW54IFJvb3QgQ0EwHhcNMjQwMzEwMTQxODAw WhcNMjkwMzA5MTQxODAwWjB8MQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJp bzEPMA0GA1UEBxMGT3R0YXdhMRIwEAYDVQQKEwlMdWEgTmdpbngxGjAYBgNVBAsT EUx1YSBOZ2lueCBSb290IENBMRowGAYDVQQDExFMdWEgTmdpbnggUm9vdCBDQTCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOFPnbLvAgFfk8oZ/s9VBUie h+wlELquwHhh+XX9w/JxMlvNzfDYyJhA90iZJ7PL88Byz/+/1Kjzw1mS7vypSGiN u+NFt2Yp+BKuG/U327vh0yPgn1aOOtVpSjJyhhu585hJUkQNOHEJvzPy4Wo0EuxM DNB7aPhhBhi4yUlTDj2N8756rm0TFn8xp+XDDjfW1XJWR51cIcDXkfRDGMAqTf5o F4xZQtjubxz4zO3rUZ9nNxCFz9+9GENIgtlJFAeLbV/Xdd6G8Kqqa08mR/RZdV9V 7siSyDAeWoWsMnJOyX/TQdnQCfbnYpRhDtbi4mOkrW2Bf/SMb1uO0LRTec/rpBcC AwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O BBYEFOnsOYUW8U3ak+h1LUisz1czYQo+MA0GCSqGSIb3DQEBCwUAA4IBAQDHySN4 lWLHa12vYPvRVLNeWq3RaHQfKc2F2PhHriGCegY4lyZJqfC0XGI4LBnJ5GK//D0B Hb8jcbGyortGBEwGuqjuOMdv0HOWibqZ7LPZ98GegtAjAJWMp/sQXkIYiRM8hlNC pl9Vp9vsnUjfCrMaLVkZCC2Nwixc5mhSeH0aYHxxFwqh88oWbXzW7xobcTaYx/1P kPdCy+jiBMCZII7J1u/e1B0J1VFad+IVJpQW+DzVIzJz9ClNAsJZjx1BBwIJGGEZ fS1XXw+HgGeH2cVFnThMy0PIvx70b//GxEoXwuJhL2+z/tNhRRBN2eMa2zrZS94k z+yCDRXP/rDxf+b7 -----END CERTIFICATE----- lua-resty-core-0.1.31/t/cert/ocsp/cfssl/ca_csr.json000066400000000000000000000003471474236722600220730ustar00rootroot00000000000000{ "CN": "Lua Nginx Root CA", "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "CA", "L": "Ottawa", "O": "Lua Nginx", "OU": "Lua Nginx Root CA", "ST": "Ontario" } ] } lua-resty-core-0.1.31/t/cert/ocsp/cfssl/cert-response.der000066400000000000000000000032661474236722600232360ustar00rootroot000000000000000 0 +00001 0 UCA10UOntario10 UOttawa10U  Lua Nginx1!0U Lua Nginx OCSP Responder1!0ULua Nginx OCSP Responder20200418195600Z0w0u0M0 +cxPNmGka#<ܷ=Tf=wԚ4%wl܅Oku%,Wр20200418190000Z20200422190000Z0  *H  ç /\a߮xMEN8#9&q$ u>l?x)á2&l z (R;N%}7,ѭ ZOU棬-^!Xz֬wF?uVi~xm?B鑘8߮yi 9WW\rDDVo.pLiAc@J@V@9Zm *j6lO+:i wNK@9劝OcM}*J_h^0Z0V0>(_b~ZJuWpx%0  *H  01 0 UCA10UOntario10 UOttawa10U  Lua Nginx1"0 U Lua Nginx Intermediate CA1"0 ULua Nginx Intermediate CA0 200418194000Z 210418194000Z01 0 UCA10UOntario10 UOttawa10U  Lua Nginx1!0U Lua Nginx OCSP Responder1!0ULua Nginx OCSP Responder0"0  *H 0 BDiI,9@oǦL쒢y0}s_ռl fw-)mWT&M|MA0T{0>awSP@c;<=-?**oVYY0Yx}|25 j^<mU>Xv.%F4VVudwiFub]@Z 8qȘ`eXȲ5߼?ieq00U0U% 0 + 0 U00U153k`0U#0=Tf=wԚ07++0)0'+0https://ocsp-responder.test0  *H   ^"b.g930- AJuѴXtX%>P SA25B* ZrP6DN#NP5Tz˟'3diM,vRf>3K;N'hOh;G~z ✣v̕fϵQ3B#*C8><Nj.t$Z zpb'I'1`[=0/aWҷ!lua-resty-core-0.1.31/t/cert/ocsp/cfssl/cfssl_config.json000066400000000000000000000013471474236722600233010ustar00rootroot00000000000000{ "signing": { "default": { "ocsp_url": "https://ocsp-responder.test", "expiry": "2190000h", "usages": [ "signing", "key encipherment", "client auth" ] }, "profiles": { "ocsp": { "usages": ["digital signature", "ocsp signing"], "expiry": "876000h" }, "intermediate": { "usages": ["cert sign", "crl sign"], "expiry": "2190000h", "ca_constraint": {"is_ca": true} }, "server": { "usages": ["signing", "key encipherment", "server auth"], "expiry": "876000h" }, "client": { "usages": ["signing", "key encipherment", "client auth"], "expiry": "876000h" } } } } lua-resty-core-0.1.31/t/cert/ocsp/cfssl/intermediate_ca-key.pem000066400000000000000000000032131474236722600243470ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAncpy3Iqw4E71BI2Bt5P1+70lHHt2sBvFu9UM0+6z/mwSqi1B /APeSDAEpUptQTPk2gdaJB2G1IpH5pcYU6I+YOzQ02XPmtlRlFxizP3lx8f6JJnM w194YD3JOayz9n+njKfonS2/EwpetopCKrHwh0FsQd0qHx78RuojTKMr2LNzBfyt UujVyM/AR1nPMh85g+Tvr9FRzEaVSpD8r2x3erJ3AtdSbYCsIEqEGPWX82IvFQjQ zm26bQoZjYl1sNa36+c5Sah9RtV3fkkiGM/fsXPcMJo97zd8Jg4ZkqAaM6zscRTB v13neSYEIMt9835jJxh8aWja4pYF/5bW6EsfQwIDAQABAoIBAH5z5PMbbr6EaFV6 tg8R05soLNqTkz11NFTgW4RokvT9VUPuOyglTXkaik6Qw9fyJ6AXLkUtKIWiQBbq 1cMIjecNQhl4SRT2visgkslnXENr3uqAGxojo4u1WFMRNbQA/5x4X7G/HJa8w8SU Loyax4ENjB2IiZ4hLdoC/8EGLzhc7VP6BhlYekeU35188VEyVk4Ls/6QTlqgFz/X 4DXOPNVeTtRap/6YtzTjmgrzP5aIqZA++qZMmRGVHoasb/f8qAXS3gyMXae1xpMA XFv6DGwd2P3V9LGPuy9MppB6MNSB3pJFGHtoodY7wI39t+omQmHhJQTIDWBMJGE1 Ml4gO7ECgYEAyx8kC01gT5uBh/grI3isgqWOYlAm7F2kpyupK8XMlnD6m1BmTQh7 rjlwbPQDDwTOsfcJY0UDnyRKKmUJvcZsJzEQfysl8tJO5/15SxXg44hBE0c2eqBb WsBIR0TKtocp+BdSClJu++QTUYSdPmaLqi9F7lnIeNcf+iLRR4CqdnkCgYEAxt5G jTEy5TH0b3vkGIqJBDOLbsRccCGmx9f4WCejJsQRyXbSgRKGPjWlG5UCeJW1LxN+ +j64bJDudBRqzgcuVZVdu/+k6vl6at1VxIRWd9MRuOk9JYf+YMvxR+i6dml0BPna D3npryH0iXQHu4IO6F1PtNiCG7ouPZeyL+g3hJsCgYBuolePkGWU9q5m0NUuTNwp jOMwyVdqBtdX9n/+R45XotHdJr2R170F+GMz9PR1ibjLVjLWzxBZ7fo3fTEBHMJr 1l2V5nqU99fipD0cmJ4VUHGhfng98nnPxEuaBe4j3RsO9iTJWnz41hFvpTvAcTpB R95fJKf8qa/RHoW+3GX8gQKBgFLa/xgKfIMDei0MuC8FYSrP8vL2evD5BEzVDZJl CVO4cxS2HeRK/IVkwmKohbwJ29A+VjQa96m8BK12aD1ovoRH1CLk0yhXQwrNJtPW s1P/K64X9zLw4yofLmrgave03fLIynKSP6uJASJXpnUYLe/gGLpnTmYQ/v0Ie+P7 402rAoGBAKdrA+ZpL0gY1D/RZ34OokkcA+xiR5jyUODM4L95gJVuKz+N1IZN9DiV 6oPBnSg24nxBHAdAKco0qQUOZtsvfiZCkZbMxcKaz7kI/ovttREZ4BQY74pga6Hk oCUHskJ9jhaei57irMB4VU68ZY33+NqXS+yPIR1XoKpmeipjaLQH -----END RSA PRIVATE KEY----- lua-resty-core-0.1.31/t/cert/ocsp/cfssl/intermediate_ca.csr000066400000000000000000000020361474236722600235710ustar00rootroot00000000000000-----BEGIN CERTIFICATE REQUEST----- MIIC0jCCAboCAQAwgYwxCzAJBgNVBAYTAkNBMRAwDgYDVQQIEwdPbnRhcmlvMQ8w DQYDVQQHEwZPdHRhd2ExEjAQBgNVBAoTCUx1YSBOZ2lueDEiMCAGA1UECxMZTHVh IE5naW54IEludGVybWVkaWF0ZSBDQTEiMCAGA1UEAxMZTHVhIE5naW54IEludGVy bWVkaWF0ZSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ3KctyK sOBO9QSNgbeT9fu9JRx7drAbxbvVDNPus/5sEqotQfwD3kgwBKVKbUEz5NoHWiQd htSKR+aXGFOiPmDs0NNlz5rZUZRcYsz95cfH+iSZzMNfeGA9yTmss/Z/p4yn6J0t vxMKXraKQiqx8IdBbEHdKh8e/EbqI0yjK9izcwX8rVLo1cjPwEdZzzIfOYPk76/R UcxGlUqQ/K9sd3qydwLXUm2ArCBKhBj1l/NiLxUI0M5tum0KGY2JdbDWt+vnOUmo fUbVd35JIhjP37Fz3DCaPe83fCYOGZKgGjOs7HEUwb9d53kmBCDLffN+YycYfGlo 2uKWBf+W1uhLH0MCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4IBAQBWJcqNaqgqKDdy xsGJpK3oriWE+caQnM51OGLjSBqyUfGf9ObgvKIQWbsPL6uMtgldf3Ctb1tjrKcz 0Fe6I8Ea8zrHrwg+gpx5M+O8ZVQmdM6kCYvX0/fMLM3p8NKBG1ZInf5N/Q6ACIVw hkmjmgGIJ4Wqlgvc+qOr4P0AmNJytNh1fn9evRGeZ3cskdgLXqqV5fC8a+3EwcgU X6Wb5eNDRDnA6cOqnwBY6ovxoGAHhinOtMkcD1X4I5zfvkBNfUZiimewQHS/xjW3 4Pst9Cj7aOSfblKo5+4LJ8fZFvgap9Yyf+JwmvpZYXidwGQQkU3YuXxPSsEaNYYA HKk+W7eh -----END CERTIFICATE REQUEST----- lua-resty-core-0.1.31/t/cert/ocsp/cfssl/intermediate_ca.pem000066400000000000000000000027611474236722600235700ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIENTCCAx2gAwIBAgIUQDB0IZF7HnvGlF2VrPKOW/M04mYwDQYJKoZIhvcNAQEL BQAwfDELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8xDzANBgNVBAcTBk90 dGF3YTESMBAGA1UEChMJTHVhIE5naW54MRowGAYDVQQLExFMdWEgTmdpbnggUm9v dCBDQTEaMBgGA1UEAxMRTHVhIE5naW54IFJvb3QgQ0EwHhcNMjQwMzEwMTQxODAw WhcNNDkwMzA0MTQxODAwWjCBjDELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFy aW8xDzANBgNVBAcTBk90dGF3YTESMBAGA1UEChMJTHVhIE5naW54MSIwIAYDVQQL ExlMdWEgTmdpbnggSW50ZXJtZWRpYXRlIENBMSIwIAYDVQQDExlMdWEgTmdpbngg SW50ZXJtZWRpYXRlIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA ncpy3Iqw4E71BI2Bt5P1+70lHHt2sBvFu9UM0+6z/mwSqi1B/APeSDAEpUptQTPk 2gdaJB2G1IpH5pcYU6I+YOzQ02XPmtlRlFxizP3lx8f6JJnMw194YD3JOayz9n+n jKfonS2/EwpetopCKrHwh0FsQd0qHx78RuojTKMr2LNzBfytUujVyM/AR1nPMh85 g+Tvr9FRzEaVSpD8r2x3erJ3AtdSbYCsIEqEGPWX82IvFQjQzm26bQoZjYl1sNa3 6+c5Sah9RtV3fkkiGM/fsXPcMJo97zd8Jg4ZkqAaM6zscRTBv13neSYEIMt9835j Jxh8aWja4pYF/5bW6EsfQwIDAQABo4GdMIGaMA4GA1UdDwEB/wQEAwIBBjAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBTyYaPSfXE2gAY8vzZpIIYNOonSdDAfBgNV HSMEGDAWgBTp7DmFFvFN2pPodS1IrM9XM2EKPjA3BggrBgEFBQcBAQQrMCkwJwYI KwYBBQUHMAGGG2h0dHBzOi8vb2NzcC1yZXNwb25kZXIudGVzdDANBgkqhkiG9w0B AQsFAAOCAQEAxiW331eII3W71aedBZPTH1c1axyHoN+hkWb8hL3Whg0K2ftm6SKJ uIi4dIYc9qbjfvIpbC/jkMGdy5tWu4m0RNBESIKc//kce0NBOQDUXH3Qp8G7qhUx J+MvAsDey4Iv/Jh1olwgiB7lVIm7gwdQSzY0XcFfxKJ+lvckv3sh8oI5/zprkJ0n y1QIrsJ1fB0maOtxF/DF2u4s2h2REPqvAIrxXZmnog+DOwG7vwjWcosEsX9qQJC7 Ho8X6+vHUENW9tpvlCmG+Nrci7T+p5s2DLUrq5gcmZkNGhCdjk3gMyeBjYgRTXUI 5KutV99z9qVO2wNB7HQz1/Q5Y5cB4Nr4Jw== -----END CERTIFICATE----- lua-resty-core-0.1.31/t/cert/ocsp/cfssl/intermediate_ca_csr.json000066400000000000000000000003671474236722600246270ustar00rootroot00000000000000{ "CN": "Lua Nginx Intermediate CA", "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "CA", "L": "Ottawa", "O": "Lua Nginx", "OU": "Lua Nginx Intermediate CA", "ST": "Ontario" } ] } lua-resty-core-0.1.31/t/cert/ocsp/cfssl/leaf-bundle.pem000066400000000000000000000105721474236722600226300ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIEYjCCA0qgAwIBAgIUAoYyuXu96S6RvXoSk2udnewBcmMwDQYJKoZIhvcNAQEL BQAwgYwxCzAJBgNVBAYTAkNBMRAwDgYDVQQIEwdPbnRhcmlvMQ8wDQYDVQQHEwZP dHRhd2ExEjAQBgNVBAoTCUx1YSBOZ2lueDEiMCAGA1UECxMZTHVhIE5naW54IElu dGVybWVkaWF0ZSBDQTEiMCAGA1UEAxMZTHVhIE5naW54IEludGVybWVkaWF0ZSBD QTAgFw0yNDAzMTAxNDI3MDBaGA8yMTI0MDIxNTE0MjcwMFowcjELMAkGA1UEBhMC VVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28x ETAPBgNVBAoTCEN1c3RvbWVyMRAwDgYDVQQLEwdXZWJzaXRlMREwDwYDVQQDEwh0 ZXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPbhwznauUQ4 K7smP0GUX7a4toKxMboTr0NNMMDlA+98dKMMWhSe3/eJUqUr0zFF59rFqwA1bWUK i67zHbIZnlWvfFV8lq2QuXt5CBeUBAT00YHdPb6pdYdWHZ32tSuqJpAVEqtbuya6 K85hBMT37yfxu58LreGSkKvwVOBoKFQzHZVDvYRs+hX8mHBqhAy0AiNfrf3AbdqD sI1p8YPr2k8varTE6lpUlhcO+dYnZHhyC8mDk5AD0kAgsnH0VvmRZwZPZmcmkeM0 aZJFdi++wmetlSv9DpEDzSVNHRuQaHEyq70jq/WKFJUlGtu6i/GhsGciSHnGfmXD qWGabXGX3L0CAwEAAaOB0jCBzzAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYI KwYBBQUHAwEwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUmZFUgNg7zMS9YorjH6KC hHmgmE0wHwYDVR0jBBgwFoAU8mGj0n1xNoAGPL82aSCGDTqJ0nQwNwYIKwYBBQUH AQEEKzApMCcGCCsGAQUFBzABhhtodHRwczovL29jc3AtcmVzcG9uZGVyLnRlc3Qw IQYDVR0RBBowGIIIdGVzdC5jb22CDHd3dy50ZXN0LmNvbTANBgkqhkiG9w0BAQsF AAOCAQEAfCbc7XXaLVMt0JCOcON4yzY+0GZ9RG6O/QBTFd25YfUxruvIHaDTcuAK tO8Q/iO/jybOHau9mwzwBe2aHhlKGYMJyvXlsQrGspcFsoyX8m5oXH3mBQhw1YhK cjNZGDNq4c8m+2EU2nFmHAQd+/inGg3N4dtBLdiE8jlhb+Cfdaa1l7YRHgD4KafY Oj5udG6FuOypcRoRerkUmizpgGofErHXmfTo14uo4FNxOhjJ57JPEBpf1Xq61k2L QTptCbpSij4ElgWMAhNhBRpp11nfg37vP/wbxOInZK4oCzf3s0OAlKvCc01QBvIr K59xzh9DRxpLjHsXphp9/XcFIlXfwQ== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIENTCCAx2gAwIBAgIUQDB0IZF7HnvGlF2VrPKOW/M04mYwDQYJKoZIhvcNAQEL BQAwfDELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8xDzANBgNVBAcTBk90 dGF3YTESMBAGA1UEChMJTHVhIE5naW54MRowGAYDVQQLExFMdWEgTmdpbnggUm9v dCBDQTEaMBgGA1UEAxMRTHVhIE5naW54IFJvb3QgQ0EwHhcNMjQwMzEwMTQxODAw WhcNNDkwMzA0MTQxODAwWjCBjDELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFy aW8xDzANBgNVBAcTBk90dGF3YTESMBAGA1UEChMJTHVhIE5naW54MSIwIAYDVQQL ExlMdWEgTmdpbnggSW50ZXJtZWRpYXRlIENBMSIwIAYDVQQDExlMdWEgTmdpbngg SW50ZXJtZWRpYXRlIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA ncpy3Iqw4E71BI2Bt5P1+70lHHt2sBvFu9UM0+6z/mwSqi1B/APeSDAEpUptQTPk 2gdaJB2G1IpH5pcYU6I+YOzQ02XPmtlRlFxizP3lx8f6JJnMw194YD3JOayz9n+n jKfonS2/EwpetopCKrHwh0FsQd0qHx78RuojTKMr2LNzBfytUujVyM/AR1nPMh85 g+Tvr9FRzEaVSpD8r2x3erJ3AtdSbYCsIEqEGPWX82IvFQjQzm26bQoZjYl1sNa3 6+c5Sah9RtV3fkkiGM/fsXPcMJo97zd8Jg4ZkqAaM6zscRTBv13neSYEIMt9835j Jxh8aWja4pYF/5bW6EsfQwIDAQABo4GdMIGaMA4GA1UdDwEB/wQEAwIBBjAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBTyYaPSfXE2gAY8vzZpIIYNOonSdDAfBgNV HSMEGDAWgBTp7DmFFvFN2pPodS1IrM9XM2EKPjA3BggrBgEFBQcBAQQrMCkwJwYI KwYBBQUHMAGGG2h0dHBzOi8vb2NzcC1yZXNwb25kZXIudGVzdDANBgkqhkiG9w0B AQsFAAOCAQEAxiW331eII3W71aedBZPTH1c1axyHoN+hkWb8hL3Whg0K2ftm6SKJ uIi4dIYc9qbjfvIpbC/jkMGdy5tWu4m0RNBESIKc//kce0NBOQDUXH3Qp8G7qhUx J+MvAsDey4Iv/Jh1olwgiB7lVIm7gwdQSzY0XcFfxKJ+lvckv3sh8oI5/zprkJ0n y1QIrsJ1fB0maOtxF/DF2u4s2h2REPqvAIrxXZmnog+DOwG7vwjWcosEsX9qQJC7 Ho8X6+vHUENW9tpvlCmG+Nrci7T+p5s2DLUrq5gcmZkNGhCdjk3gMyeBjYgRTXUI 5KutV99z9qVO2wNB7HQz1/Q5Y5cB4Nr4Jw== -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDyDCCArCgAwIBAgIUUw9rlqc2DnJNFZ9gw/zRLPRQ4zMwDQYJKoZIhvcNAQEL BQAwfDELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8xDzANBgNVBAcTBk90 dGF3YTESMBAGA1UEChMJTHVhIE5naW54MRowGAYDVQQLExFMdWEgTmdpbnggUm9v dCBDQTEaMBgGA1UEAxMRTHVhIE5naW54IFJvb3QgQ0EwHhcNMjQwMzEwMTQxODAw WhcNMjkwMzA5MTQxODAwWjB8MQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJp bzEPMA0GA1UEBxMGT3R0YXdhMRIwEAYDVQQKEwlMdWEgTmdpbngxGjAYBgNVBAsT EUx1YSBOZ2lueCBSb290IENBMRowGAYDVQQDExFMdWEgTmdpbnggUm9vdCBDQTCC ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOFPnbLvAgFfk8oZ/s9VBUie h+wlELquwHhh+XX9w/JxMlvNzfDYyJhA90iZJ7PL88Byz/+/1Kjzw1mS7vypSGiN u+NFt2Yp+BKuG/U327vh0yPgn1aOOtVpSjJyhhu585hJUkQNOHEJvzPy4Wo0EuxM DNB7aPhhBhi4yUlTDj2N8756rm0TFn8xp+XDDjfW1XJWR51cIcDXkfRDGMAqTf5o F4xZQtjubxz4zO3rUZ9nNxCFz9+9GENIgtlJFAeLbV/Xdd6G8Kqqa08mR/RZdV9V 7siSyDAeWoWsMnJOyX/TQdnQCfbnYpRhDtbi4mOkrW2Bf/SMb1uO0LRTec/rpBcC AwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O BBYEFOnsOYUW8U3ak+h1LUisz1czYQo+MA0GCSqGSIb3DQEBCwUAA4IBAQDHySN4 lWLHa12vYPvRVLNeWq3RaHQfKc2F2PhHriGCegY4lyZJqfC0XGI4LBnJ5GK//D0B Hb8jcbGyortGBEwGuqjuOMdv0HOWibqZ7LPZ98GegtAjAJWMp/sQXkIYiRM8hlNC pl9Vp9vsnUjfCrMaLVkZCC2Nwixc5mhSeH0aYHxxFwqh88oWbXzW7xobcTaYx/1P kPdCy+jiBMCZII7J1u/e1B0J1VFad+IVJpQW+DzVIzJz9ClNAsJZjx1BBwIJGGEZ fS1XXw+HgGeH2cVFnThMy0PIvx70b//GxEoXwuJhL2+z/tNhRRBN2eMa2zrZS94k z+yCDRXP/rDxf+b7 -----END CERTIFICATE----- lua-resty-core-0.1.31/t/cert/ocsp/cfssl/leaf-key.pem000066400000000000000000000032171474236722600221450ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEA9uHDOdq5RDgruyY/QZRftri2grExuhOvQ00wwOUD73x0owxa FJ7f94lSpSvTMUXn2sWrADVtZQqLrvMdshmeVa98VXyWrZC5e3kIF5QEBPTRgd09 vql1h1Ydnfa1K6omkBUSq1u7JrorzmEExPfvJ/G7nwut4ZKQq/BU4GgoVDMdlUO9 hGz6FfyYcGqEDLQCI1+t/cBt2oOwjWnxg+vaTy9qtMTqWlSWFw751idkeHILyYOT kAPSQCCycfRW+ZFnBk9mZyaR4zRpkkV2L77CZ62VK/0OkQPNJU0dG5BocTKrvSOr 9YoUlSUa27qL8aGwZyJIecZ+ZcOpYZptcZfcvQIDAQABAoIBAGP/I6UeW6YvHj9q iXqVj4MiJAKhpOOar4WSEWpAGKz6+v9DtITfqRXJUGlIa/1sNDIfmFi4Szv+3n8Z R/DogYJxVuoFUb6xfP9vEYEDWfFr/CQeqbC9ULZlgg+GavFptL7tWieAOzi/dZjd ISJqzjqepgEQqPhR9jk+WhKe/Z7EXcuLDEHBVyHGoN9ss60jppbRzvpB7etqS/iV ZPw7Nu2Rd4SWvGx0gah4rXBGgS5YG+pM2oPp3telF0yMVFLXGMN6WxyiULIrrtyh zBxRhdmSKjbodZNYun90FF2wynD666SHzi856NHqJPySL3Cs9sMESpKGxFDA9ZQM XD+Nkr0CgYEA92sgmnYk4OinG577S9vHlq3N8RufDNtENCpK/hNAYYhW/CTj22qx p+q9vIx5qGSNkgVpq3uINUzgJtIbRCvFuip8EKQlfSfMWGOVqo8qIWHurQcFSipa X9TdHdU/Ega3GjOQ07Lp69lg8PUB/2lckc5cY0NgARKuSGMkBYO7Y/8CgYEA/3He 773w/DSUMj2TpNeKLc9tofTmBLNd7aNJ3vNB3lINgvpTwRtuNxT8Onji9xTG5R58 rCx5Md4uPdvRY2+M5Yfr6+jGkVF2qH5jVKNyyVzF5pnE/KMWlE2bMcNjpnae+atB eygh9RAGt8biZ2AUXWiIgW/7PXnq0ROVXrhPT0MCgYA9+2Zli6ddeKs0bjWCIYL0 qoHnHwZPUDbb4qR61hPQ2zj/XbZ/Z1EuQc5ah86KcvZMWHLKdN4AjEuzLfuKrnSQ WMhP2u9RVUEJ+5io68igKEqEqjeXBtkxHMBwEtYEDA6ez8A+aJnVbdWtR5PCioCY PlxCucQ5QJbMp5mEkCXHvQKBgQDNExgNlInRkEyhgPn1Tu0qFetIKJo5j96Kl5sI mHZ7C5i5XEq9L05ufjR4pPBhuJZs/urMNvAdbufk1YLmt3mAFHz86eXwaFxArScF nirbKdXfaffRcwT/jsZXTyvDSlwayLhLLU8FtRYPmGXO5D21N+TPNZ2YHza7H2O9 pW5WjQKBgQCf+n6L6EZ0Nd5Ci5hQNSNyG/ptFlfPF250jEn95Ikln4ctT3fzuyP8 pOqbcp0+sM1TyQavXh4DnE41DGt5QIOdCAwpxe5ZdUXlLS/0+dO/R0kglwMbqRHQ zx7iwdrFGuVszMbVUBncOfje6NT4BKC9E3Ai2RX2nNPYeTP1XWDEYg== -----END RSA PRIVATE KEY----- lua-resty-core-0.1.31/t/cert/ocsp/cfssl/leaf.csr000066400000000000000000000021021474236722600213550ustar00rootroot00000000000000-----BEGIN CERTIFICATE REQUEST----- MIIC6zCCAdMCAQAwcjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWEx FjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xETAPBgNVBAoTCEN1c3RvbWVyMRAwDgYD VQQLEwdXZWJzaXRlMREwDwYDVQQDEwh0ZXN0LmNvbTCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBAPbhwznauUQ4K7smP0GUX7a4toKxMboTr0NNMMDlA+98 dKMMWhSe3/eJUqUr0zFF59rFqwA1bWUKi67zHbIZnlWvfFV8lq2QuXt5CBeUBAT0 0YHdPb6pdYdWHZ32tSuqJpAVEqtbuya6K85hBMT37yfxu58LreGSkKvwVOBoKFQz HZVDvYRs+hX8mHBqhAy0AiNfrf3AbdqDsI1p8YPr2k8varTE6lpUlhcO+dYnZHhy C8mDk5AD0kAgsnH0VvmRZwZPZmcmkeM0aZJFdi++wmetlSv9DpEDzSVNHRuQaHEy q70jq/WKFJUlGtu6i/GhsGciSHnGfmXDqWGabXGX3L0CAwEAAaA0MDIGCSqGSIb3 DQEJDjElMCMwIQYDVR0RBBowGIIIdGVzdC5jb22CDHd3dy50ZXN0LmNvbTANBgkq hkiG9w0BAQsFAAOCAQEACBrQqSJVP2h83H3VVb3IF+Diy4m209qRFOdXn79cQ646 aMscLPKpS4BXaiTvSUckyzNlL7q+QRjSYcfhc7XuzQ8FtiR+oaPCmSpmYrFC7tGq 9bE4ZajI2QWGkK6UiPBh5HD+KxFlKMktGeBd6wG5EscREafNAHaDSqFaFOEguH6D GW29oX4Qn1Pm5Cs0OwGjWOg4KvjknVnRF6LC6WXy6NQ7Kc/fqVRFlqLv3Vn8pWXE ryNlajq429O1vvNBAXjPdfOjKWVSz1CoeBgVwdGG8nC9FdvgWBc1di8Z/X6gbypk FAHTY6FsBSFLsIMqqg/QNcUSWwW5Espmi2qvDQ6hHQ== -----END CERTIFICATE REQUEST----- lua-resty-core-0.1.31/t/cert/ocsp/cfssl/leaf.pem000066400000000000000000000030561474236722600213600ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIEYjCCA0qgAwIBAgIUAoYyuXu96S6RvXoSk2udnewBcmMwDQYJKoZIhvcNAQEL BQAwgYwxCzAJBgNVBAYTAkNBMRAwDgYDVQQIEwdPbnRhcmlvMQ8wDQYDVQQHEwZP dHRhd2ExEjAQBgNVBAoTCUx1YSBOZ2lueDEiMCAGA1UECxMZTHVhIE5naW54IElu dGVybWVkaWF0ZSBDQTEiMCAGA1UEAxMZTHVhIE5naW54IEludGVybWVkaWF0ZSBD QTAgFw0yNDAzMTAxNDI3MDBaGA8yMTI0MDIxNTE0MjcwMFowcjELMAkGA1UEBhMC VVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28x ETAPBgNVBAoTCEN1c3RvbWVyMRAwDgYDVQQLEwdXZWJzaXRlMREwDwYDVQQDEwh0 ZXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPbhwznauUQ4 K7smP0GUX7a4toKxMboTr0NNMMDlA+98dKMMWhSe3/eJUqUr0zFF59rFqwA1bWUK i67zHbIZnlWvfFV8lq2QuXt5CBeUBAT00YHdPb6pdYdWHZ32tSuqJpAVEqtbuya6 K85hBMT37yfxu58LreGSkKvwVOBoKFQzHZVDvYRs+hX8mHBqhAy0AiNfrf3AbdqD sI1p8YPr2k8varTE6lpUlhcO+dYnZHhyC8mDk5AD0kAgsnH0VvmRZwZPZmcmkeM0 aZJFdi++wmetlSv9DpEDzSVNHRuQaHEyq70jq/WKFJUlGtu6i/GhsGciSHnGfmXD qWGabXGX3L0CAwEAAaOB0jCBzzAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYI KwYBBQUHAwEwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUmZFUgNg7zMS9YorjH6KC hHmgmE0wHwYDVR0jBBgwFoAU8mGj0n1xNoAGPL82aSCGDTqJ0nQwNwYIKwYBBQUH AQEEKzApMCcGCCsGAQUFBzABhhtodHRwczovL29jc3AtcmVzcG9uZGVyLnRlc3Qw IQYDVR0RBBowGIIIdGVzdC5jb22CDHd3dy50ZXN0LmNvbTANBgkqhkiG9w0BAQsF AAOCAQEAfCbc7XXaLVMt0JCOcON4yzY+0GZ9RG6O/QBTFd25YfUxruvIHaDTcuAK tO8Q/iO/jybOHau9mwzwBe2aHhlKGYMJyvXlsQrGspcFsoyX8m5oXH3mBQhw1YhK cjNZGDNq4c8m+2EU2nFmHAQd+/inGg3N4dtBLdiE8jlhb+Cfdaa1l7YRHgD4KafY Oj5udG6FuOypcRoRerkUmizpgGofErHXmfTo14uo4FNxOhjJ57JPEBpf1Xq61k2L QTptCbpSij4ElgWMAhNhBRpp11nfg37vP/wbxOInZK4oCzf3s0OAlKvCc01QBvIr K59xzh9DRxpLjHsXphp9/XcFIlXfwQ== -----END CERTIFICATE----- lua-resty-core-0.1.31/t/cert/ocsp/cfssl/leaf_csr.json000066400000000000000000000004221474236722600224110ustar00rootroot00000000000000{ "CN": "test.com", "hosts": [ "test.com", "www.test.com" ], "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "US", "L": "San Francisco", "O": "Customer", "OU": "Website", "ST": "California" } ] } lua-resty-core-0.1.31/t/cert/ocsp/cfssl/ocsp-key.pem000066400000000000000000000032171474236722600222020ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEAq3Crdfl19L2Tffp2+1R74p0iR/51RLgX2QGoh8PdWRf7GTo8 Jsho/7FSUaWdfSLmsHSpZCg6eZpXJqCJ67EzZK2I8bm1tv+9m7V6FLUn2mBsEQWB b8zPIc7dcMhALc1/+9dDJB781ZEt6GiV8vDp8ymErBtb2l2YpJuU7vXX0Kj7bBL2 jx+mn5YGDL3RW4TaFF8Eh6hXHFMKH7STL/XUUyNx4s7H4VDFZULBSLU3g7p37b5w O0ni8IZIhx2E459vFp8Cpv2Z3jTpXOPAgY+Br9lXBd/yEFN5pkzt6OrfLm5wV+ck 3HHLy4tsY2SMz5V/w6aQJmoeP7Xxoev8/m5GNQIDAQABAoIBAF1phbNBWpkg1oWU /FGTRfFDBxPNPR5VZIEUWzymZywNWf7z8SR8nGF9v8nHAJnXc3UAC/ALz1jE1Omy HZQzuDoKKAz10GJG1IxMBJnV30IouZlIs680HERij9vM8NNEHpEdSHMdA0xmz2nL 2rBFvmOE4spYGeNQjkRalXrir1X8aLYBoe3iPY9UzHRFq0shUobjuwjfCVi3060F m3+Z5BhHvjxSJLe4g1iFqeg/eiIwuuz8NgoilGAgPXSmYRyBIqWBGSjaKLL5Immh l+0LKpE9Izz1AVH/1dWdg+CKmN/vE/W94LMHdxNtCReVSDAbDulqPkDZj9uR6sD8 ilM4Yt0CgYEA1OCymV0xC3b/88yRGIuj8SQR7VsAyCKUpx7MNyUWzILj39+QewW2 6rvnxy7yHJONkGPZsqDP3pWSElRjUt1Q2Xe5hOmL51BxmIaMO80nV7QIpWnzZN5+ +aQYZ51taRgCRaC4D6OYKFeUeHrWrt6bAzDBQ8e+B2ooT+gA9nT2VbcCgYEAzisf RPlo8znydeSYojzzjyFdRYojeWJU9n5kkvo8d5IbqfxNDcrlOqtbAKderaQc1nbH olKaM9LheYuLxwb40A7sCfeavISPH0snjalWUq/KGEbKKNlptf0IpXraSIY+8fdw /fk1jzcrk77QLrKxICAYrm10xlp2S0v2zVRgY3MCgYEAy5TT2I1iAPfeEXbacCHj OBLpvhegqMVBao2ueTJUGmM2r/vq/WvaoaPwJfHEgwWthZ+oKwdVpCVgW30uu6mB z2eLGQwMyruI13gdFne9H0fCWQb5SMbroayH1lecsbvPOG1aeUJXmoUfLRU0yGmE z0lKGpskJY0lXj2e5hO3HQMCgYBWsvurXdcssamsuj0VvNwPzNAUdksEuL1SC0Tw KhtTjTXk/hzJOBG94mGanMfL7b/S0JCTSnleYcg//NcDE4N+u0e3yVBhBr3JQymX ASc0DojGPL62/vbdeVMxg8BXz1yZFJ2HsE09tM22i/+wI6UpBVZbw9vfrhsg/wkC wADo0QKBgQCs4t7HnOtZd4TchUtjWkJ9wJ6yzeD56H/0XGoSUbjyD4ls46ZlDUUM XcyrBOGkQ6yfpQS9+NNpyC5TA/mCKS9JEe0RULGnpaU4VOJ3W2ZCNxjp7eIPK29o Q/9jmKqiu5rEWlJ79bC+NhE8RVWosA6t56RUjutDn8W6PG8q7yadiA== -----END RSA PRIVATE KEY----- lua-resty-core-0.1.31/t/cert/ocsp/cfssl/ocsp-response-good-response.der000066400000000000000000000032701474236722600260220ustar00rootroot000000000000000 0 +00001 0 UCA10UOntario10 UOttawa10U  Lua Nginx1!0U Lua Nginx OCSP Responder1!0ULua Nginx OCSP Responder20240310143100Z0w0u0M0 +cxPNmGka#<ܷa}q6<6i :t2{.zkrc20240310140000Z20240314140000Z0  *H  ub6sH 6eMϥ\Ic@y;okX[UY*P݅8$);lw&EVK_9X!wma?ʂ K rgDfz*z8]\tryBI5ʾp6L}T&e}^ (3HtiqɧVemkD0wIq=5j]P[Iݓ(twqH?`0\0X0@{nFA.frxA{0  *H  01 0 UCA10UOntario10 UOttawa10U  Lua Nginx1"0 U Lua Nginx Intermediate CA1"0 ULua Nginx Intermediate CA0  240310142700Z21240215142700Z01 0 UCA10UOntario10 UOttawa10U  Lua Nginx1!0U Lua Nginx OCSP Responder1!0ULua Nginx OCSP Responder0"0  *H 0 puu}vT{"GuDY:<&hRQ}"td(:yW&3d񹵶z'`lo!p@-C$Ց-h)[]Шl [_WS /S#qPeBH7wp;IHo4\WSyL.npW$qˋlcdϕæ&j?nF500U0U% 0 + 0 U00UaŪoHֳQ0U#0a}q6<6i :t07++0)0'+0https://ocsp-responder.test0  *H  , 'ogb ;#bN?XC[Gzp%Gz={ cZwGMch,[ycO٩(˅:qؒ"VV8_?y-U= /)YFc,IO!"c^N:pJXcOŞ97gMqz v!ZgAT!jѴrsH$d^0Z0V0>(_b~ZJuWpx%0  *H  01 0 UCA10UOntario10 UOttawa10U  Lua Nginx1"0 U Lua Nginx Intermediate CA1"0 ULua Nginx Intermediate CA0 200418194000Z 210418194000Z01 0 UCA10UOntario10 UOttawa10U  Lua Nginx1!0U Lua Nginx OCSP Responder1!0ULua Nginx OCSP Responder0"0  *H 0 BDiI,9@oǦL쒢y0}s_ռl fw-)mWT&M|MA0T{0>awSP@c;<=-?**oVYY0Yx}|25 j^<mU>Xv.%F4VVudwiFub]@Z 8qȘ`eXȲ5߼?ieq00U0U% 0 + 0 U00U153k`0U#0=Tf=wԚ07++0)0'+0https://ocsp-responder.test0  *H   ^"b.g930- AJuѴXtX%>P SA25B* ZrP6DN#NP5Tz˟'3diM,vRf>3K;N'hOh;G~z ✣v̕fϵQ3B#*C8><Nj.t$Z zpb'I'1`[=0/aWҷ!lua-resty-core-0.1.31/t/cert/ocsp/cfssl/ocsp.csr000066400000000000000000000020361474236722600214200ustar00rootroot00000000000000-----BEGIN CERTIFICATE REQUEST----- MIIC0DCCAbgCAQAwgYoxCzAJBgNVBAYTAkNBMRAwDgYDVQQIEwdPbnRhcmlvMQ8w DQYDVQQHEwZPdHRhd2ExEjAQBgNVBAoTCUx1YSBOZ2lueDEhMB8GA1UECxMYTHVh IE5naW54IE9DU1AgUmVzcG9uZGVyMSEwHwYDVQQDExhMdWEgTmdpbnggT0NTUCBS ZXNwb25kZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrcKt1+XX0 vZN9+nb7VHvinSJH/nVEuBfZAaiHw91ZF/sZOjwmyGj/sVJRpZ19IuawdKlkKDp5 mlcmoInrsTNkrYjxubW2/72btXoUtSfaYGwRBYFvzM8hzt1wyEAtzX/710MkHvzV kS3oaJXy8OnzKYSsG1vaXZikm5Tu9dfQqPtsEvaPH6aflgYMvdFbhNoUXwSHqFcc UwoftJMv9dRTI3HizsfhUMVlQsFItTeDunftvnA7SeLwhkiHHYTjn28WnwKm/Zne NOlc48CBj4Gv2VcF3/IQU3mmTO3o6t8ubnBX5yTcccvLi2xjZIzPlX/DppAmah4/ tfGh6/z+bkY1AgMBAAGgADANBgkqhkiG9w0BAQsFAAOCAQEAHJ5WraOQEhwMJpyB wjCSHydomosRpoawtu5OsUt1E7iZ4P4DFRFKUy6iYRkXgacUnKtBBVqjECJa665b oh7Q2YE655dyTLL7tI2uyQpGXV1Ko3YH6S/UnojZKMIbenCSnBYB1FklRG4MmfBg KSCqVcViCdKNmAleF+i0xUvEkVfCHG9hMkuKhfN8T22Vq350fPRpyVuX0HD7uJC2 9j+ZLMZDMQjhnuioCf4aTKB1dXZHSwgvhJ58oYhsTGgP3fQMa68hHYIWWNILsJCz Jt6pf5NNfYAigbnY/78SuDGi58JEH+5TAC/dSM1uZe5k4kXuwpDlclzUgctEiVjs NEBM1Q== -----END CERTIFICATE REQUEST----- lua-resty-core-0.1.31/t/cert/ocsp/cfssl/ocsp.pem000066400000000000000000000030361474236722600214130ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIEWDCCA0CgAwIBAgIUe+huEvFGQccuZsZy8aDHeEGGtHswDQYJKoZIhvcNAQEL BQAwgYwxCzAJBgNVBAYTAkNBMRAwDgYDVQQIEwdPbnRhcmlvMQ8wDQYDVQQHEwZP dHRhd2ExEjAQBgNVBAoTCUx1YSBOZ2lueDEiMCAGA1UECxMZTHVhIE5naW54IElu dGVybWVkaWF0ZSBDQTEiMCAGA1UEAxMZTHVhIE5naW54IEludGVybWVkaWF0ZSBD QTAgFw0yNDAzMTAxNDI3MDBaGA8yMTI0MDIxNTE0MjcwMFowgYoxCzAJBgNVBAYT AkNBMRAwDgYDVQQIEwdPbnRhcmlvMQ8wDQYDVQQHEwZPdHRhd2ExEjAQBgNVBAoT CUx1YSBOZ2lueDEhMB8GA1UECxMYTHVhIE5naW54IE9DU1AgUmVzcG9uZGVyMSEw HwYDVQQDExhMdWEgTmdpbnggT0NTUCBSZXNwb25kZXIwggEiMA0GCSqGSIb3DQEB AQUAA4IBDwAwggEKAoIBAQCrcKt1+XX0vZN9+nb7VHvinSJH/nVEuBfZAaiHw91Z F/sZOjwmyGj/sVJRpZ19IuawdKlkKDp5mlcmoInrsTNkrYjxubW2/72btXoUtSfa YGwRBYFvzM8hzt1wyEAtzX/710MkHvzVkS3oaJXy8OnzKYSsG1vaXZikm5Tu9dfQ qPtsEvaPH6aflgYMvdFbhNoUXwSHqFccUwoftJMv9dRTI3HizsfhUMVlQsFItTeD unftvnA7SeLwhkiHHYTjn28WnwKm/ZneNOlc48CBj4Gv2VcF3/IQU3mmTO3o6t8u bnBX5yTcccvLi2xjZIzPlX/DppAmah4/tfGh6/z+bkY1AgMBAAGjga8wgawwDgYD VR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMJMAwGA1UdEwEB/wQCMAAw HQYDVR0OBBYEFBPZYcWqsm+j1OTwnv/2SM3Ws1HJMB8GA1UdIwQYMBaAFPJho9J9 cTaABjy/Nmkghg06idJ0MDcGCCsGAQUFBwEBBCswKTAnBggrBgEFBQcwAYYbaHR0 cHM6Ly9vY3NwLXJlc3BvbmRlci50ZXN0MA0GCSqGSIb3DQEBCwUAA4IBAQAs3SAT nif5b+ii4ItnpGIcniA7sYgjv+6hYrTUTj+vWENbmEd6FAJwJYJHrno99qfN2t97 CWNadxkRR/qN0xATxE0dY2gsxBpbwICoA3k8lz/9VBl+p3g9kOqbSQYxrxOEoQov EvlV/n8zCq8eOjoHU/IwV3IP1Ik0KKj8rAeIGzV/M403LhahyxlZZVF5Qo7MszQ5 8hwPHSfgcbCRh/XSS6Y8N6RDvBVUoHofeikXsy+di7cYfT1PEC2bhdsbLi/0WvDm ZrotJOHoZrhqEuEgMrMDg5E8s17QLL+Vd078DMSSqG6HDPwMckdjDMhlI+OBZKwc Dnb4OMHJnL+of2Kh -----END CERTIFICATE----- lua-resty-core-0.1.31/t/cert/ocsp/cfssl/ocsp_csr.json000066400000000000000000000003651474236722600224540ustar00rootroot00000000000000{ "CN": "Lua Nginx OCSP Responder", "key": { "algo": "rsa", "size": 2048 }, "names": [ { "C": "CA", "L": "Ottawa", "O": "Lua Nginx", "OU": "Lua Nginx OCSP Responder", "ST": "Ontario" } ] } lua-resty-core-0.1.31/t/cert/ocsp/chain.pem000066400000000000000000000224021474236722600204150ustar00rootroot00000000000000Certificate: Data: Version: 3 (0x2) Serial Number: 4 (0x4) Signature Algorithm: sha1WithRSAEncryption Issuer: C=US, ST=California, L=Default City, O=OpenResty, CN=signing-ca-2 Validity Not Before: Oct 16 03:27:09 2014 GMT Not After : Sep 22 03:27:09 2114 GMT Subject: C=US, ST=California, L=Default City, O=OpenResty, CN=test.com Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:c7:bd:50:99:71:46:af:93:22:85:ab:74:8b:5b: 19:74:af:3e:ad:d2:e1:17:3e:cb:5b:36:9c:8a:38: bd:1b:47:2d:8b:92:55:1d:fe:a6:72:92:78:00:de: 30:cb:a3:10:b5:92:aa:b8:e0:7b:44:9a:f5:99:89: 36:f4:84:20:81:e3:5c:76:00:9d:76:e7:b9:41:ab: 74:b6:14:9f:b2:94:b3:b6:48:a8:92:dc:09:e3:3d: 04:e3:5f:0f:5b:50:ad:0c:59:3a:88:06:39:2d:34: a6:52:2f:58:6f:53:1b:df:9f:98:ea:82:8d:52:60: b1:ef:6b:e9:f5:ad:29:87:45 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: 67:DF:28:25:D1:F8:83:36:28:EE:DB:41:63:E4:E0:3A:32:0D:EA:30 X509v3 Authority Key Identifier: keyid:B3:0B:F5:7D:51:16:51:7E:28:37:C3:A2:0F:1D:2F:10:C0:51:A3:B3 DirName:/C=US/ST=California/L=Default City/O=OpenResty/CN=signing-ca-1 serial:03 Authority Information Access: OCSP - URI:http://127.0.0.1:8888/ocsp?foo=1 Signature Algorithm: sha1WithRSAEncryption 37:29:3f:ed:d9:47:9a:51:36:a3:5b:00:85:66:de:51:4d:48: 2d:f8:bc:f1:5e:b4:fd:30:48:f0:25:ee:77:57:9c:f1:4b:0a: 4f:7e:96:1a:f8:48:76:23:46:8d:d6:f2:5e:1e:08:52:12:53: 08:07:9f:75:db:77:22:2e:7e:89:c2:2c:66:85:6b:df:e9:77: ca:23:6d:9a:af:87:8a:8c:27:37:1e:9e:55:92:8e:8a:a9:93: 24:41:a8:96:01:c0:65:93:8e:3d:7a:6c:bf:ed:c8:2a:f8:26: cc:00:17:b7:27:ca:85:6c:2e:d5:2a:0a:8d:f3:88:e8:26:48: e3:e8 -----BEGIN CERTIFICATE----- MIIDaTCCAtKgAwIBAgIBBDANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJVUzET MBEGA1UECBMKQ2FsaWZvcm5pYTEVMBMGA1UEBxMMRGVmYXVsdCBDaXR5MRIwEAYD VQQKEwlPcGVuUmVzdHkxFTATBgNVBAMTDHNpZ25pbmctY2EtMjAgFw0xNDEwMTYw MzI3MDlaGA8yMTE0MDkyMjAzMjcwOVowYDELMAkGA1UEBhMCVVMxEzARBgNVBAgT CkNhbGlmb3JuaWExFTATBgNVBAcTDERlZmF1bHQgQ2l0eTESMBAGA1UEChMJT3Bl blJlc3R5MREwDwYDVQQDEwh0ZXN0LmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw gYkCgYEAx71QmXFGr5Mihat0i1sZdK8+rdLhFz7LWzaciji9G0cti5JVHf6mcpJ4 AN4wy6MQtZKquOB7RJr1mYk29IQggeNcdgCddue5Qat0thSfspSztkioktwJ4z0E 418PW1CtDFk6iAY5LTSmUi9Yb1Mb35+Y6oKNUmCx72vp9a0ph0UCAwEAAaOCASsw ggEnMAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVk IENlcnRpZmljYXRlMB0GA1UdDgQWBBRn3ygl0fiDNiju20Fj5OA6Mg3qMDCBjgYD VR0jBIGGMIGDgBSzC/V9URZRfig3w6IPHS8QwFGjs6FopGYwZDELMAkGA1UEBhMC VVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFTATBgNVBAcTDERlZmF1bHQgQ2l0eTES MBAGA1UEChMJT3BlblJlc3R5MRUwEwYDVQQDEwxzaWduaW5nLWNhLTGCAQMwPAYI KwYBBQUHAQEEMDAuMCwGCCsGAQUFBzABhiBodHRwOi8vMTI3LjAuMC4xOjg4ODgv b2NzcD9mb289MTANBgkqhkiG9w0BAQUFAAOBgQA3KT/t2UeaUTajWwCFZt5RTUgt +LzxXrT9MEjwJe53V5zxSwpPfpYa+Eh2I0aN1vJeHghSElMIB59123ciLn6Jwixm hWvf6XfKI22ar4eKjCc3Hp5Vko6KqZMkQaiWAcBlk449emy/7cgq+CbMABe3J8qF bC7VKgqN84joJkjj6A== -----END CERTIFICATE----- Certificate: Data: Version: 3 (0x2) Serial Number: 3 (0x3) Signature Algorithm: sha1WithRSAEncryption Issuer: C=US, ST=California, L=Default City, O=OpenResty, CN=signing-ca-1 Validity Not Before: Oct 16 03:27:09 2014 GMT Not After : Sep 22 03:27:09 2114 GMT Subject: C=US, ST=California, L=Default City, O=OpenResty, CN=signing-ca-2 Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:d3:24:1c:92:a5:bb:00:d9:b1:fb:2b:1d:7a:32: a1:6c:49:eb:3c:2d:29:80:d6:65:8b:17:3a:f0:4b: dc:0c:57:fb:d5:31:68:a5:e4:54:86:55:f9:1b:a8: d7:7d:32:01:3b:cf:5c:38:2b:f5:bc:d3:8b:c8:b6: ab:76:65:32:e6:4b:d5:e4:fd:d1:92:c8:33:6a:74: f3:c7:ec:97:c3:c7:9f:e4:d5:55:75:b8:bd:39:ec: 2d:1f:c6:54:c8:2b:2d:17:e0:05:77:28:44:f7:dd: e1:6e:f0:59:05:51:f5:b9:b4:fe:be:ad:40:a6:d5: 9a:c1:64:e0:9b:dd:67:e5:f1 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Key Identifier: B3:0B:F5:7D:51:16:51:7E:28:37:C3:A2:0F:1D:2F:10:C0:51:A3:B3 X509v3 Authority Key Identifier: keyid:D2:30:71:56:50:A6:BC:21:C5:A1:A1:AB:11:A7:08:5B:EB:3A:A4:27 X509v3 Basic Constraints: CA:TRUE Signature Algorithm: sha1WithRSAEncryption 0c:61:c0:c7:11:c2:f0:39:f0:76:9d:4f:43:d4:90:54:1f:26: 3d:54:3d:77:5f:c0:b3:4a:c2:1b:b6:18:d2:12:8d:24:4d:76: f5:07:0b:14:3e:17:2d:42:ee:85:30:db:e3:4d:81:67:59:97: 0a:b3:bb:c5:27:ea:69:c6:ee:99:5c:44:36:53:3e:c4:47:68: f8:fe:c6:53:38:fb:e7:9a:0c:3c:6c:78:93:29:d2:49:7d:29: d0:61:6e:81:9b:d6:ec:1a:e2:3e:62:62:41:bc:6d:4d:33:91: 76:20:5e:32:70:08:3e:24:72:fe:b1:8a:83:57:04:19:b5:cb: 99:b7 -----BEGIN CERTIFICATE----- MIICkDCCAfmgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJVUzET MBEGA1UECBMKQ2FsaWZvcm5pYTEVMBMGA1UEBxMMRGVmYXVsdCBDaXR5MRIwEAYD VQQKEwlPcGVuUmVzdHkxFTATBgNVBAMTDHNpZ25pbmctY2EtMTAgFw0xNDEwMTYw MzI3MDlaGA8yMTE0MDkyMjAzMjcwOVowZDELMAkGA1UEBhMCVVMxEzARBgNVBAgT CkNhbGlmb3JuaWExFTATBgNVBAcTDERlZmF1bHQgQ2l0eTESMBAGA1UEChMJT3Bl blJlc3R5MRUwEwYDVQQDEwxzaWduaW5nLWNhLTIwgZ8wDQYJKoZIhvcNAQEBBQAD gY0AMIGJAoGBANMkHJKluwDZsfsrHXoyoWxJ6zwtKYDWZYsXOvBL3AxX+9UxaKXk VIZV+Ruo130yATvPXDgr9bzTi8i2q3ZlMuZL1eT90ZLIM2p088fsl8PHn+TVVXW4 vTnsLR/GVMgrLRfgBXcoRPfd4W7wWQVR9bm0/r6tQKbVmsFk4JvdZ+XxAgMBAAGj UDBOMB0GA1UdDgQWBBSzC/V9URZRfig3w6IPHS8QwFGjszAfBgNVHSMEGDAWgBTS MHFWUKa8IcWhoasRpwhb6zqkJzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUA A4GBAAxhwMcRwvA58HadT0PUkFQfJj1UPXdfwLNKwhu2GNISjSRNdvUHCxQ+Fy1C 7oUw2+NNgWdZlwqzu8Un6mnG7plcRDZTPsRHaPj+xlM4++eaDDxseJMp0kl9KdBh boGb1uwa4j5iYkG8bU0zkXYgXjJwCD4kcv6xioNXBBm1y5m3 -----END CERTIFICATE----- Certificate: Data: Version: 3 (0x2) Serial Number: 2 (0x2) Signature Algorithm: sha1WithRSAEncryption Issuer: C=US, ST=California, L=Default City, O=OpenResty, CN=root-ca Validity Not Before: Oct 16 03:27:09 2014 GMT Not After : Sep 22 03:27:09 2114 GMT Subject: C=US, ST=California, L=Default City, O=OpenResty, CN=signing-ca-1 Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:a0:3e:1a:4f:6c:b9:3d:ab:0f:02:de:da:82:92: ee:a2:69:88:80:ed:f2:b6:98:bc:c6:ee:d3:47:82: 4a:e7:d3:7f:55:68:5c:6d:9e:aa:ba:59:e3:5b:7f: 32:4f:79:44:4a:4f:13:e4:2e:3f:1f:98:10:a4:72: d5:f0:e7:44:8e:d4:a7:b9:fb:54:be:b6:fa:f7:dc: 9c:29:93:d4:9f:a1:5b:18:6e:68:93:91:1b:8c:a0: 4f:02:52:e9:9d:e8:98:f3:fd:67:da:78:4b:4f:d8: 2d:90:83:5c:0b:e5:fe:48:27:e4:ec:bb:99:26:06: 8e:34:fe:93:e4:d2:fc:97:57 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Key Identifier: D2:30:71:56:50:A6:BC:21:C5:A1:A1:AB:11:A7:08:5B:EB:3A:A4:27 X509v3 Authority Key Identifier: keyid:1D:2F:09:60:EB:E4:EA:B5:0B:52:A9:5C:5E:09:2B:DD:34:70:CF:BA X509v3 Basic Constraints: CA:TRUE Signature Algorithm: sha1WithRSAEncryption a6:16:2f:fc:13:67:5e:ce:0e:79:cb:b0:91:52:9b:9e:b5:9f: e1:fa:7d:78:f4:2a:93:f3:94:62:45:17:87:b9:0a:59:b9:a3: a9:75:51:ca:f0:04:6c:01:d1:3a:a9:dd:66:7d:27:7b:1e:4f: 48:3a:25:ea:a5:01:32:fc:87:4b:08:da:f8:f5:62:88:e8:b9: 94:c7:cb:ee:33:08:ab:2f:52:f4:4a:14:4f:ac:2d:a2:f8:de: c9:6f:95:b7:91:23:b9:ec:95:90:de:86:21:f5:6f:1b:cf:13: 47:77:78:dd:7a:16:e9:8b:cc:df:3d:45:8a:76:af:15:d1:9a: 37:a2 -----BEGIN CERTIFICATE----- MIICizCCAfSgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJVUzET MBEGA1UECBMKQ2FsaWZvcm5pYTEVMBMGA1UEBxMMRGVmYXVsdCBDaXR5MRIwEAYD VQQKEwlPcGVuUmVzdHkxEDAOBgNVBAMTB3Jvb3QtY2EwIBcNMTQxMDE2MDMyNzA5 WhgPMjExNDA5MjIwMzI3MDlaMGQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxp Zm9ybmlhMRUwEwYDVQQHEwxEZWZhdWx0IENpdHkxEjAQBgNVBAoTCU9wZW5SZXN0 eTEVMBMGA1UEAxMMc2lnbmluZy1jYS0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB iQKBgQCgPhpPbLk9qw8C3tqCku6iaYiA7fK2mLzG7tNHgkrn039VaFxtnqq6WeNb fzJPeURKTxPkLj8fmBCkctXw50SO1Ke5+1S+tvr33Jwpk9SfoVsYbmiTkRuMoE8C Uumd6Jjz/WfaeEtP2C2Qg1wL5f5IJ+Tsu5kmBo40/pPk0vyXVwIDAQABo1AwTjAd BgNVHQ4EFgQU0jBxVlCmvCHFoaGrEacIW+s6pCcwHwYDVR0jBBgwFoAUHS8JYOvk 6rULUqlcXgkr3TRwz7owDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQCm Fi/8E2dezg55y7CRUpuetZ/h+n149CqT85RiRReHuQpZuaOpdVHK8ARsAdE6qd1m fSd7Hk9IOiXqpQEy/IdLCNr49WKI6LmUx8vuMwirL1L0ShRPrC2i+N7Jb5W3kSO5 7JWQ3oYh9W8bzxNHd3jdehbpi8zfPUWKdq8V0Zo3og== -----END CERTIFICATE----- lua-resty-core-0.1.31/t/cert/ocsp/ocsp-req.der000066400000000000000000000001041474236722600210500ustar00rootroot000000000000000B0@0>0<0:0 +&!mF xw`% }QQ~(7â/Qlua-resty-core-0.1.31/t/cert/ocsp/ocsp-resp-no-certs.der000066400000000000000000000006041474236722600227670ustar00rootroot000000000000000 y0u +0f0b0̡f0d1 0 UUS10U California10U Default City10U  OpenResty10U signing-ca-220141016032709Z0Q0O0:0 +&!mF xw`% }QQ~(7â/Q20141016032709Z0  *H *R4DOv RnrTnt *~;\ b_CDp8nH}d CXqM6c#˪cn|ܭPD. ]hlua-resty-core-0.1.31/t/cert/ocsp/ocsp-resp-signed-by-orphaned-no-certs.der000066400000000000000000000006001474236722600264400ustar00rootroot000000000000000| u0q +0b0^0ȡb0`1 0 UUS10U California10U Default City10U  OpenResty10Uorphaned20141016032709Z0Q0O0:0 +&!mF xw`% }QQ~(7â/Q20141016032709Z0  *H c@PSq4r#.I2/k9]痀H)L*dнw4;Z>_޻w;tIZw[5ܥ]e9~vKl_STn–9mpG`n>Σlua-resty-core-0.1.31/t/cert/ocsp/ocsp-resp-signed-by-orphaned.der000066400000000000000000000020241474236722600247120ustar00rootroot000000000000000  0 +000ȡb0`1 0 UUS10U California10U Default City10U  OpenResty10Uorphaned20141016032709Z0Q0O0:0 +&!mF xw`% }QQ~(7â/Q20141016032709Z0  *H c@PSq4r#.I2/k9]痀H)L*dнw4;Z>_޻w;tIZw[5ܥ]e9~vKl_STn–9mpG`n>Σ000 0  *H 0`1 0 UUS10U California10U Default City10U  OpenResty10Uorphaned0  141016032709Z21140922032709Z0`1 0 UUS10U California10U Default City10U  OpenResty10Uorphaned00  *H 0/+ENYMfî'{g! r-!5znpt}ŵoIm/@Hh.10}x@ $AJspC~eîrģ937IRV)P0N0Uj©5 !JvG̰0U#0j©5 !JvG̰0 U00  *H YmʯXVYJY0l|\YEvɶ0a2g=Ba- )F ki !5p_=kاf=,RƳpY-B0MgY 'i\D6S>GhS8 bbAmM3v ^2p>$rW˙lua-resty-core-0.1.31/t/cert/ocsp/revoked-chain.pem000066400000000000000000000224221474236722600220540ustar00rootroot00000000000000Certificate: Data: Version: 3 (0x2) Serial Number: 8 (0x8) Signature Algorithm: sha1WithRSAEncryption Issuer: C=US, ST=California, L=Default City, O=OpenResty, CN=signing-ca-2 Validity Not Before: Oct 16 03:27:09 2014 GMT Not After : Sep 22 03:27:09 2114 GMT Subject: C=US, ST=California, L=Default City, O=OpenResty, CN=revoked-test.com Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:ca:50:23:9a:59:70:ea:00:47:ff:72:05:29:9b: 5d:6d:4b:73:37:a4:ff:38:20:4b:5b:ac:1f:3b:34: f5:12:f8:8b:0e:02:bc:bd:14:34:39:6f:7d:5b:1f: d4:15:e7:64:2e:65:fb:b1:a8:aa:f6:96:d3:e6:2b: 00:0e:f3:8a:ef:99:ab:3e:e6:5d:eb:6d:a6:4a:d0: aa:ff:a9:d6:9a:41:f0:66:22:0a:38:9c:28:4f:1f: 0d:cf:a2:79:96:f9:fc:3d:1e:83:70:f5:97:6e:07: cf:a2:17:87:0d:2a:41:19:3a:44:96:89:e7:0d:cb: 88:20:86:e1:de:08:8b:0d:db Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: FB:98:2B:56:90:69:E1:B4:2B:C2:DB:25:7C:13:87:D5:D7:BC:70:B6 X509v3 Authority Key Identifier: keyid:B3:0B:F5:7D:51:16:51:7E:28:37:C3:A2:0F:1D:2F:10:C0:51:A3:B3 DirName:/C=US/ST=California/L=Default City/O=OpenResty/CN=signing-ca-1 serial:03 Authority Information Access: OCSP - URI:http://127.0.0.1:8888/ocsp?foo=1 Signature Algorithm: sha1WithRSAEncryption 43:77:33:e9:cc:b1:42:35:94:0a:57:a5:dd:94:21:c0:cc:42: 04:81:bd:b2:ac:4d:10:68:f3:fe:33:0a:8e:b9:3e:e9:f2:44: aa:1c:e7:3e:e8:e0:57:40:41:ef:4a:b1:32:b0:f2:75:7c:aa: 77:d2:64:9d:ba:a1:12:ea:f9:83:31:ba:9f:83:58:1c:38:e9: d0:a6:dd:04:72:85:d1:2d:c7:3b:b2:71:ef:e4:f6:57:0c:6a: b6:fc:e5:13:2d:be:a6:c1:f4:4b:4d:c8:69:cc:7c:2e:25:c1: 8e:80:9e:19:c3:17:b2:21:a7:af:e8:2f:f1:d4:bb:8c:a3:39: be:49 -----BEGIN CERTIFICATE----- MIIDcTCCAtqgAwIBAgIBCDANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJVUzET MBEGA1UECBMKQ2FsaWZvcm5pYTEVMBMGA1UEBxMMRGVmYXVsdCBDaXR5MRIwEAYD VQQKEwlPcGVuUmVzdHkxFTATBgNVBAMTDHNpZ25pbmctY2EtMjAgFw0xNDEwMTYw MzI3MDlaGA8yMTE0MDkyMjAzMjcwOVowaDELMAkGA1UEBhMCVVMxEzARBgNVBAgT CkNhbGlmb3JuaWExFTATBgNVBAcTDERlZmF1bHQgQ2l0eTESMBAGA1UEChMJT3Bl blJlc3R5MRkwFwYDVQQDExByZXZva2VkLXRlc3QuY29tMIGfMA0GCSqGSIb3DQEB AQUAA4GNADCBiQKBgQDKUCOaWXDqAEf/cgUpm11tS3M3pP84IEtbrB87NPUS+IsO Ary9FDQ5b31bH9QV52QuZfuxqKr2ltPmKwAO84rvmas+5l3rbaZK0Kr/qdaaQfBm Igo4nChPHw3PonmW+fw9HoNw9ZduB8+iF4cNKkEZOkSWiecNy4gghuHeCIsN2wID AQABo4IBKzCCAScwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBH ZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFPuYK1aQaeG0K8LbJXwTh9XX vHC2MIGOBgNVHSMEgYYwgYOAFLML9X1RFlF+KDfDog8dLxDAUaOzoWikZjBkMQsw CQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEVMBMGA1UEBxMMRGVmYXVs dCBDaXR5MRIwEAYDVQQKEwlPcGVuUmVzdHkxFTATBgNVBAMTDHNpZ25pbmctY2Et MYIBAzA8BggrBgEFBQcBAQQwMC4wLAYIKwYBBQUHMAGGIGh0dHA6Ly8xMjcuMC4w LjE6ODg4OC9vY3NwP2Zvbz0xMA0GCSqGSIb3DQEBBQUAA4GBAEN3M+nMsUI1lApX pd2UIcDMQgSBvbKsTRBo8/4zCo65PunyRKoc5z7o4FdAQe9KsTKw8nV8qnfSZJ26 oRLq+YMxup+DWBw46dCm3QRyhdEtxzuyce/k9lcMarb85RMtvqbB9EtNyGnMfC4l wY6AnhnDF7Ihp6/oL/HUu4yjOb5J -----END CERTIFICATE----- Certificate: Data: Version: 3 (0x2) Serial Number: 3 (0x3) Signature Algorithm: sha1WithRSAEncryption Issuer: C=US, ST=California, L=Default City, O=OpenResty, CN=signing-ca-1 Validity Not Before: Oct 16 03:27:09 2014 GMT Not After : Sep 22 03:27:09 2114 GMT Subject: C=US, ST=California, L=Default City, O=OpenResty, CN=signing-ca-2 Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:d3:24:1c:92:a5:bb:00:d9:b1:fb:2b:1d:7a:32: a1:6c:49:eb:3c:2d:29:80:d6:65:8b:17:3a:f0:4b: dc:0c:57:fb:d5:31:68:a5:e4:54:86:55:f9:1b:a8: d7:7d:32:01:3b:cf:5c:38:2b:f5:bc:d3:8b:c8:b6: ab:76:65:32:e6:4b:d5:e4:fd:d1:92:c8:33:6a:74: f3:c7:ec:97:c3:c7:9f:e4:d5:55:75:b8:bd:39:ec: 2d:1f:c6:54:c8:2b:2d:17:e0:05:77:28:44:f7:dd: e1:6e:f0:59:05:51:f5:b9:b4:fe:be:ad:40:a6:d5: 9a:c1:64:e0:9b:dd:67:e5:f1 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Key Identifier: B3:0B:F5:7D:51:16:51:7E:28:37:C3:A2:0F:1D:2F:10:C0:51:A3:B3 X509v3 Authority Key Identifier: keyid:D2:30:71:56:50:A6:BC:21:C5:A1:A1:AB:11:A7:08:5B:EB:3A:A4:27 X509v3 Basic Constraints: CA:TRUE Signature Algorithm: sha1WithRSAEncryption 0c:61:c0:c7:11:c2:f0:39:f0:76:9d:4f:43:d4:90:54:1f:26: 3d:54:3d:77:5f:c0:b3:4a:c2:1b:b6:18:d2:12:8d:24:4d:76: f5:07:0b:14:3e:17:2d:42:ee:85:30:db:e3:4d:81:67:59:97: 0a:b3:bb:c5:27:ea:69:c6:ee:99:5c:44:36:53:3e:c4:47:68: f8:fe:c6:53:38:fb:e7:9a:0c:3c:6c:78:93:29:d2:49:7d:29: d0:61:6e:81:9b:d6:ec:1a:e2:3e:62:62:41:bc:6d:4d:33:91: 76:20:5e:32:70:08:3e:24:72:fe:b1:8a:83:57:04:19:b5:cb: 99:b7 -----BEGIN CERTIFICATE----- MIICkDCCAfmgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJVUzET MBEGA1UECBMKQ2FsaWZvcm5pYTEVMBMGA1UEBxMMRGVmYXVsdCBDaXR5MRIwEAYD VQQKEwlPcGVuUmVzdHkxFTATBgNVBAMTDHNpZ25pbmctY2EtMTAgFw0xNDEwMTYw MzI3MDlaGA8yMTE0MDkyMjAzMjcwOVowZDELMAkGA1UEBhMCVVMxEzARBgNVBAgT CkNhbGlmb3JuaWExFTATBgNVBAcTDERlZmF1bHQgQ2l0eTESMBAGA1UEChMJT3Bl blJlc3R5MRUwEwYDVQQDEwxzaWduaW5nLWNhLTIwgZ8wDQYJKoZIhvcNAQEBBQAD gY0AMIGJAoGBANMkHJKluwDZsfsrHXoyoWxJ6zwtKYDWZYsXOvBL3AxX+9UxaKXk VIZV+Ruo130yATvPXDgr9bzTi8i2q3ZlMuZL1eT90ZLIM2p088fsl8PHn+TVVXW4 vTnsLR/GVMgrLRfgBXcoRPfd4W7wWQVR9bm0/r6tQKbVmsFk4JvdZ+XxAgMBAAGj UDBOMB0GA1UdDgQWBBSzC/V9URZRfig3w6IPHS8QwFGjszAfBgNVHSMEGDAWgBTS MHFWUKa8IcWhoasRpwhb6zqkJzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUA A4GBAAxhwMcRwvA58HadT0PUkFQfJj1UPXdfwLNKwhu2GNISjSRNdvUHCxQ+Fy1C 7oUw2+NNgWdZlwqzu8Un6mnG7plcRDZTPsRHaPj+xlM4++eaDDxseJMp0kl9KdBh boGb1uwa4j5iYkG8bU0zkXYgXjJwCD4kcv6xioNXBBm1y5m3 -----END CERTIFICATE----- Certificate: Data: Version: 3 (0x2) Serial Number: 2 (0x2) Signature Algorithm: sha1WithRSAEncryption Issuer: C=US, ST=California, L=Default City, O=OpenResty, CN=root-ca Validity Not Before: Oct 16 03:27:09 2014 GMT Not After : Sep 22 03:27:09 2114 GMT Subject: C=US, ST=California, L=Default City, O=OpenResty, CN=signing-ca-1 Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:a0:3e:1a:4f:6c:b9:3d:ab:0f:02:de:da:82:92: ee:a2:69:88:80:ed:f2:b6:98:bc:c6:ee:d3:47:82: 4a:e7:d3:7f:55:68:5c:6d:9e:aa:ba:59:e3:5b:7f: 32:4f:79:44:4a:4f:13:e4:2e:3f:1f:98:10:a4:72: d5:f0:e7:44:8e:d4:a7:b9:fb:54:be:b6:fa:f7:dc: 9c:29:93:d4:9f:a1:5b:18:6e:68:93:91:1b:8c:a0: 4f:02:52:e9:9d:e8:98:f3:fd:67:da:78:4b:4f:d8: 2d:90:83:5c:0b:e5:fe:48:27:e4:ec:bb:99:26:06: 8e:34:fe:93:e4:d2:fc:97:57 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Key Identifier: D2:30:71:56:50:A6:BC:21:C5:A1:A1:AB:11:A7:08:5B:EB:3A:A4:27 X509v3 Authority Key Identifier: keyid:1D:2F:09:60:EB:E4:EA:B5:0B:52:A9:5C:5E:09:2B:DD:34:70:CF:BA X509v3 Basic Constraints: CA:TRUE Signature Algorithm: sha1WithRSAEncryption a6:16:2f:fc:13:67:5e:ce:0e:79:cb:b0:91:52:9b:9e:b5:9f: e1:fa:7d:78:f4:2a:93:f3:94:62:45:17:87:b9:0a:59:b9:a3: a9:75:51:ca:f0:04:6c:01:d1:3a:a9:dd:66:7d:27:7b:1e:4f: 48:3a:25:ea:a5:01:32:fc:87:4b:08:da:f8:f5:62:88:e8:b9: 94:c7:cb:ee:33:08:ab:2f:52:f4:4a:14:4f:ac:2d:a2:f8:de: c9:6f:95:b7:91:23:b9:ec:95:90:de:86:21:f5:6f:1b:cf:13: 47:77:78:dd:7a:16:e9:8b:cc:df:3d:45:8a:76:af:15:d1:9a: 37:a2 -----BEGIN CERTIFICATE----- MIICizCCAfSgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJVUzET MBEGA1UECBMKQ2FsaWZvcm5pYTEVMBMGA1UEBxMMRGVmYXVsdCBDaXR5MRIwEAYD VQQKEwlPcGVuUmVzdHkxEDAOBgNVBAMTB3Jvb3QtY2EwIBcNMTQxMDE2MDMyNzA5 WhgPMjExNDA5MjIwMzI3MDlaMGQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxp Zm9ybmlhMRUwEwYDVQQHEwxEZWZhdWx0IENpdHkxEjAQBgNVBAoTCU9wZW5SZXN0 eTEVMBMGA1UEAxMMc2lnbmluZy1jYS0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB iQKBgQCgPhpPbLk9qw8C3tqCku6iaYiA7fK2mLzG7tNHgkrn039VaFxtnqq6WeNb fzJPeURKTxPkLj8fmBCkctXw50SO1Ke5+1S+tvr33Jwpk9SfoVsYbmiTkRuMoE8C Uumd6Jjz/WfaeEtP2C2Qg1wL5f5IJ+Tsu5kmBo40/pPk0vyXVwIDAQABo1AwTjAd BgNVHQ4EFgQU0jBxVlCmvCHFoaGrEacIW+s6pCcwHwYDVR0jBBgwFoAUHS8JYOvk 6rULUqlcXgkr3TRwz7owDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQCm Fi/8E2dezg55y7CRUpuetZ/h+n149CqT85RiRReHuQpZuaOpdVHK8ARsAdE6qd1m fSd7Hk9IOiXqpQEy/IdLCNr49WKI6LmUx8vuMwirL1L0ShRPrC2i+N7Jb5W3kSO5 7JWQ3oYh9W8bzxNHd3jdehbpi8zfPUWKdq8V0Zo3og== -----END CERTIFICATE----- lua-resty-core-0.1.31/t/cert/ocsp/revoked-ocsp-resp.der000066400000000000000000000020611474236722600226730ustar00rootroot000000000000000- &0" +000ݡf0d1 0 UUS10U California10U Default City10U  OpenResty10U signing-ca-220141016032709Z0b0`0:0 +&!mF xw`% }QQ~(7â/Q20141016032709Z20141016032709Z0  *H H+jƺV&?ՑP}՜Ȁr.yxǸ6^EQ^TӃ}p~?+,kN/pOa#z_╢brd~'#@nQSEE/:p1Ʈz0000  *H 0d1 0 UUS10U California10U Default City10U  OpenResty10U signing-ca-10  141016032709Z21140922032709Z0d1 0 UUS10U California10U Default City10U  OpenResty10U signing-ca-200  *H 0$ٱ+z2lI<-)e:K W1hTU}2;\8+Ӌȶve2Kђ3jtǟUu9-T+-w(DnYQ@՚dgP0N0U }QQ~(7â/Q0U#00qVP!š[:'0 U00  *H  a9vOCԐT&=T=w_J$Mv >-B0MgY 'i\D6S>GhS8 bbAmM3v ^2p>$rW˙lua-resty-core-0.1.31/t/cert/ocsp/test-com.crt000066400000000000000000000067411474236722600211050ustar00rootroot00000000000000Certificate: Data: Version: 3 (0x2) Serial Number: 4 (0x4) Signature Algorithm: sha1WithRSAEncryption Issuer: C=US, ST=California, L=Default City, O=OpenResty, CN=signing-ca-2 Validity Not Before: Oct 16 03:27:09 2014 GMT Not After : Sep 22 03:27:09 2114 GMT Subject: C=US, ST=California, L=Default City, O=OpenResty, CN=test.com Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:c7:bd:50:99:71:46:af:93:22:85:ab:74:8b:5b: 19:74:af:3e:ad:d2:e1:17:3e:cb:5b:36:9c:8a:38: bd:1b:47:2d:8b:92:55:1d:fe:a6:72:92:78:00:de: 30:cb:a3:10:b5:92:aa:b8:e0:7b:44:9a:f5:99:89: 36:f4:84:20:81:e3:5c:76:00:9d:76:e7:b9:41:ab: 74:b6:14:9f:b2:94:b3:b6:48:a8:92:dc:09:e3:3d: 04:e3:5f:0f:5b:50:ad:0c:59:3a:88:06:39:2d:34: a6:52:2f:58:6f:53:1b:df:9f:98:ea:82:8d:52:60: b1:ef:6b:e9:f5:ad:29:87:45 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: 67:DF:28:25:D1:F8:83:36:28:EE:DB:41:63:E4:E0:3A:32:0D:EA:30 X509v3 Authority Key Identifier: keyid:B3:0B:F5:7D:51:16:51:7E:28:37:C3:A2:0F:1D:2F:10:C0:51:A3:B3 DirName:/C=US/ST=California/L=Default City/O=OpenResty/CN=signing-ca-1 serial:03 Authority Information Access: OCSP - URI:http://127.0.0.1:8888/ocsp?foo=1 Signature Algorithm: sha1WithRSAEncryption 37:29:3f:ed:d9:47:9a:51:36:a3:5b:00:85:66:de:51:4d:48: 2d:f8:bc:f1:5e:b4:fd:30:48:f0:25:ee:77:57:9c:f1:4b:0a: 4f:7e:96:1a:f8:48:76:23:46:8d:d6:f2:5e:1e:08:52:12:53: 08:07:9f:75:db:77:22:2e:7e:89:c2:2c:66:85:6b:df:e9:77: ca:23:6d:9a:af:87:8a:8c:27:37:1e:9e:55:92:8e:8a:a9:93: 24:41:a8:96:01:c0:65:93:8e:3d:7a:6c:bf:ed:c8:2a:f8:26: cc:00:17:b7:27:ca:85:6c:2e:d5:2a:0a:8d:f3:88:e8:26:48: e3:e8 -----BEGIN CERTIFICATE----- MIIDaTCCAtKgAwIBAgIBBDANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJVUzET MBEGA1UECBMKQ2FsaWZvcm5pYTEVMBMGA1UEBxMMRGVmYXVsdCBDaXR5MRIwEAYD VQQKEwlPcGVuUmVzdHkxFTATBgNVBAMTDHNpZ25pbmctY2EtMjAgFw0xNDEwMTYw MzI3MDlaGA8yMTE0MDkyMjAzMjcwOVowYDELMAkGA1UEBhMCVVMxEzARBgNVBAgT CkNhbGlmb3JuaWExFTATBgNVBAcTDERlZmF1bHQgQ2l0eTESMBAGA1UEChMJT3Bl blJlc3R5MREwDwYDVQQDEwh0ZXN0LmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw gYkCgYEAx71QmXFGr5Mihat0i1sZdK8+rdLhFz7LWzaciji9G0cti5JVHf6mcpJ4 AN4wy6MQtZKquOB7RJr1mYk29IQggeNcdgCddue5Qat0thSfspSztkioktwJ4z0E 418PW1CtDFk6iAY5LTSmUi9Yb1Mb35+Y6oKNUmCx72vp9a0ph0UCAwEAAaOCASsw ggEnMAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVk IENlcnRpZmljYXRlMB0GA1UdDgQWBBRn3ygl0fiDNiju20Fj5OA6Mg3qMDCBjgYD VR0jBIGGMIGDgBSzC/V9URZRfig3w6IPHS8QwFGjs6FopGYwZDELMAkGA1UEBhMC VVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFTATBgNVBAcTDERlZmF1bHQgQ2l0eTES MBAGA1UEChMJT3BlblJlc3R5MRUwEwYDVQQDEwxzaWduaW5nLWNhLTGCAQMwPAYI KwYBBQUHAQEEMDAuMCwGCCsGAQUFBzABhiBodHRwOi8vMTI3LjAuMC4xOjg4ODgv b2NzcD9mb289MTANBgkqhkiG9w0BAQUFAAOBgQA3KT/t2UeaUTajWwCFZt5RTUgt +LzxXrT9MEjwJe53V5zxSwpPfpYa+Eh2I0aN1vJeHghSElMIB59123ciLn6Jwixm hWvf6XfKI22ar4eKjCc3Hp5Vko6KqZMkQaiWAcBlk449emy/7cgq+CbMABe3J8qF bC7VKgqN84joJkjj6A== -----END CERTIFICATE----- lua-resty-core-0.1.31/t/cert/ocsp/wrong-issuer-order-chain.pem000066400000000000000000000224021474236722600241700ustar00rootroot00000000000000Certificate: Data: Version: 3 (0x2) Serial Number: 4 (0x4) Signature Algorithm: sha1WithRSAEncryption Issuer: C=US, ST=California, L=Default City, O=OpenResty, CN=signing-ca-2 Validity Not Before: Oct 16 03:27:09 2014 GMT Not After : Sep 22 03:27:09 2114 GMT Subject: C=US, ST=California, L=Default City, O=OpenResty, CN=test.com Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:c7:bd:50:99:71:46:af:93:22:85:ab:74:8b:5b: 19:74:af:3e:ad:d2:e1:17:3e:cb:5b:36:9c:8a:38: bd:1b:47:2d:8b:92:55:1d:fe:a6:72:92:78:00:de: 30:cb:a3:10:b5:92:aa:b8:e0:7b:44:9a:f5:99:89: 36:f4:84:20:81:e3:5c:76:00:9d:76:e7:b9:41:ab: 74:b6:14:9f:b2:94:b3:b6:48:a8:92:dc:09:e3:3d: 04:e3:5f:0f:5b:50:ad:0c:59:3a:88:06:39:2d:34: a6:52:2f:58:6f:53:1b:df:9f:98:ea:82:8d:52:60: b1:ef:6b:e9:f5:ad:29:87:45 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Comment: OpenSSL Generated Certificate X509v3 Subject Key Identifier: 67:DF:28:25:D1:F8:83:36:28:EE:DB:41:63:E4:E0:3A:32:0D:EA:30 X509v3 Authority Key Identifier: keyid:B3:0B:F5:7D:51:16:51:7E:28:37:C3:A2:0F:1D:2F:10:C0:51:A3:B3 DirName:/C=US/ST=California/L=Default City/O=OpenResty/CN=signing-ca-1 serial:03 Authority Information Access: OCSP - URI:http://127.0.0.1:8888/ocsp?foo=1 Signature Algorithm: sha1WithRSAEncryption 37:29:3f:ed:d9:47:9a:51:36:a3:5b:00:85:66:de:51:4d:48: 2d:f8:bc:f1:5e:b4:fd:30:48:f0:25:ee:77:57:9c:f1:4b:0a: 4f:7e:96:1a:f8:48:76:23:46:8d:d6:f2:5e:1e:08:52:12:53: 08:07:9f:75:db:77:22:2e:7e:89:c2:2c:66:85:6b:df:e9:77: ca:23:6d:9a:af:87:8a:8c:27:37:1e:9e:55:92:8e:8a:a9:93: 24:41:a8:96:01:c0:65:93:8e:3d:7a:6c:bf:ed:c8:2a:f8:26: cc:00:17:b7:27:ca:85:6c:2e:d5:2a:0a:8d:f3:88:e8:26:48: e3:e8 -----BEGIN CERTIFICATE----- MIIDaTCCAtKgAwIBAgIBBDANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJVUzET MBEGA1UECBMKQ2FsaWZvcm5pYTEVMBMGA1UEBxMMRGVmYXVsdCBDaXR5MRIwEAYD VQQKEwlPcGVuUmVzdHkxFTATBgNVBAMTDHNpZ25pbmctY2EtMjAgFw0xNDEwMTYw MzI3MDlaGA8yMTE0MDkyMjAzMjcwOVowYDELMAkGA1UEBhMCVVMxEzARBgNVBAgT CkNhbGlmb3JuaWExFTATBgNVBAcTDERlZmF1bHQgQ2l0eTESMBAGA1UEChMJT3Bl blJlc3R5MREwDwYDVQQDEwh0ZXN0LmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw gYkCgYEAx71QmXFGr5Mihat0i1sZdK8+rdLhFz7LWzaciji9G0cti5JVHf6mcpJ4 AN4wy6MQtZKquOB7RJr1mYk29IQggeNcdgCddue5Qat0thSfspSztkioktwJ4z0E 418PW1CtDFk6iAY5LTSmUi9Yb1Mb35+Y6oKNUmCx72vp9a0ph0UCAwEAAaOCASsw ggEnMAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVk IENlcnRpZmljYXRlMB0GA1UdDgQWBBRn3ygl0fiDNiju20Fj5OA6Mg3qMDCBjgYD VR0jBIGGMIGDgBSzC/V9URZRfig3w6IPHS8QwFGjs6FopGYwZDELMAkGA1UEBhMC VVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFTATBgNVBAcTDERlZmF1bHQgQ2l0eTES MBAGA1UEChMJT3BlblJlc3R5MRUwEwYDVQQDEwxzaWduaW5nLWNhLTGCAQMwPAYI KwYBBQUHAQEEMDAuMCwGCCsGAQUFBzABhiBodHRwOi8vMTI3LjAuMC4xOjg4ODgv b2NzcD9mb289MTANBgkqhkiG9w0BAQUFAAOBgQA3KT/t2UeaUTajWwCFZt5RTUgt +LzxXrT9MEjwJe53V5zxSwpPfpYa+Eh2I0aN1vJeHghSElMIB59123ciLn6Jwixm hWvf6XfKI22ar4eKjCc3Hp5Vko6KqZMkQaiWAcBlk449emy/7cgq+CbMABe3J8qF bC7VKgqN84joJkjj6A== -----END CERTIFICATE----- Certificate: Data: Version: 3 (0x2) Serial Number: 2 (0x2) Signature Algorithm: sha1WithRSAEncryption Issuer: C=US, ST=California, L=Default City, O=OpenResty, CN=root-ca Validity Not Before: Oct 16 03:27:09 2014 GMT Not After : Sep 22 03:27:09 2114 GMT Subject: C=US, ST=California, L=Default City, O=OpenResty, CN=signing-ca-1 Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:a0:3e:1a:4f:6c:b9:3d:ab:0f:02:de:da:82:92: ee:a2:69:88:80:ed:f2:b6:98:bc:c6:ee:d3:47:82: 4a:e7:d3:7f:55:68:5c:6d:9e:aa:ba:59:e3:5b:7f: 32:4f:79:44:4a:4f:13:e4:2e:3f:1f:98:10:a4:72: d5:f0:e7:44:8e:d4:a7:b9:fb:54:be:b6:fa:f7:dc: 9c:29:93:d4:9f:a1:5b:18:6e:68:93:91:1b:8c:a0: 4f:02:52:e9:9d:e8:98:f3:fd:67:da:78:4b:4f:d8: 2d:90:83:5c:0b:e5:fe:48:27:e4:ec:bb:99:26:06: 8e:34:fe:93:e4:d2:fc:97:57 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Key Identifier: D2:30:71:56:50:A6:BC:21:C5:A1:A1:AB:11:A7:08:5B:EB:3A:A4:27 X509v3 Authority Key Identifier: keyid:1D:2F:09:60:EB:E4:EA:B5:0B:52:A9:5C:5E:09:2B:DD:34:70:CF:BA X509v3 Basic Constraints: CA:TRUE Signature Algorithm: sha1WithRSAEncryption a6:16:2f:fc:13:67:5e:ce:0e:79:cb:b0:91:52:9b:9e:b5:9f: e1:fa:7d:78:f4:2a:93:f3:94:62:45:17:87:b9:0a:59:b9:a3: a9:75:51:ca:f0:04:6c:01:d1:3a:a9:dd:66:7d:27:7b:1e:4f: 48:3a:25:ea:a5:01:32:fc:87:4b:08:da:f8:f5:62:88:e8:b9: 94:c7:cb:ee:33:08:ab:2f:52:f4:4a:14:4f:ac:2d:a2:f8:de: c9:6f:95:b7:91:23:b9:ec:95:90:de:86:21:f5:6f:1b:cf:13: 47:77:78:dd:7a:16:e9:8b:cc:df:3d:45:8a:76:af:15:d1:9a: 37:a2 -----BEGIN CERTIFICATE----- MIICizCCAfSgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJVUzET MBEGA1UECBMKQ2FsaWZvcm5pYTEVMBMGA1UEBxMMRGVmYXVsdCBDaXR5MRIwEAYD VQQKEwlPcGVuUmVzdHkxEDAOBgNVBAMTB3Jvb3QtY2EwIBcNMTQxMDE2MDMyNzA5 WhgPMjExNDA5MjIwMzI3MDlaMGQxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxp Zm9ybmlhMRUwEwYDVQQHEwxEZWZhdWx0IENpdHkxEjAQBgNVBAoTCU9wZW5SZXN0 eTEVMBMGA1UEAxMMc2lnbmluZy1jYS0xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB iQKBgQCgPhpPbLk9qw8C3tqCku6iaYiA7fK2mLzG7tNHgkrn039VaFxtnqq6WeNb fzJPeURKTxPkLj8fmBCkctXw50SO1Ke5+1S+tvr33Jwpk9SfoVsYbmiTkRuMoE8C Uumd6Jjz/WfaeEtP2C2Qg1wL5f5IJ+Tsu5kmBo40/pPk0vyXVwIDAQABo1AwTjAd BgNVHQ4EFgQU0jBxVlCmvCHFoaGrEacIW+s6pCcwHwYDVR0jBBgwFoAUHS8JYOvk 6rULUqlcXgkr3TRwz7owDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQCm Fi/8E2dezg55y7CRUpuetZ/h+n149CqT85RiRReHuQpZuaOpdVHK8ARsAdE6qd1m fSd7Hk9IOiXqpQEy/IdLCNr49WKI6LmUx8vuMwirL1L0ShRPrC2i+N7Jb5W3kSO5 7JWQ3oYh9W8bzxNHd3jdehbpi8zfPUWKdq8V0Zo3og== -----END CERTIFICATE----- Certificate: Data: Version: 3 (0x2) Serial Number: 3 (0x3) Signature Algorithm: sha1WithRSAEncryption Issuer: C=US, ST=California, L=Default City, O=OpenResty, CN=signing-ca-1 Validity Not Before: Oct 16 03:27:09 2014 GMT Not After : Sep 22 03:27:09 2114 GMT Subject: C=US, ST=California, L=Default City, O=OpenResty, CN=signing-ca-2 Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (1024 bit) Modulus: 00:d3:24:1c:92:a5:bb:00:d9:b1:fb:2b:1d:7a:32: a1:6c:49:eb:3c:2d:29:80:d6:65:8b:17:3a:f0:4b: dc:0c:57:fb:d5:31:68:a5:e4:54:86:55:f9:1b:a8: d7:7d:32:01:3b:cf:5c:38:2b:f5:bc:d3:8b:c8:b6: ab:76:65:32:e6:4b:d5:e4:fd:d1:92:c8:33:6a:74: f3:c7:ec:97:c3:c7:9f:e4:d5:55:75:b8:bd:39:ec: 2d:1f:c6:54:c8:2b:2d:17:e0:05:77:28:44:f7:dd: e1:6e:f0:59:05:51:f5:b9:b4:fe:be:ad:40:a6:d5: 9a:c1:64:e0:9b:dd:67:e5:f1 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Key Identifier: B3:0B:F5:7D:51:16:51:7E:28:37:C3:A2:0F:1D:2F:10:C0:51:A3:B3 X509v3 Authority Key Identifier: keyid:D2:30:71:56:50:A6:BC:21:C5:A1:A1:AB:11:A7:08:5B:EB:3A:A4:27 X509v3 Basic Constraints: CA:TRUE Signature Algorithm: sha1WithRSAEncryption 0c:61:c0:c7:11:c2:f0:39:f0:76:9d:4f:43:d4:90:54:1f:26: 3d:54:3d:77:5f:c0:b3:4a:c2:1b:b6:18:d2:12:8d:24:4d:76: f5:07:0b:14:3e:17:2d:42:ee:85:30:db:e3:4d:81:67:59:97: 0a:b3:bb:c5:27:ea:69:c6:ee:99:5c:44:36:53:3e:c4:47:68: f8:fe:c6:53:38:fb:e7:9a:0c:3c:6c:78:93:29:d2:49:7d:29: d0:61:6e:81:9b:d6:ec:1a:e2:3e:62:62:41:bc:6d:4d:33:91: 76:20:5e:32:70:08:3e:24:72:fe:b1:8a:83:57:04:19:b5:cb: 99:b7 -----BEGIN CERTIFICATE----- MIICkDCCAfmgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJVUzET MBEGA1UECBMKQ2FsaWZvcm5pYTEVMBMGA1UEBxMMRGVmYXVsdCBDaXR5MRIwEAYD VQQKEwlPcGVuUmVzdHkxFTATBgNVBAMTDHNpZ25pbmctY2EtMTAgFw0xNDEwMTYw MzI3MDlaGA8yMTE0MDkyMjAzMjcwOVowZDELMAkGA1UEBhMCVVMxEzARBgNVBAgT CkNhbGlmb3JuaWExFTATBgNVBAcTDERlZmF1bHQgQ2l0eTESMBAGA1UEChMJT3Bl blJlc3R5MRUwEwYDVQQDEwxzaWduaW5nLWNhLTIwgZ8wDQYJKoZIhvcNAQEBBQAD gY0AMIGJAoGBANMkHJKluwDZsfsrHXoyoWxJ6zwtKYDWZYsXOvBL3AxX+9UxaKXk VIZV+Ruo130yATvPXDgr9bzTi8i2q3ZlMuZL1eT90ZLIM2p088fsl8PHn+TVVXW4 vTnsLR/GVMgrLRfgBXcoRPfd4W7wWQVR9bm0/r6tQKbVmsFk4JvdZ+XxAgMBAAGj UDBOMB0GA1UdDgQWBBSzC/V9URZRfig3w6IPHS8QwFGjszAfBgNVHSMEGDAWgBTS MHFWUKa8IcWhoasRpwhb6zqkJzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUA A4GBAAxhwMcRwvA58HadT0PUkFQfJj1UPXdfwLNKwhu2GNISjSRNdvUHCxQ+Fy1C 7oUw2+NNgWdZlwqzu8Un6mnG7plcRDZTPsRHaPj+xlM4++eaDDxseJMp0kl9KdBh boGb1uwa4j5iYkG8bU0zkXYgXjJwCD4kcv6xioNXBBm1y5m3 -----END CERTIFICATE----- lua-resty-core-0.1.31/t/cert/test.crt000066400000000000000000000041631474236722600173610ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIGETCCA/mgAwIBAgIUE3pqyVuRQL+qGuSFAUCLq4g7pt4wDQYJKoZIhvcNAQEL BQAwgZcxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH DA1TYW4gRnJhbmNpc2NvMRIwEAYDVQQKDAlPcGVuUmVzdHkxEjAQBgNVBAsMCU9w ZW5SZXN0eTERMA8GA1UEAwwIdGVzdC5jb20xIDAeBgkqhkiG9w0BCQEWEWFnZW50 emhAZ21haWwuY29tMB4XDTIyMDUyOTA2MTk1N1oXDTMyMDUyNjA2MTk1N1owgZcx CzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4g RnJhbmNpc2NvMRIwEAYDVQQKDAlPcGVuUmVzdHkxEjAQBgNVBAsMCU9wZW5SZXN0 eTERMA8GA1UEAwwIdGVzdC5jb20xIDAeBgkqhkiG9w0BCQEWEWFnZW50emhAZ21h aWwuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAyLzMbnMBcxYB 2W0uEqPKo2lOJdUQTnakipVLqRvZIJv7NkZgU76pxdFwoSxPpvJcpJ4rsosBZvhV dkGoKmuVfIFU0lYcdaccq88aT7E9XfTXiiyB2tkT6jS6wr+QxDj7KW47zdUBUT9O 6ClNyY2o1gZldElTG0Bwk4j2sAkXuWGmyncTOJ4ge3mWVksAQYbL5pwfdfyqgDmK B4nLJHBkorLbF7nm7pK2HzQCtaEUJpQKpJdCULcOHrydjVAwHUQsZAb9XXjQWPTb A0BSplbgMSI6saT9uA2RjLBzpYKj8J1rWGadWteSyQAf6XooQrquTPuR+OWF6t/m 2vkTcJlh1ukPPAPZBvlAQX9VSLWk5fmAQZA5BxYXNVWcMGVNO7UtilRmjqK1nCmv oyDXHzpE5RZPBZH4ecOqTscUgmS72ItPGWMtEtCQYbzWyMAa1cpCvK40YRa4814r XgffWgWJQfqyVvRjzpWIUiqwjUX3/p3W3pxX/GNHOv2ZH/pebcODOl7EFxzv5eQc z9vW5+RfiCSzs5bGG7qw58dMFROeAJbwR6t2o6GRd0HfgTTwSDcrrpcdLP/PaL+v twnrNa9r7rIwXnDWxYo3KiGpqEfG2WwW+lJsUzZOi9eI9kYPyvFmNFLugZbHMi+h ICCb8AQB2thON5X4N7FtP5GVfMR9vIkCAwEAAaNTMFEwHQYDVR0OBBYEFDEy866N WPHPTJKeL/96VYoczkINMB8GA1UdIwQYMBaAFDEy866NWPHPTJKeL/96VYoczkIN MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBAHJgyS6/OyRqzqwd +6DnntGV+MTo9WBNvNs/fekJghnrr85oG330GasYENQLi0wF20to7FMan2U9kwgV cbhDwe70JD0jg8htYof/uXOMBVWT4iZ+eXn60mP3iLsSutwt/drXBBzbxMYbUC12 CIiadkV8aMPIN6oGnF7TLF4AvBqYYp2qAVGXr/ZQm3L7NPB0jkSktSe6obnaq1tO ug18ImhzAqkn1UGnLRiTADOba5HuKtovwWtLblNBODdnv1E7IK1A6jpqwiYjlbU5 4v9ZzFzEJw+GqYHkTRmJGCA2Uw7HNEUFeno1BTp19Ce9fvrkofTWYmLp/NAvEp6E aFnBdCjY4tWzI2Iig7IjDIM7F6igGODybeN9ijD7oSyEDtNE7ECLSuXhgekiQJ8c NYALgbbNPxWx8zJcNiYy1NDYdIjO5vYFOpbn+rQObKVCX/X+Al9fT126ciTT1xAF fZtkGPpp3Wjgws9UDSzetvWHYt0Rs70m351LFPHyR4tQLHoDFqnA2buG/mSvKZ9U to0JQ/8QPRIYv0FUJcF0+/xQRYrIqvmjiCpfL2hwJyRViq7f8z0/tmMoLxFlPo/k GC+gvh3WwTB622h9JEqS48lllcYZIQWOX2mbFtUtNFdzUtSRmZMa8RmcYr5So2OH 9QLIIjC6ntPFjWq+uLJAJ8uazRt7 -----END CERTIFICATE----- lua-resty-core-0.1.31/t/cert/test.crt.der000066400000000000000000000030251474236722600201260ustar00rootroot0000000000000000zj[@@;0  *H  01 0 UUS10U California10U San Francisco10U OpenResty10U OpenResty10U test.com1 0 *H  agentzh@gmail.com0 220529061957Z 320526061957Z01 0 UUS10U California10U San Francisco10U OpenResty10U OpenResty10U test.com1 0 *H  agentzh@gmail.com0"0  *H 0 ȼnssm.ʣiN%NvK 6F`Sp,O\+fUvA*k|TVuO=]׊,4¿8)n;Q?N)MɍetIS@p aw8 {yVKAu9$pd4& BPP0D,d]xX@RV1": skXfZגz(BLpa<@AUHA95U0eM;-Tf) :DOyêNd؋Oc-АaB4a^+^ZAVcΕR*EޜWcG:^mÃ:^_$LGvwA߁4H7+,h 5k0^pŊ7*!GlRlS6N׈Ff4R2/ N77m?|}S0Q0U12XL/zUB 0U#012XL/zUB 0U00  *H  r`.;$jάѕ`M?} h} LKhSe=qC$=#mbsU&~yyc-P-vvE|h7^,^bQPr4tD'ګ[N |"hs'A-3k*/kKnSA87gQ; @:j Y\'M 6S4Ezz5:u'~bb/hYt(ճ#b"# ;m}0,D@J"@5 ?2\6&2t:lB___O]r$}dihT ,޶b&ߝKGP,zٻd)T C=AT%tPEȪ*_/hp'$U=?c(/e>/0zh}$Je!_i-4WsRԑbRc"0ōj@'˚{lua-resty-core-0.1.31/t/cert/test.key000066400000000000000000000063101474236722600173550ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDIvMxucwFzFgHZ bS4So8qjaU4l1RBOdqSKlUupG9kgm/s2RmBTvqnF0XChLE+m8lykniuyiwFm+FV2 Qagqa5V8gVTSVhx1pxyrzxpPsT1d9NeKLIHa2RPqNLrCv5DEOPspbjvN1QFRP07o KU3JjajWBmV0SVMbQHCTiPawCRe5YabKdxM4niB7eZZWSwBBhsvmnB91/KqAOYoH icskcGSistsXuebukrYfNAK1oRQmlAqkl0JQtw4evJ2NUDAdRCxkBv1deNBY9NsD QFKmVuAxIjqxpP24DZGMsHOlgqPwnWtYZp1a15LJAB/peihCuq5M+5H45YXq3+ba +RNwmWHW6Q88A9kG+UBBf1VItaTl+YBBkDkHFhc1VZwwZU07tS2KVGaOorWcKa+j INcfOkTlFk8Fkfh5w6pOxxSCZLvYi08ZYy0S0JBhvNbIwBrVykK8rjRhFrjzXite B99aBYlB+rJW9GPOlYhSKrCNRff+ndbenFf8Y0c6/Zkf+l5tw4M6XsQXHO/l5BzP 29bn5F+IJLOzlsYburDnx0wVE54AlvBHq3ajoZF3Qd+BNPBINyuulx0s/89ov6+3 Ces1r2vusjBecNbFijcqIamoR8bZbBb6UmxTNk6L14j2Rg/K8WY0Uu6BlscyL6Eg IJvwBAHa2E43lfg3sW0/kZV8xH28iQIDAQABAoICABwZgax8YNmRXRTomah2USlq 1kupdazmIsZbe8niYhSUgSfp1hYi/HT6in+lSkkeaCWLFqbZmoqlfKEfM8EsajKR kCQZdcZqbDMIvLAnKWX7nihzboIKHSWN2A7m7gbpyw7TpX98r8CF0i/hiEgMknPT VWRf10hbTub4J0AhJbcHmmeBH6mvSPC/5nGR8ik6C1TuyeCkS+HDLDU97rfdG9lC nDTICzGeS+w2RaLTN5Tm6E599gSCe3GGCa/8Z5/RKT2fVNw+yzuImxfrayZpxtxZ 5El1xSZ8j8FX+fhTP0uxXZN0WdabkqqcX9s5BGXC6B9Sn+5tgr+MNC626ye58N36 vhASbLhnZxZ1MxbVNdvQjl9A5mj/Tv/TM/syjFkElFwXBFz5MXgYRTu5TnoJpDyp wMqNodTSbe8UuULtBIHYyuLEsrPWjne/ape8CqSQKgfnI91tveAMlAQA+yGRufSw fx1gDrBIk3EtDGuelAIiW1ZimZoTj51HW7Mpfq9PXbuVO7i+zzSDFP/zyto2hITq UeiTwKYpj8AgF39HiudAyJVYKDjKgATeSN1ziTvXBvBxe4JJ+7wovjl+R5ClBUEk cNrn3FNVrgPjmJ6X7+42U2upQ2WIo8dT6PuE408nh2FR/VuabEqqwmmDEUW19+U+ yZWfhDMv6Y/l6f75UBHhAoIBAQD++61+BBEwqTPfGH5EUxxeeaXXto8zW/N3aBql f77iI3/XuOhve4WfL8v5xAXPfPIBGGBlG5RQ0Quxoo5fE6RPKt+5vaaOpMhLVf4L sAQfLM9M9JK84BbWI+Z1o2s1knxlTlK0GZ/pbqg6J1YFfFAL/3PKi98EAGw9Dpj9 u3GnSjF/dbtwwUiTS0Rv/8FV4bFxsSoul+N3xeyi26UWG9WIvuAzuLJfvqV2fb/l o3LKpeXyD+SFatRmPe0JWIi2o0ZQpF8hhJXg1UYo2RGWf/bbl3SnivIMb/hNs8LB 17DNKu1DvgZoJSyocFmKAShZvbbirQYRtHo7SI2hAaOt6T81AoIBAQDJib1HIp/V N59IIFOru6+kc9Vkhm8FDf3iyQfIL9Y0uVI4WrdKUeIH+pEKU7CMCT0WSgCxENe2 TT+pOF3/T398eEmGAr79CtgtSzzuDvBlpD2aEfhjBPUE7g6tNuUFjgFJmzdXHT7u 99mWag4l30hfIAFXLu9ofm05nw0CRxlotYUiTCBU892ZxpO2/nDNJUjAU1MOvSa7 MM7VbETui9teHgjZa+AadHZs2OqnWVo+g3RcKl3PyAdcOWobVQknRrpN9SlQkf/V GYRhY2tQCpstKrEDQPWsNGmwjmT3uPdK8t5SXZZBji282XtCa+C+tB34AZ8YuU/Z BH+Akez5zw6FAoIBAQCLK17kGuAvCQsQx1OTgzFGt2q3NCMwyw01rRJuJi1PTETo vznOL0MdQX85Ua5CM1X7Fwz14nmvKooRaEIAzr2toB8AR+zyiinwRH0mb+mwAksb G5pDkKOmOW394zYOxWcz++3T8vB+/jC/nNysnc8q3UCb2n/ctUZehOsoAfjkb/BY OzAVOMmd60TtRFCHyWmKPkJhr/EtXE/uC6gtSv/fZR8F29cvvuScqcHlWrK6vJWm 6tm1oDtRmpcXtMTZuoAUX8K0jqMnVgC3JtMcq7dW33GCSKoX870429Z+6nTLZpSd lsf0a+XWAYw9cKhPYubBDeL0IudcGBuFN1nZACfJAoIBABpg/vdKnuUHjL+iC5GU 1V6PEsU/m1RsCmkeqvgW2tC32P0rUoZVxWIJ9+YEIj2SD/7U3NZQQAvKfKSnjhYW z7b4/5ac0WbJfpYfHPCD4A9Nugpqg7piMbfdeOpPHxblCWIbANlUKKKaqk43v3ZR jWV2CPbiW8+vjJhYKxm7OKYt7CkbEbhM2xp/lWIEV7tiP+18eoiZVXJ25vukWjlm 8OWWxM3Aguqzh7Sjh8MzvM4l4psVqIXDxsLZePvu223aohQGHMxA791yo5Mjsi4d 1UXKKrUkUYOisJq9aJXMDgIvW84oFbyq4W2wgaOl/xq29J07iRlxV/Qt1Ip9jyj7 YwkCggEBANFod5wwlOzTyAlRdZAPvyBWa0i+SLWecwr93rGQF3UuZwzaviY7U0tp BoeFZAxiwns3SM6SJYIhce8Ku0PO1rp4FXvOopnIVO9BFXk1E5YUholQHHbERsse pQahtlZ26ZAyRQjMQI9KKmU6pNFiF87MCnsz70BQajKo2+5NfZpnjaQzT6uyJeRQ Iy38QlOk0221UsUU/bjahDlxmuHVdcnl6gi+4SYrI45wJSiBTiCJrVmxScg2D3IA EZ3pVKOam0a3Mroqe0uMdY892cIYSAKOrZcxg5ZXWKDwlcsXgVuGDSvrU8LUPqn1 jxLWsmKbkVA5hFln8GPxs6EqfqOJhkM= -----END PRIVATE KEY----- lua-resty-core-0.1.31/t/cert/test.key.der000066400000000000000000000044551474236722600201360ustar00rootroot000000000000000 )ȼnssm.ʣiN%NvK 6F`Sp,O\+fUvA*k|TVuO=]׊,4¿8)n;Q?N)MɍetIS@p aw8 {yVKAu9$pd4& BPP0D,d]xX@RV1": skXfZגz(BLpa<@AUHA95U0eM;-Tf) :DOyêNd؋Oc-АaB4a^+^ZAVcΕR*EޜWcG:^mÃ:^_$LGvwA߁4H7+,h 5k0^pŊ7*!GlRlS6N׈Ff4R2/ N77m?|}|`ّ]虨vQ)jKu"[{b'"tJIh%ٚ|3,j2$ujl3')e(sn %ӥ|/H sUd_H[N'@!%gHq): TK,5=B4 1K6E7N}{q g)=T>;k&iYIu&|WS?K]tY֛_9eRm4.'lggu35Ў_@hN32Y\\1xE;Nz <ʍmBIJ֎wj *#m !`Hq- k"[VbG[)~O];46Q) G@ȕX(8ʀHs;q{I(9~GA$pSU㘞6SkCeSO'aQ[lJiE>ɕ3/P~03~DS^y׶3[wh#׸o{/|`eP _O*߹KU ,L#uk5|eNRn:'V|P sʋl=qJ1upHKDoUq*.wۥՈ3_v}rʥjf= XFP_!F(ۗt oMװ*Ch%,pY(Yz;H?5ɉG"7H Ssdo /4R8ZJQ S =J׶M?8]O|xI -K<e=c6I7W>ٖj%H_ W.h~m9 Gh"L TݙƓp%HSS&0lD^ktvlYZ>t\*]\9jU 'FM)PackP -*@4idJR]A-{BkྴO+^/ S1Fj4#0 5n&-OLD9/CA9QB3U y*hBνG)D}&oKC9m6g3~0ܬ*@ܵF^(oX;08ɝDDPi>Ba-\O -Je/䜩Zٵ;Qٺ_´'V&VqH8~tfk=pOb "\7Y'`J ^?Tl iз+RUb "=P@ |϶f~M jb1xO bT(N7vQev[ϯX+8-)LbWb?|zUrvZ9f곇3%xmڢ@r#.E*$Qh/[(m;qW-Ԋ}(c hw0 Qu VkHHs ޱu.g ھ&;SKid b{7HΒ%!q Cֺx{΢TAy5PvFVv2E@J*e:b {3@Pj2M}g3O%P#-BSmRڄ9qu&+#p%(N YI6rTF2*{Ku=H1WX[ +S>ֲbP9Ygc*~Clua-resty-core-0.1.31/t/cert/test2.crt000066400000000000000000000041061474236722600174400ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIF7zCCA9egAwIBAgIUBwRM0hlOTRGtIMvLy56P3TZc6jIwDQYJKoZIhvcNAQEL BQAwgYYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH DA1TYW4gRnJhbmNpc2NvMRIwEAYDVQQKDAlPcGVuUmVzdHkxEjAQBgNVBAMMCXRl c3QyLmNvbTEiMCAGCSqGSIb3DQEJARYTb3BlbnJlc3R5QGdtYWlsLmNvbTAeFw0y MjA1MjkwNjEzMjVaFw0zMjA1MjYwNjEzMjVaMIGGMQswCQYDVQQGEwJVUzETMBEG A1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzESMBAGA1UE CgwJT3BlblJlc3R5MRIwEAYDVQQDDAl0ZXN0Mi5jb20xIjAgBgkqhkiG9w0BCQEW E29wZW5yZXN0eUBnbWFpbC5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK AoICAQDCOlzMo5qPtb5wjXHqy1mjm2rMAPeiz0wrDRXC0+9l/f/6KYBfJoaAuLau P6kCojDNLOOHAjmbjeoG+bVGoLVNAGhFaThKQepmBPFhjtT0+7syGq6H12Wb9mmn hMy65gS+7dsUU74HUjlHuYyOnXHmrJH/7sGzG6DXX6t2x0Ts49gVWzFr1TINMjP0 opupvpokbr+EEzIP4NE5isPQnMeIt2HhzTMN+wHBalnHIVq0v03M911l4XpzHtP+ MetDMraHJdv8Hlh5qeyrDkn7N5zE05cnSu6AK3vMaxsDbRJ92Akv6bLMqTqSnR3j 16Qwqs369cU+zl7wQJ7+J1Gh5DhOe9Vns+bLbBJC5XZz3qcFxUXXRResuBYPQNht JwgT7wq+XNMkd7TzDQzfWx4G7zz+3ogiNK6k02e0Uafuizi4nyMpwuu9SwvfYan3 QBL7ddjuMGUHG9oOepLmiKt8ST/plduc+67oXu1oeGnaEthpQ9Aong0/JhDvvnsX Pe4tZQwzFK1m/fxF034l3fy+gmGfnRC4k2thUotfp+BReDAZ5Wwg6FO7eaowuQbH Qk8Pt36yd0fWwAgX3kmhxC91QOYt29Aya4gTuJT4ajueDVRzB3bCxX0t7Awz/Ohh 36XiLHZp7Zo1eJtG7oOXRJdiKCglxOk9WiXTIaDXunXDGRl+DQIDAQABo1MwUTAd BgNVHQ4EFgQUwIug2OC092u/dZFClmac5Sbo4ukwHwYDVR0jBBgwFoAUwIug2OC0 92u/dZFClmac5Sbo4ukwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC AgEAhnWpbQ31DbMzbSiY7iKM8OsUAqPzjvGObB6hzF+i8/q0GfQm11V+aKFTWu3p 5aJua0hCPxq3F6q3Wj+F42pcRkoOmcGMMkGVOFeT1TRaC1WwTvhYjwFke4jqOi+5 kcfLWO3bkADm73AuW/PJ6WgQzrfOvd+uvVX6B0NKumgNYrhyDfwb4tZ/fOLHSA9W NNd/93yo2OhH0vOMbAcDGdOpBR7Sx7c+BeI57kORIlSwCQmaSeIIOLs69VsMH/Yo DiNWfbj7pPRhdCSEmd59wyPKUcBJHfEE9z54NIb6ETTKrmtwYLPNKdgW6dqHe8UK bsjXiiw0Y3nHhrv7Fh+aqy470mn890K0+CPTh9Gi+Qwkfyt7tJr4uCdDzLPoP6up FlQaobMtOFuCMNZs+B1UZm2jcj5j/PjY19PZu8XAHOFJmY66oqK6FvZHrq/26K29 p6BXPMUVhxFoXUX2EmAtey919+GY9KncMuhobn+5If/6mug3QRNNt/csw30NvBOZ 6Lqc920e/lgoFPQ7RnxI5PLNdTFLTqM8c9lMt6rqcff7cK9aonfWPd3s1pyWTFhx tSBH95qNcu+kgu+iVLeFZjqyTW5lLyqZLPjnx8cS4HZtAUeM73RjFcDVokqGxAgc qzatPoPNGjLtG1JoMsXjaMuc0ed3BkjXpXH24z8o0g7ppgQ= -----END CERTIFICATE----- lua-resty-core-0.1.31/t/cert/test2.key000066400000000000000000000063041474236722600174420ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQDCOlzMo5qPtb5w jXHqy1mjm2rMAPeiz0wrDRXC0+9l/f/6KYBfJoaAuLauP6kCojDNLOOHAjmbjeoG +bVGoLVNAGhFaThKQepmBPFhjtT0+7syGq6H12Wb9mmnhMy65gS+7dsUU74HUjlH uYyOnXHmrJH/7sGzG6DXX6t2x0Ts49gVWzFr1TINMjP0opupvpokbr+EEzIP4NE5 isPQnMeIt2HhzTMN+wHBalnHIVq0v03M911l4XpzHtP+MetDMraHJdv8Hlh5qeyr Dkn7N5zE05cnSu6AK3vMaxsDbRJ92Akv6bLMqTqSnR3j16Qwqs369cU+zl7wQJ7+ J1Gh5DhOe9Vns+bLbBJC5XZz3qcFxUXXRResuBYPQNhtJwgT7wq+XNMkd7TzDQzf Wx4G7zz+3ogiNK6k02e0Uafuizi4nyMpwuu9SwvfYan3QBL7ddjuMGUHG9oOepLm iKt8ST/plduc+67oXu1oeGnaEthpQ9Aong0/JhDvvnsXPe4tZQwzFK1m/fxF034l 3fy+gmGfnRC4k2thUotfp+BReDAZ5Wwg6FO7eaowuQbHQk8Pt36yd0fWwAgX3kmh xC91QOYt29Aya4gTuJT4ajueDVRzB3bCxX0t7Awz/Ohh36XiLHZp7Zo1eJtG7oOX RJdiKCglxOk9WiXTIaDXunXDGRl+DQIDAQABAoICAF1s/V5iA+LEpUo2f2lVT1Tn WUOv424pEJZUwPbqQuloeEy40crzGRepwhWnAYEGyzqmMPusElHEvaGFU7EZdJwJ ah6ZMj5l3n4cOo+WyNDelXjQZMtqzLFsof22X1Q3eGjuuMbaUTnsTyk1E2s2SKeQ stnM2tdwnrl6h1unFnxsTHBZYThhYKYAVAWEgiPwTuzfaLf7E8WXeoyXNwGNqF0W +LpInhpHdty2b2Ddpmfy7VV+Vyq+fswJNCe9k1DLgAkaKOrpHd3H4tOVF/kDEyGK NdbssDRutinqCyBmwtJNrH2jiCHx9P65HLuP6qaOQm5I8gv38KrYKqJN/3JD+ODQ dn8yVXjcCRzq8vylFLJfVEY0hB3ZWJAgDxY8GFax7foyaJ6889qgMOU4xBdotF7c hKNsH+ClHSuJ5h4SNAV7/mRcJrYDFJ9imuY4PGFMZMQYSZig5dLawTe52+wsSuZ4 kYxDXk76ZLr/MsbijrNOdze3Mny6EPxJGlv04XNNfIrsN9PXQGLpUwaJSJMGnFTI TgAlcLATVMLusU2xf/Ra8eCk8Xydk0ExdB4TnMD0TTM/6bPJYIwwqrjee1ao4V0E eISaoC8QHDi1XIFav2amzeyfHQI8uV4OQwV1rVLgeBY8TtQ0Mk6oU3AZ9z8Hvb1V szdpOicXdI2lC9qpFiIBAoIBAQDxYMCvRDTkYcebG2sSi7ViUd3NWuBYFjlNfHED /Rz6mUDud9r6TC3nqCPuugGt9P7fz3KktCoSh/x6iYsUP7iSK2V6Gg/kD1wtjIdY 9OW8u2cHyyGPshgZBgFJ4jE1wvzHQApQYrbdLdSmlwnvXT+tEG57vEa1ep2DSNaJ hXlvpPMJAghNtc0wvcTZ8Aas8HfuEthKrb22O2zo0J2QObBZv2gcA0djW0ZbEEGg BVNzmfaZFrLqSIP+7SD9KTgyRz1pAmeIgv//szYweHNVGeVbPgG2W4HiaV7c4+aF 3dmaikSZgz6Qily74HcVMrTzcgw2v2uM3IkTvWEX1PrixPdhAoIBAQDN/mqXtqtO mbQBbn6+QgnVNRc/lnLv2QnzfuK93omZGFrl+COaCdM+T93PQkTiEydCjOYgwv3x 6KVMyrZLVKuYIHcdwP7z+Xi3wDQkCO0D8JmJGFBU+tAUJHEgF7DxEDa+PGxEPXWe Ta4ZXpqQH96bssfzyFB2+PQcSIcRyWdnhJyVgXdRfMxMbYxH6g5X1bIGOAzCF1hp b9QN3Rc/2UKCfw3IoFl1Yzo8yXi9hLhkIb2tjpBmt9V6itgVHL12HLLgvzs4egkI aBHtMIxWcrzq+XtG3ARgugkRlhLhDR7nZOV2nFYXFNJ2tHfg2q4PBkrFm5EPLpXj shzOZzlok0ItAoIBAGVo7ssz7rzcz828sTlzdNs/5d33BjY78As78wdn+hrW9E68 EEYEZ2ziWWZcw4PgYIyLTXEhOGPcuhiJXOM++j5++P1Zob+BLIr+dYbMLREj8t91 Wj5S5ojs2vG9lEswBp93ql2ne4hlTuhGoKfuF2iQdLqLmXF5eF/F5EyWxTRAqtLo BbEQZorJz8B4dXWG+fwN8s09PW0oflM6AlirxAmQvx61yfJWULLFm6ytUChLUS10 OerwWHRsD+YMwU1uXMCXgAP8da1qD6RBlsL0REYXQQTqYSFMf8xx+1HWqSuiV7vf RhPX7aoJXj6LtTZqffMqbPcbWIPwlrA6jMVlV0ECggEAHqfDAyrrGXpkQGZKNFQt lG4fNJZWKn15LqRuZ+UrQv5N4LVpzu2xYy+Nid+J0r8Y8512Td/W3N5LYz8zm8hQ 9QW31FS5XGN+5JGU8NvnMdPndXCJ2+urdaPqteTwrx9DllH1pr4it9lFlH7wr4we m7siaJQh7WKlKWRdvXbkjZI9nz4yHI1e9ezDmJwrYETsBmLm+ydwP9iljR6e7CCP 9k2kJnw+c+q9avhsoH+U1Un0KVTzBmZLPb5V4+ZwB5jDwhCTZpc6quaZ7FtyNxdC KBHSl7v8ZsyottZHnvhN5g+s2lbvtOWjYIkA4hSJHLFKBVheYQ0Ev2rtQIY6E+b+ TQKCAQA+jl6f5wFSGBFjnrQu5V6E3tcI6fhkk2b4KGRBLyp27gIdqnw6FCZLsJ+g qUmJd8lz3E4UR/VXy2lSWcKbmDmO1l+v2fZZu227hbZp8YTsPqt1JhnrroBP3Pdj d+Zj+ZJpw5MbLb+8Wsx41fsAy8k1kZX82Vigbj2HEE/O7keflwBfa455ue9IGIFY 1SRNNJPB4RZ/9T/NM+MsTJZapsp6Si/nkncluSKeBnE1LfHoJi2eVW77qPIOGOPy L3iaDoc8MmhMx2EFzSDlzwdB9Jg8cXxF4XxjadYc6JOtzUEkCqR0XS8KOgO2eMU0 uWdAG+HmOwioRij8CIrb/9veL2jl -----END PRIVATE KEY----- lua-resty-core-0.1.31/t/cert/test_der.crt000066400000000000000000000030251474236722600202070ustar00rootroot0000000000000000zj[@@;0  *H  01 0 UUS10U California10U San Francisco10U OpenResty10U OpenResty10U test.com1 0 *H  agentzh@gmail.com0 220529061957Z 320526061957Z01 0 UUS10U California10U San Francisco10U OpenResty10U OpenResty10U test.com1 0 *H  agentzh@gmail.com0"0  *H 0 ȼnssm.ʣiN%NvK 6F`Sp,O\+fUvA*k|TVuO=]׊,4¿8)n;Q?N)MɍetIS@p aw8 {yVKAu9$pd4& BPP0D,d]xX@RV1": skXfZגz(BLpa<@AUHA95U0eM;-Tf) :DOyêNd؋Oc-АaB4a^+^ZAVcΕR*EޜWcG:^mÃ:^_$LGvwA߁4H7+,h 5k0^pŊ7*!GlRlS6N׈Ff4R2/ N77m?|}S0Q0U12XL/zUB 0U#012XL/zUB 0U00  *H  r`.;$jάѕ`M?} h} LKhSe=qC$=#mbsU&~yyc-P-vvE|h7^,^bQPr4tD'ګ[N |"hs'A-3k*/kKnSA87gQ; @:j Y\'M 6S4Ezz5:u'~bb/hYt(ճ#b"# ;m}0,D@J"@5 ?2\6&2t:lB___O]r$}dihT ,޶b&ߝKGP,zٻd)T C=AT%tPEȪ*_/hp'$U=?c(/e>/0zh}$Je!_i-4WsRԑbRc"0ōj@'˚{lua-resty-core-0.1.31/t/cert/test_der.key000066400000000000000000000045071474236722600202150ustar00rootroot000000000000000 C0  *H  -0 )ȼnssm.ʣiN%NvK 6F`Sp,O\+fUvA*k|TVuO=]׊,4¿8)n;Q?N)MɍetIS@p aw8 {yVKAu9$pd4& BPP0D,d]xX@RV1": skXfZגz(BLpa<@AUHA95U0eM;-Tf) :DOyêNd؋Oc-АaB4a^+^ZAVcΕR*EޜWcG:^mÃ:^_$LGvwA߁4H7+,h 5k0^pŊ7*!GlRlS6N׈Ff4R2/ N77m?|}|`ّ]虨vQ)jKu"[{b'"tJIh%ٚ|3,j2$ujl3')e(sn %ӥ|/H sUd_H[N'@!%gHq): TK,5=B4 1K6E7N}{q g)=T>;k&iYIu&|WS?K]tY֛_9eRm4.'lggu35Ў_@hN32Y\\1xE;Nz <ʍmBIJ֎wj *#m !`Hq- k"[VbG[)~O];46Q) G@ȕX(8ʀHs;q{I(9~GA$pSU㘞6SkCeSO'aQ[lJiE>ɕ3/P~03~DS^y׶3[wh#׸o{/|`eP _O*߹KU ,L#uk5|eNRn:'V|P sʋl=qJ1upHKDoUq*.wۥՈ3_v}rʥjf= XFP_!F(ۗt oMװ*Ch%,pY(Yz;H?5ɉG"7H Ssdo /4R8ZJQ S =J׶M?8]O|xI -K<e=c6I7W>ٖj%H_ W.h~m9 Gh"L TݙƓp%HSS&0lD^ktvlYZ>t\*]\9jU 'FM)PackP -*@4idJR]A-{BkྴO+^/ S1Fj4#0 5n&-OLD9/CA9QB3U y*hBνG)D}&oKC9m6g3~0ܬ*@ܵF^(oX;08ɝDDPi>Ba-\O -Je/䜩Zٵ;Qٺ_´'V&VqH8~tfk=pOb "\7Y'`J ^?Tl iз+RUb "=P@ |϶f~M jb1xO bT(N7vQev[ϯX+8-)LbWb?|zUrvZ9f곇3%xmڢ@r#.E*$Qh/[(m;qW-Ԋ}(c hw0 Qu VkHHs ޱu.g ھ&;SKid b{7HΒ%!q Cֺx{΢TAy5PvFVv2E@J*e:b {3@Pj2M}g3O%P#-BSmRڄ9qu&+#p%(N YI6rTF2*{Ku=H1WX[ +S>ֲbP9Ygc*~Clua-resty-core-0.1.31/t/cert/test_passphrase.crt000066400000000000000000000017211474236722600216070ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIICozCCAgwCCQDEutRdSs3vZjANBgkqhkiG9w0BAQUFADCBlDELMAkGA1UEBhMC Q04xEjAQBgNVBAgMCUd1YW5nZG9uZzERMA8GA1UEBwwIU2hlblpoZW4xEjAQBgNV BAoMCU9wZW5SZXN0eTESMBAGA1UECwwJT3BlblJlc3R5MREwDwYDVQQDDAh0ZXN0 LmNvbTEjMCEGCSqGSIb3DQEJARYUZ3VhbmdsaW5sdkBnbWFpbC5jb20wIBcNMTYw NDI4MTQ0MzI4WhgPMjE1MTAzMjcxNDQzMjhaMIGUMQswCQYDVQQGEwJDTjESMBAG A1UECAwJR3Vhbmdkb25nMREwDwYDVQQHDAhTaGVuWmhlbjESMBAGA1UECgwJT3Bl blJlc3R5MRIwEAYDVQQLDAlPcGVuUmVzdHkxETAPBgNVBAMMCHRlc3QuY29tMSMw IQYJKoZIhvcNAQkBFhRndWFuZ2xpbmx2QGdtYWlsLmNvbTCBnzANBgkqhkiG9w0B AQEFAAOBjQAwgYkCgYEA2KZ+HdH9R2tarxD8PKqu5EYq2BNGlFRg1xJmrw0XZBRM UP/VPb+sIeioooz36uhiXfQjExlpBCA/0zNAN+HbFyqpPPTf1qLGrj/dqeE4MJaN Bwzxiv3fZnENT65u2qbiFWIY+ATNHgA20d50nxNNjPTzLbkx/nYXL92r4kuAGk0C AwEAATANBgkqhkiG9w0BAQUFAAOBgQCfMo0qbcs3kwl1tcNBO5hCcUUJRzyv041V ff/nZ/JPIMo/LSZd12K82G/dLRN7uRT9nzqtm+JRkHALHWWWFKi6bdg1vcdOTWqC 08bCkJHQoXJQQLvvA6gNvnR+0b7L4CrCmrcyYgKDLXVGNP9Wv/PqSWWbxsmqngkA Mvy6CVytFw== -----END CERTIFICATE----- lua-resty-core-0.1.31/t/cert/test_passphrase.key000066400000000000000000000017031474236722600216070ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-EDE3-CBC,679ACC8E69ACAA92 Ssrjp3VU4somCNPiXkWqcudDnvnwbyj/Q0pS07at3lXKbhQSgI1Tzhg9Pm3BXXj5 mkLdeGG5ocrj1Q9dhtmZgZeHHQIiynZBhjBu1Y+HPef8jXOWLrCOi8EKiWkJ2qG3 V1KFM/95CcDt0mRLykUXEL3IpUst05SFb9XwiLokB7ypeu3NhgNUHjL6G+ubB4ri TOUjCW4pEoNHjdC22IiqSncwCVhluYSGhr6ktHKehZMhYIXmL1wmSLdhTlsPXCQl xvYILQ2vJcKIR1BkeYYPD/OQC6zCZlXIErzfgeZiz2+NTudKYpb9VmsQKsO+R8L7 tZ/fNaR0vk8bbimMHgStAV4acVsC/7WxsqOjMJ8VTq1iqhYPl6N7kRdR3H3kSSOm cN9T3SrOHDVaHbnWgToaOE4mKFjvFSLIOcWgus0iOHWXmY+SLG+Ndag3oVB6R9oB cAHX19mq99+GhzA8IV4I0En2UCKQhnGPvkM+9mcCDxhRETlwncDjlMGOHpQ65J9r eReVPIpnDkvHxPGTtsR3ZHTdWTZb+C0W2N3QIlJKrOzxFmfoj++yG3tMX42aDY0g DVkrXgcKobiWN0AVrJNAwfG7uObKSCFYgz/0RRMCO4cjXRW99nxdjVDZhyc6R0Te jzuF04okkOLNb25n2hP+yIULrn+6Nv/uHtFI0j0n3hOzcKh//dNbACSAKgkHni9g JKDFJXgLJxf+Wc3So0DF9gYMKJJ+WbcdVT9gkC7RyQHlC90Pn7kNXzHr0ZawUsNI ZxSkL4dMhYAfA4lUBJbOkwbSurv97LinOSRffpM0Nmf7VNw/Ue15eg== -----END RSA PRIVATE KEY----- lua-resty-core-0.1.31/t/count.t000066400000000000000000000014111474236722600162410ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(1014); #master_process_enabled(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 3); #no_diff(); no_long_string(); run_tests(); __DATA__ === TEST 1: module size --- config location = /re { access_log off; content_by_lua_block { local base = require "resty.core.base" local n = 0 for _, _ in pairs(base) do n = n + 1 end ngx.say("base size: ", n) } } --- request GET /re --- stap2 global c probe process("$LIBLUA_PATH").function("rehashtab") { c++ printf("rehash: %d\n", c) } --- response_body base size: 20 --- no_error_log [error] lua-resty-core-0.1.31/t/ctx.t000066400000000000000000000672541474236722600157300ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; use Cwd qw(cwd); #worker_connections(1014); #master_process_enabled(1); log_level('debug'); #repeat_each(120); repeat_each(2); plan tests => repeat_each() * (blocks() * 3 + 13); #no_diff(); #no_long_string(); my $pwd = cwd(); add_block_preprocessor(sub { my $block = shift; my $http_config = $block->http_config || ''; $http_config .= <<_EOC_; lua_package_path "$pwd/lib/?.lua;\$prefix/html/?.lua;../lua-resty-lrucache/lib/?.lua;;"; init_by_lua_block { local verbose = false if verbose then local dump = require "jit.dump" dump.on(nil, "$Test::Nginx::Util::ErrLogFile") else local v = require "jit.v" v.on("$Test::Nginx::Util::ErrLogFile") end require "resty.core" -- jit.off() } _EOC_ $block->set_value("http_config", $http_config); }); check_accum_error_log(); $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); run_tests(); __DATA__ === TEST 1: get ngx.ctx --- config location = /t { content_by_lua_block { for i = 1, 100 do ngx.ctx.foo = i end ngx.say("ctx.foo = ", ngx.ctx.foo) } } --- request GET /t --- response_body ctx.foo = 100 --- no_error_log [error] -- NYI: bad argument --- error_log eval qr/\[TRACE\s+\d+\s+content_by_lua\(nginx\.conf:\d+\):2 loop\]/ === TEST 2: set ngx.ctx --- config location = /t { content_by_lua_block { for i = 1, 100 do ngx.ctx = {foo = i} end ngx.say("ctx.foo = ", ngx.ctx.foo) } } --- request GET /t --- response_body ctx.foo = 100 --- no_error_log [error] -- NYI: bad argument --- error_log eval qr/\[TRACE\s+\d+\s+content_by_lua\(nginx\.conf:\d+\):2 loop\]/ === TEST 3: ngx.ctx in ssl_certificate_by_lua --- http_config server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { ngx.ctx.answer = 42 ngx.log(ngx.WARN, "ngx.ctx.answer = ", ngx.ctx.answer) ngx.ctx.count = 0 } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { content_by_lua_block { ngx.say(ngx.ctx.answer) ngx.ctx.count = ngx.ctx.count + 1 ngx.say(ngx.ctx.count) } } } --- config lua_ssl_trusted_certificate ../../cert/test.crt; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end for i = 1, 2 do local req = "GET /foo HTTP/1.1\r\nHost: test.com\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end local body_seen = false while true do local line, err = sock:receive() if not line then break end if body_seen then if line == "0" then assert(sock:receive()) break end local line, err = sock:receive(line) ngx.print("received: ", line) assert(sock:receive()) elseif line == "" then body_seen = true end end end sock:close() end -- do -- collectgarbage() } } --- request GET /t --- response_body received: 42 received: 1 received: 42 received: 1 --- error_log ngx.ctx.answer = 42 --- grep_error_log eval qr/lua release ngx.ctx at ref \d+/ --- grep_error_log_out eval ["lua release ngx.ctx at ref 2 lua release ngx.ctx at ref 2 lua release ngx.ctx at ref 1 ", "lua release ngx.ctx at ref 2 lua release ngx.ctx at ref 2 lua release ngx.ctx at ref 1 lua release ngx.ctx at ref 2 lua release ngx.ctx at ref 2 lua release ngx.ctx at ref 1 "] --- no_error_log [error] === TEST 4: ngx.ctx in ssl_certificate_by_lua (share objects) --- http_config server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { ngx.ctx.req = { count = 0 } } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { content_by_lua_block { ngx.ctx.req.count = ngx.ctx.req.count + 1 ngx.say(ngx.ctx.req.count) } } } --- config lua_ssl_trusted_certificate ../../cert/test.crt; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end for i = 1, 2 do local req = "GET /foo HTTP/1.1\r\nHost: test.com\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end local body_seen = false while true do local line, err = sock:receive() if not line then break end if body_seen then if line == "0" then assert(sock:receive()) break end local line, err = sock:receive(line) ngx.print("received: ", line) assert(sock:receive()) elseif line == "" then body_seen = true end end end sock:close() end -- do -- collectgarbage() } } --- request GET /t --- response_body received: 1 received: 2 --- no_error_log [error] === TEST 5: ngx.ctx in ssl_certificate_by_lua (release ctx when client aborted) --- http_config server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" ssl.clear_certs() ngx.ctx.answer = 42 } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { return 200 "ok"; } } --- config lua_ssl_trusted_certificate ../../cert/test.crt; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) end sock:close() end -- do -- collectgarbage() } } --- request GET /t --- response_body failed to do SSL handshake: handshake failed --- grep_error_log eval qr/lua release ngx.ctx at ref \d+/ --- grep_error_log_out eval ["lua release ngx.ctx at ref 1 ", "lua release ngx.ctx at ref 1 lua release ngx.ctx at ref 1 "] === TEST 6: ngx.ctx in ssl_session_store_by_lua --- http_config ssl_session_store_by_lua_block { ngx.ctx.answer = 42 ngx.log(ngx.WARN, "ngx.ctx.answer = ", ngx.ctx.answer) ngx.ctx.count = 0 } server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_session_tickets off; ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { content_by_lua_block { ngx.say(ngx.ctx.answer) ngx.ctx.count = ngx.ctx.count + 1 ngx.say(ngx.ctx.count) } } } --- config lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_protocols TLSv1.2; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end for i = 1, 2 do local req = "GET /foo HTTP/1.1\r\nHost: test.com\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end local body_seen = false while true do local line, err = sock:receive() if not line then break end if body_seen then if line == "0" then assert(sock:receive()) break end local line, err = sock:receive(line) ngx.print("received: ", line) assert(sock:receive()) elseif line == "" then body_seen = true end end end package.loaded.session = sess sock:close() end -- do } } --- request GET /t --- response_body received: 42 received: 1 received: 42 received: 1 --- error_log ngx.ctx.answer = 42 --- grep_error_log eval qr/lua release ngx.ctx at ref \d+/ --- grep_error_log_out eval ["lua release ngx.ctx at ref 2 lua release ngx.ctx at ref 2 lua release ngx.ctx at ref 1 ", "lua release ngx.ctx at ref 2 lua release ngx.ctx at ref 2 lua release ngx.ctx at ref 1 lua release ngx.ctx at ref 2 lua release ngx.ctx at ref 2 lua release ngx.ctx at ref 1 "] --- no_error_log [error] === TEST 7: ngx.ctx in ssl_session_store_by_lua (release ctx when client aborted) --- http_config ssl_session_store_by_lua_block { ngx.ctx.answer = 42 } server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_session_tickets off; ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { return 200 "ok"; } } --- config lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_protocols TLSv1.2; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("closed") sock:close() end -- do } } --- request GET /t --- response_body closed --- grep_error_log eval qr/lua release ngx.ctx at ref \d+/ --- grep_error_log_out eval ["lua release ngx.ctx at ref 1 ", "lua release ngx.ctx at ref 1 lua release ngx.ctx at ref 1 "] --- no_error_log [error] === TEST 8: ngx.ctx in ssl_session_fetch_by_lua --- http_config ssl_session_fetch_by_lua_block { ngx.ctx.answer = 42 ngx.ctx.count = 0 } server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_session_tickets off; ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; ssl_protocols TLSv1.2; server_tokens off; location /foo { content_by_lua_block { if package.loaded.session then ngx.say(ngx.ctx.answer) ngx.ctx.count = ngx.ctx.count + 1 ngx.say(ngx.ctx.count) end } } } --- config lua_ssl_trusted_certificate ../../cert/test.crt; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end for i = 1, 2 do local req = "GET /foo HTTP/1.1\r\nHost: test.com\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end local body_seen = false while true do local line, err = sock:receive() if not line then break end if body_seen then if line == "0" then assert(sock:receive()) break end local line, err = sock:receive(line) ngx.log(ngx.WARN, "received: ", line) assert(sock:receive()) elseif line == "" then body_seen = true end end end package.loaded.session = sess sock:close() end -- do } } --- request GET /t --- grep_error_log eval qr/(received: \w+|lua release ngx.ctx at ref \d+)/ --- grep_error_log_out eval ["lua release ngx.ctx at ref 1 ", "lua release ngx.ctx at ref 1 lua release ngx.ctx at ref 2 received: 42 received: 1 lua release ngx.ctx at ref 2 received: 42 received: 1 lua release ngx.ctx at ref 1 "] --- no_error_log [error] === TEST 9: ngx.ctx in ssl_session_fetch_by_lua (release ctx when client aborted) --- http_config ssl_session_fetch_by_lua_block { ngx.ctx.answer = 42 } server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_session_tickets off; ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; ssl_protocols TLSv1.2; server_tokens off; location /foo { return 200 "ok"; } } --- config lua_ssl_trusted_certificate ../../cert/test.crt; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end package.loaded.session = sess ngx.say("closed") sock:close() end -- do } } --- request GET /t --- response_body closed --- grep_error_log eval qr/lua release ngx.ctx at ref \d+/ --- grep_error_log_out eval ["lua release ngx.ctx at ref 1 ", "lua release ngx.ctx at ref 1 lua release ngx.ctx at ref 1 "] --- no_error_log [error] === TEST 10: ngx.ctx in ssl* and other phases --- http_config ssl_session_store_by_lua_block { ngx.ctx.count = ngx.ctx.count and (ngx.ctx.count + 1) or 1 } ssl_session_fetch_by_lua_block { ngx.ctx.count = ngx.ctx.count and (ngx.ctx.count + 10) or 10 } server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_session_tickets off; ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; ssl_protocols TLSv1.2; ssl_certificate_by_lua_block { ngx.ctx.count = ngx.ctx.count and (ngx.ctx.count + 100) or 100 } server_tokens off; location /foo { content_by_lua_block { ngx.ctx.count = ngx.ctx.count + 1 ngx.say(ngx.ctx.count) } } } --- config lua_ssl_trusted_certificate ../../cert/test.crt; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end for i = 1, 2 do local req = "GET /foo HTTP/1.1\r\nHost: test.com\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end local body_seen = false while true do local line, err = sock:receive() if not line then break end if body_seen then if line == "0" then assert(sock:receive()) break end local line, err = sock:receive(line) ngx.log(ngx.WARN, "received: ", line) assert(sock:receive()) elseif line == "" then body_seen = true end end end package.loaded.session = sess sock:close() end -- do } } --- request GET /t --- grep_error_log eval qr/(received: \w+|lua release ngx.ctx at ref \d+)/ --- grep_error_log_out eval ["lua release ngx.ctx at ref 2 received: 112 lua release ngx.ctx at ref 2 received: 112 lua release ngx.ctx at ref 1 ", "lua release ngx.ctx at ref 2 received: 112 lua release ngx.ctx at ref 2 received: 112 lua release ngx.ctx at ref 1 lua release ngx.ctx at ref 2 received: 112 lua release ngx.ctx at ref 2 received: 112 lua release ngx.ctx at ref 1 "] --- no_error_log [error] === TEST 11: overwrite values will only take affect in the current http request --- http_config server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { ngx.ctx.answer = 0 } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo1 { content_by_lua_block { ngx.say(ngx.ctx.answer) ngx.ctx.answer = 42 } } location /foo2 { content_by_lua_block { ngx.say(ngx.ctx.answer) } } } --- config lua_ssl_trusted_certificate ../../cert/test.crt; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end for i = 1, 2 do local req = "GET /foo" .. i .. " HTTP/1.1\r\nHost: test.com\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end local body_seen = false while true do local line, err = sock:receive() if not line then break end if body_seen then if line == "0" then assert(sock:receive()) break end local line, err = sock:receive(line) ngx.print("received: ", line) assert(sock:receive()) elseif line == "" then body_seen = true end end end sock:close() end -- do -- collectgarbage() } } --- request GET /t --- response_body received: 0 received: 0 === TEST 12: prohibit setting ngx.ctx to non-table value --- config location = /t { content_by_lua_block { local ok, err = pcall(function() ngx.ctx = nil end) if not ok then ngx.say(err) end } } --- request GET /t --- response_body_like ctx should be a table while getting a nil --- no_error_log [error] === TEST 13: get_ctx_table --- config location = /t { content_by_lua_block { local get_ctx_table = require "resty.core.ctx" .get_ctx_table local reused_ctx = {} local ctx = get_ctx_table(reused_ctx) if ctx == reused_ctx then ngx.say("reused") end local ctx2 = get_ctx_table() if ctx2 == reused_ctx then ngx.say("reused again") end } } --- request GET /t --- response_body reused reused again --- no_error_log [error] === TEST 14: ngx.ctx in ssl_client_hello_by_lua --- http_config server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_client_hello_by_lua_block { ngx.ctx.answer = 42 ngx.log(ngx.WARN, "ngx.ctx.answer = ", ngx.ctx.answer) ngx.ctx.count = 0 } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { content_by_lua_block { ngx.say(ngx.ctx.answer) ngx.ctx.count = ngx.ctx.count + 1 ngx.say(ngx.ctx.count) } } } --- config lua_ssl_trusted_certificate ../../cert/test.crt; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end for i = 1, 2 do local req = "GET /foo HTTP/1.1\r\nHost: test.com\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end local body_seen = false while true do local line, err = sock:receive() if not line then break end if body_seen then if line == "0" then assert(sock:receive()) break end local line, err = sock:receive(line) ngx.print("received: ", line) assert(sock:receive()) elseif line == "" then body_seen = true end end end sock:close() end -- do -- collectgarbage() } } --- request GET /t --- response_body received: 42 received: 1 received: 42 received: 1 --- error_log ngx.ctx.answer = 42 --- grep_error_log eval qr/lua release ngx.ctx at ref \d+/ --- grep_error_log_out eval ["lua release ngx.ctx at ref 2 lua release ngx.ctx at ref 2 lua release ngx.ctx at ref 1 ", "lua release ngx.ctx at ref 2 lua release ngx.ctx at ref 2 lua release ngx.ctx at ref 1 lua release ngx.ctx at ref 2 lua release ngx.ctx at ref 2 lua release ngx.ctx at ref 1 "] --- no_error_log [error] lua-resty-core-0.1.31/t/decode-base64.t000066400000000000000000000243701474236722600174270ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(1014); #master_process_enabled(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 5 - 2); #no_diff(); #no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: string --- config location = /base64 { content_by_lua_block { local s for i = 1, 100 do s = ngx.decode_base64("aGVsbG8=") end ngx.say(s) } } --- request GET /base64 --- response_body hello --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] -- NYI: === TEST 2: set base64 (nil) --- config location = /base64 { content_by_lua_block { local s for i = 1, 100 do s = ngx.decode_base64("") end ngx.say(s) } } --- request GET /base64 --- response_body eval: "\n" --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] -- NYI: === TEST 3: set base64 (number) --- config location = /base64 { content_by_lua_block { local s for i = 1, 100 do s = ngx.decode_base64("My4xNA==") end ngx.say(s) } } --- request GET /base64 --- response_body 3.14 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] -- NYI: === TEST 4: set base64 (boolean) --- config location = /base64 { content_by_lua_block { local s for i = 1, 100 do s = ngx.decode_base64("dHJ1ZQ==") end ngx.say(s) } } --- request GET /base64 --- response_body true --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] -- NYI: === TEST 5: string (buf size just smaller than 4096) --- config location = /base64 { content_by_lua_block { local s for i = 1, 100 do s = ngx.decode_base64(string.rep("a", 5460)) end if not s then ngx.say("bad base64 string") else ngx.say(string.len(s)) end } } --- request GET /base64 --- response_body 4095 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] -- NYI: === TEST 6: string (buf size just a bit bigger than 4096) --- config location = /base64 { content_by_lua_block { local s for i = 1, 100 do s = ngx.decode_base64(string.rep("a", 5462)) end if not s then ngx.say("bad base64 string") else ngx.say(string.len(s)) end } } --- request GET /base64 --- response_body 4096 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] -- NYI: === TEST 7: decode_base64url --- config location = /t { content_by_lua_block { local enc = require("ngx.base64") local function to_hex(str) return (str:gsub('.', function(c) return string.format('%02x', string.byte(c)) end)) end -- RFC 4648 test vectors ngx.say("decode_base64url(\"\") = \"", enc.decode_base64url(""), "\"") ngx.say("decode_base64url(\"Zg\") = \"", enc.decode_base64url("Zg"), "\"") ngx.say("decode_base64url(\"Zm8\") = \"", enc.decode_base64url("Zm8"), "\"") ngx.say("decode_base64url(\"Zm9v\") = \"", enc.decode_base64url("Zm9v"), "\"") ngx.say("decode_base64url(\"Zm9vYg\") = \"", enc.decode_base64url("Zm9vYg"), "\"") ngx.say("decode_base64url(\"Zm9vYmE\") = \"", enc.decode_base64url("Zm9vYmE"), "\"") ngx.say("decode_base64url(\"Zm9vYmFy\") = \"", enc.decode_base64url("Zm9vYmFy"), "\"") ngx.say("decode_base64url(\"_w\") = \"\\x", to_hex(enc.decode_base64url("_w")), "\"") ngx.say("decode_base64url(\"YQBi\") = \"\\x", to_hex(enc.decode_base64url("YQBi")), "\"") } } --- request GET /t --- response_body decode_base64url("") = "" decode_base64url("Zg") = "f" decode_base64url("Zm8") = "fo" decode_base64url("Zm9v") = "foo" decode_base64url("Zm9vYg") = "foob" decode_base64url("Zm9vYmE") = "fooba" decode_base64url("Zm9vYmFy") = "foobar" decode_base64url("_w") = "\xff" decode_base64url("YQBi") = "\x610062" --- no_error_log [error] [crit] === TEST 8: decode_base64url with invalid input --- config location = /t { content_by_lua_block { local enc = require("ngx.base64") local res, err = enc.decode_base64url(" ") ngx.say("decode_base64url returned: ", res, ", ", err) } } --- request GET /t --- response_body decode_base64url returned: nil, invalid input --- no_error_log [error] -- NYI: === TEST 9: decode_base64mime decode with newlines ('\n') inserted after every 76 characters --- http_config eval: $::HttpConfig --- config location = /base64mime { content_by_lua_block { local s for i = 1, 100 do s = ngx.decode_base64mime("T3BlblJlc3R5IGlzIGEgZnVsbC1mbGVkZ2VkIHdlYiBwbGF0Zm9ybSB0aGF0IGludGVncmF0ZXMg\ndGhlIHN0YW5kYXJkIE5naW54IGNvcmUsIEx1YUpJVCwgbWFueSBjYXJlZnVsbHkgd3JpdHRlbiBM\ndWEgbGlicmFyaWVzLCBsb3RzIG9mIGhpZ2ggcXVhbGl0eSAzcmQtcGFydHkgTmdpbnggbW9kdWxl\ncywgYW5kIG1vc3Qgb2YgdGhlaXIgZXh0ZXJuYWwgZGVwZW5kZW5jaWVzLiBJdCBpcyBkZXNpZ25l\nZCB0byBoZWxwIGRldmVsb3BlcnMgZWFzaWx5IGJ1aWxkIHNjYWxhYmxlIHdlYiBhcHBsaWNhdGlv\nbnMsIHdlYiBzZXJ2aWNlcywgYW5kIGR5bmFtaWMgd2ViIGdhdGV3YXlzLg==\n") end ngx.say(s) } } --- request GET /base64mime --- response_body OpenResty is a full-fledged web platform that integrates the standard Nginx core, LuaJIT, many carefully written Lua libraries, lots of high quality 3rd-party Nginx modules, and most of their external dependencies. It is designed to help developers easily build scalable web applications, web services, and dynamic web gateways. --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] -- NYI: === TEST 10: decode_base64mime decode with random newlines ('\n') inserted --- http_config eval: $::HttpConfig --- config location = /base64mime { content_by_lua_block { local s for i = 1, 100 do s = ngx.decode_base64mime("T\n3BlblJ\nlc3R5IGlzIGEgZnVsbC1mbGVkZ2VkIHdlYiBwb\nGF0Zm9ybSB0aGF0IGludGVncmF0ZXMg\ndGhlIHN0YW5kYXJkIE5naW54IGNvcmUsIEx1YUpJVCwgbWFueSBjYXJlZnVsbHkgd3JpdHRlbiBM\ndWEgbGlicmFyaWVz\nLCBsb3RzIG9mIGhpZ2ggcXVhbGl0eSAzcmQtcGFydHkgTmdpbnggbW9kdWxl\ncywgYW5kIG1vc3Qgb2YgdGhlaXIgZXh0ZXJuYWwgZGVwZW5kZW5jaWVzLiBJdCBpcyBkZXNpZ25l\nZCB0byBoZWxwIGRldmVsb3BlcnMgZWFzaWx5IGJ1aWxkIHNjYWxhYmxlIHdlYiBhcHBsaWNhdGlv\nbnMsIHdlYiBzZXJ2aWNlc\nywgYW5kIGR5bmFtaWMgd2ViIGdhdGV3YXlzLg==\n") end ngx.say(s) } } --- request GET /base64mime --- response_body OpenResty is a full-fledged web platform that integrates the standard Nginx core, LuaJIT, many carefully written Lua libraries, lots of high quality 3rd-party Nginx modules, and most of their external dependencies. It is designed to help developers easily build scalable web applications, web services, and dynamic web gateways. --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] -- NYI: === TEST 11: decode_base64mime decode with characters outside alphabet --- http_config eval: $::HttpConfig --- config location = /base64mime { content_by_lua_block { local s for i = 1, 100 do s = ngx.decode_base64mime("!T3B#lblJl@c3R5IG\rlzIGEgZnVs\nbC1mbGVkZ2Vk&IHdlYiBwbG'F0Zm9ybSB0aGF0[IGludGVncmF0ZXMg\ndGhlIHN0YW]5kYXJkIE5naW54IGNvcmUsIEx1-YUpJVCwg_bWFueSBjYXJlZnVsbHkgd3JpdHRlbiBM\ndWEgbGlicmFyaWVzLCBsb3R$zIG9mIGhpZ2%ggcXVhbGl0eSAzcmQ^tcGFydHkgTm&dpbnggbW9kdWxl\ncywgYW5kIG1vc3Qgb2YgdGhlaXIgZXh0ZXJuYWwgZGVwZW5kZW5jaWVzLiBJdCBpcyBkZXNpZ25l\nZCB0byBoZWxwIGRldmVsb3BlcnMgZWFzaWx5IGJ1aWxkIHNjYWxhYmxlIHdlYiBhcHBsaWNhdGlv\nbnMsIHdlYiBzZXJ2aWNlcywgYW5kIGR5bmFtaWMgd2ViIGdhdGV3YXlzLg==\n") end ngx.say(s) } } --- request GET /base64mime --- response_body OpenResty is a full-fledged web platform that integrates the standard Nginx core, LuaJIT, many carefully written Lua libraries, lots of high quality 3rd-party Nginx modules, and most of their external dependencies. It is designed to help developers easily build scalable web applications, web services, and dynamic web gateways. --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] -- NYI: === TEST 12: decode_base64mime decode not well formed string --- http_config eval: $::HttpConfig --- config location = /base64mime { content_by_lua_block { local s for i = 1, 100 do s = ngx.decode_base64mime('zaaLg==') end ngx.say(s) } } --- request GET /base64mime --- response_body nil --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] -- NYI: === TEST 13: decode_base64mime decode empty string --- http_config eval: $::HttpConfig --- config location = /base64mime { content_by_lua_block { local s for i = 1, 100 do s = ngx.decode_base64mime('') end ngx.say(s .. 'empty') } } --- request GET /base64mime --- response_body empty --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] -- NYI: === TEST 14: decode_base64mime decode outside the base encoding alphabet string --- http_config eval: $::HttpConfig --- config location = /base64mime { content_by_lua_block { local s for i = 1, 100 do s = ngx.decode_base64mime('^&$') end ngx.say(s .. 'empty') } } --- request GET /base64mime --- response_body empty --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] -- NYI: lua-resty-core-0.1.31/t/encode-base64.t000066400000000000000000000120551474236722600174360ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(1014); #master_process_enabled(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 5 - 1); #no_diff(); #no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: set base64 (string) --- config location = /base64 { content_by_lua_block { local s for i = 1, 100 do s = ngx.encode_base64("hello") end ngx.say(s) } } --- request GET /base64 --- response_body aGVsbG8= --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] -- NYI: === TEST 2: set base64 (nil) --- config location = /base64 { content_by_lua_block { local s for i = 1, 100 do s = ngx.encode_base64(nil) end ngx.say(s) } } --- request GET /base64 --- response_body eval: "\n" --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] -- NYI: === TEST 3: set base64 (number) --- config location = /base64 { content_by_lua_block { local s for i = 1, 100 do s = ngx.encode_base64(3.14) end ngx.say(s) } } --- request GET /base64 --- response_body My4xNA== --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] -- NYI: === TEST 4: set base64 (boolean) --- config location = /base64 { content_by_lua_block { local s for i = 1, 100 do s = ngx.encode_base64(true) end ngx.say(s) } } --- request GET /base64 --- response_body dHJ1ZQ== --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] -- NYI: === TEST 5: set base64 (buf is a little larger than 4096) --- config location = /base64 { content_by_lua_block { local s for i = 1, 100 do s = ngx.encode_base64(string.rep("a", 3073)) end ngx.say(string.len(s)) } } --- request GET /base64 --- response_body 4100 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] -- NYI: === TEST 6: set base64 (buf is just 4096) --- config location = /base64 { content_by_lua_block { local s for i = 1, 100 do s = ngx.encode_base64(string.rep("a", 3071)) end ngx.say(string.len(s)) } } --- request GET /base64 --- response_body 4096 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] -- NYI: === TEST 7: set base64 (number) without padding (explicitly specified) --- config location = /base64 { content_by_lua_block { local s for i = 1, 200 do s = ngx.encode_base64(3.14, true) end ngx.say(s) } } --- request GET /base64 --- response_body My4xNA --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] -- NYI: === TEST 8: set base64 (number) with padding (explicitly specified) --- config location = /base64 { content_by_lua_block { local s for i = 1, 200 do s = ngx.encode_base64(3.14, false) end ngx.say(s) } } --- request GET /base64 --- response_body My4xNA== --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] -- NYI: === TEST 9: encode_base64url --- config location = /t { content_by_lua_block { local enc = require("ngx.base64") -- RFC 4648 test vectors ngx.say("encode_base64url(\"\") = \"", enc.encode_base64url(""), "\"") ngx.say("encode_base64url(\"f\") = \"", enc.encode_base64url("f"), "\"") ngx.say("encode_base64url(\"fo\") = \"", enc.encode_base64url("fo"), "\"") ngx.say("encode_base64url(\"foo\") = \"", enc.encode_base64url("foo"), "\"") ngx.say("encode_base64url(\"foob\") = \"", enc.encode_base64url("foob"), "\"") ngx.say("encode_base64url(\"fooba\") = \"", enc.encode_base64url("fooba"), "\"") ngx.say("encode_base64url(\"foobar\") = \"", enc.encode_base64url("foobar"), "\"") ngx.say("encode_base64url(\"\\xff\") = \"", enc.encode_base64url("\xff"), "\"") ngx.say("encode_base64url(\"a\\0b\") = \"", enc.encode_base64url("a\0b"), "\"") } } --- request GET /t --- response_body encode_base64url("") = "" encode_base64url("f") = "Zg" encode_base64url("fo") = "Zm8" encode_base64url("foo") = "Zm9v" encode_base64url("foob") = "Zm9vYg" encode_base64url("fooba") = "Zm9vYmE" encode_base64url("foobar") = "Zm9vYmFy" encode_base64url("\xff") = "_w" encode_base64url("a\0b") = "YQBi" --- no_error_log [error] -- NYI: lua-resty-core-0.1.31/t/errlog-raw-log.t000066400000000000000000000107761474236722600177670ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; log_level('error'); repeat_each(1); plan tests => repeat_each() * (blocks() * 2 + 5); add_block_preprocessor(sub { my $block = shift; my $http_config = $block->http_config || ''; my $init_by_lua_block = $block->init_by_lua_block || ''; $http_config .= <<_EOC_; lua_package_path '$t::TestCore::lua_package_path'; init_by_lua_block { $t::TestCore::init_by_lua_block $init_by_lua_block } _EOC_ $block->set_value("http_config", $http_config); }); no_long_string(); run_tests(); __DATA__ === TEST 1: errlog.raw_log with bad log level (ngx.ERROR, -1) --- config location /log { content_by_lua_block { local errlog = require "ngx.errlog" errlog.raw_log(ngx.ERROR, "hello, log") ngx.say("done") } } --- request GET /log --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log bad log level === TEST 2: errlog.raw_log with bad levels (9) --- config location /log { content_by_lua_block { local errlog = require "ngx.errlog" errlog.raw_log(9, "hello, log") ngx.say("done") } } --- request GET /log --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log bad log level === TEST 3: errlog.raw_log with bad log message --- config location /log { content_by_lua_block { local errlog = require "ngx.errlog" errlog.raw_log(ngx.ERR, 123) ngx.say("done") } } --- request GET /log --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log bad argument #2 to 'raw_log' (must be a string) === TEST 4: errlog.raw_log test log-level ERR --- config location /log { content_by_lua_block { local errlog = require "ngx.errlog" errlog.raw_log(ngx.ERR, "hello world") } } --- request GET /log --- error_log eval qr/\[error\] \S+: \S+ hello world/ === TEST 5: errlog.raw_log JITs --- init_by_lua_block -- local verbose = true local verbose = false local outfile = errlog_file -- local outfile = "/tmp/v.log" if verbose then local dump = require "jit.dump" dump.on(nil, outfile) else local v = require "jit.v" v.on(outfile) end require "resty.core" -- jit.opt.start("hotloop=1") -- jit.opt.start("loopunroll=1000000") -- jit.off() --- config location /log { content_by_lua_block { local errlog = require "ngx.errlog" for i = 1, 100 do errlog.raw_log(ngx.ERR, "hello world") end } } --- request GET /log --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx.conf:\d+\):4 loop\]/ === TEST 6: errlog.raw_log in init_by_lua --- init_by_lua_block local errlog = require "ngx.errlog" errlog.raw_log(ngx.ERR, "hello world from init_by_lua") --- config location /t { return 200; } --- request GET /t --- grep_error_log chop hello world from init_by_lua --- grep_error_log_out eval ["hello world from init_by_lua\n", ""] === TEST 7: errlog.raw_log in init_worker_by_lua --- http_config init_worker_by_lua_block { local errlog = require "ngx.errlog" errlog.raw_log(ngx.ERR, "hello world from init_worker_by_lua") } --- config location /t { return 200; } --- request GET /t --- grep_error_log chop hello world from init_worker_by_lua --- grep_error_log_out eval ["hello world from init_worker_by_lua\n", ""] === TEST 8: errlog.raw_log with \0 in the log message --- config location /log { content_by_lua_block { local errlog = require "ngx.errlog" errlog.raw_log(ngx.ERR, "hello\0world") ngx.say("ok") } } --- request GET /log --- response_body ok --- error_log eval "hello\0world, client: " === TEST 9: errlog.raw_log is captured by errlog.get_logs() --- http_config lua_capture_error_log 4k; --- config location /log { content_by_lua_block { local errlog = require "ngx.errlog" errlog.raw_log(ngx.ERR, "hello from raw_log()") local res, err = errlog.get_logs() if not res then error("FAILED " .. err) end ngx.say("log lines: ", #res / 3) } } --- request GET /log --- response_body log lines: 1 --- error_log eval qr/\[error\] .*? hello from raw_log\(\)/ --- skip_nginx: 3: <1.11.2 lua-resty-core-0.1.31/t/errlog.t000066400000000000000000001040341474236722600164100ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(1014); #master_process_enabled(1); log_level('error'); repeat_each(2); plan tests => repeat_each() * (blocks() * 2 + 15); add_block_preprocessor(sub { my $block = shift; my $http_config = $block->http_config || ''; my $init_by_lua_block = $block->init_by_lua_block || ''; $http_config .= <<_EOC_; lua_package_path '$t::TestCore::lua_package_path'; init_by_lua_block { $t::TestCore::init_by_lua_block $init_by_lua_block } _EOC_ $block->set_value("http_config", $http_config); }); #no_diff(); no_long_string(); #check_accum_error_log(); run_tests(); __DATA__ === TEST 1: sanity --- http_config lua_capture_error_log 4m; --- config location /t { access_by_lua_block { ngx.log(ngx.ERR, "enter 1") ngx.log(ngx.ERR, "enter 11") local errlog = require "ngx.errlog" local res, err = errlog.get_logs() if not res then error("FAILED " .. err) end ngx.say("log lines:", #res / 3) } } --- request GET /t --- response_body log lines:2 --- grep_error_log eval qr/enter \d+/ --- grep_error_log_out eval [ "enter 1 enter 11 ", "enter 1 enter 11 " ] --- skip_nginx: 3: <1.11.2 === TEST 2: overflow captured error logs --- http_config lua_capture_error_log 4k; --- config location /t { access_by_lua_block { ngx.log(ngx.ERR, "enter 1") ngx.log(ngx.ERR, "enter 22" .. string.rep("a", 4096)) local errlog = require "ngx.errlog" local res, err = errlog.get_logs() if not res then error("FAILED " .. err) end ngx.say("log lines:", #res / 3) } } --- request GET /t --- response_body log lines:1 --- grep_error_log eval qr/enter \d+/ --- grep_error_log_out eval [ "enter 1 enter 22 ", "enter 1 enter 22 " ] --- skip_nginx: 3: <1.11.2 === TEST 3: 404 error (not found) --- http_config lua_capture_error_log 4m; --- config log_by_lua_block { local errlog = require "ngx.errlog" local res, err = errlog.get_logs() if not res then error("FAILED " .. err) end ngx.log(ngx.ERR, "capture log line:", #res / 3) } --- request GET /t --- error_code: 404 --- grep_error_log eval qr/capture log line:\d+|No such file or directory/ --- grep_error_log_out eval [ qr/^No such file or directory capture log line:1 $/, qr/^No such file or directory capture log line:2 $/ ] --- skip_nginx: 2: <1.11.2 === TEST 4: 500 error --- http_config lua_capture_error_log 4m; --- config location /t { content_by_lua_block { local t = {}/4 } } log_by_lua_block { local errlog = require "ngx.errlog" local res, err = errlog.get_logs() if not res then error("FAILED " .. err) end ngx.log(ngx.ERR, "capture log line:", #res / 3) } --- request GET /t --- error_code: 500 --- grep_error_log eval qr/capture log line:\d+|attempt to perform arithmetic on a table value/ --- grep_error_log_out eval [ qr/^attempt to perform arithmetic on a table value capture log line:1 $/, qr/^attempt to perform arithmetic on a table value capture log line:2 $/ ] --- skip_nginx: 2: <1.11.2 === TEST 5: no error log --- http_config lua_capture_error_log 4m; --- config location /t { echo "hello"; } log_by_lua_block { local errlog = require "ngx.errlog" local res, err = errlog.get_logs() if not res then error("FAILED " .. err) end ngx.log(ngx.ERR, "capture log line:", #res / 3) } --- request GET /t --- response_body hello --- grep_error_log eval qr/capture log line:\d+/ --- grep_error_log_out eval [ qr/^capture log line:0 $/, qr/^capture log line:1 $/ ] --- skip_nginx: 3: <1.11.2 === TEST 6: customize the log path --- http_config lua_capture_error_log 4m; error_log logs/error_http.log error; --- config location /t { error_log logs/error.log error; access_by_lua_block { ngx.log(ngx.ERR, "enter access /t") } echo "hello"; } log_by_lua_block { local errlog = require "ngx.errlog" local res, err = errlog.get_logs() if not res then error("FAILED " .. err) end ngx.log(ngx.ERR, "capture log line:", #res / 3) } --- request GET /t --- response_body hello --- grep_error_log eval qr/capture log line:\d+|enter access/ --- grep_error_log_out eval [ qr/^enter access capture log line:1 $/, qr/^enter access capture log line:2 $/ ] --- skip_nginx: 3: <1.11.2 === TEST 7: invalid size (< 4k) --- http_config lua_capture_error_log 3k; --- config location /t { echo "hello"; } --- must_die --- error_log invalid capture error log size "3k", minimum size is 4096 --- skip_nginx: 2: <1.11.2 === TEST 8: invalid size (no argu) --- http_config lua_capture_error_log; --- config location /t { echo "hello"; } --- must_die --- error_log invalid number of arguments in "lua_capture_error_log" directive --- skip_nginx: 2: <1.11.2 === TEST 9: without directive + ngx.errlog --- config location /t { access_by_lua_block { ngx.log(ngx.ERR, "enter 1") local errlog = require "ngx.errlog" local res, err = errlog.get_logs() if not res then error("FAILED " .. err) end ngx.say("log lines:", #res / 3) } } --- request GET /t --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log directive "lua_capture_error_log" is not set --- skip_nginx: 3: <1.11.2 === TEST 10: without directive + ngx.set_filter_level --- config location /t { access_by_lua_block { local errlog = require "ngx.errlog" local status, err = errlog.set_filter_level(ngx.ERR) if not status then error(err) end } } --- request GET /t --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log directive "lua_capture_error_log" is not set --- skip_nginx: 3: <1.11.2 === TEST 11: filter log by level(ngx.INFO) --- http_config lua_capture_error_log 4m; --- config location /t { access_by_lua_block { local errlog = require "ngx.errlog" local status, err = errlog.set_filter_level(ngx.INFO) if not status then error(err) end ngx.log(ngx.INFO, "-->1") ngx.log(ngx.WARN, "-->2") ngx.log(ngx.ERR, "-->3") } content_by_lua_block { local errlog = require "ngx.errlog" local res = errlog.get_logs() ngx.say("log lines:", #res / 3) } } --- log_level: info --- request GET /t --- response_body log lines:3 --- grep_error_log eval qr/-->\d+/ --- grep_error_log_out eval [ "-->1 -->2 -->3 ", "-->1 -->2 -->3 " ] --- skip_nginx: 3: <1.11.2 === TEST 12: filter log by level(ngx.WARN) --- http_config lua_capture_error_log 4m; --- config location /t { access_by_lua_block { local errlog = require "ngx.errlog" local status, err = errlog.set_filter_level(ngx.WARN) if not status then error(err) end ngx.log(ngx.INFO, "-->1") ngx.log(ngx.WARN, "-->2") ngx.log(ngx.ERR, "-->3") } content_by_lua_block { local errlog = require "ngx.errlog" local res = errlog.get_logs() ngx.say("log lines:", #res / 3) } } --- log_level: info --- request GET /t --- response_body log lines:2 --- grep_error_log eval qr/-->\d+/ --- grep_error_log_out eval [ "-->1 -->2 -->3 ", "-->1 -->2 -->3 " ] --- skip_nginx: 3: <1.11.2 === TEST 13: filter log by level(ngx.CRIT) --- http_config lua_capture_error_log 4m; --- log_level: info --- config location /t { access_by_lua_block { local errlog = require "ngx.errlog" local status, err = errlog.set_filter_level(ngx.CRIT) if not status then error(err) end ngx.log(ngx.INFO, "-->1") ngx.log(ngx.WARN, "-->2") ngx.log(ngx.ERR, "-->3") } content_by_lua_block { local errlog = require "ngx.errlog" local res = errlog.get_logs() ngx.say("log lines:", #res / 3) } } --- request GET /t --- response_body log lines:0 --- grep_error_log eval qr/-->\d+/ --- grep_error_log_out eval [ "-->1 -->2 -->3 ", "-->1 -->2 -->3 " ] --- skip_nginx: 3: <1.11.2 === TEST 14: set max count and reuse table --- http_config lua_capture_error_log 4m; --- config location /t { access_by_lua_block { tab_clear = require "table.clear" ngx.log(ngx.ERR, "enter 1") ngx.log(ngx.ERR, "enter 22") ngx.log(ngx.ERR, "enter 333") local errlog = require "ngx.errlog" local res = {} local err res, err = errlog.get_logs(2, res) if not res then error("FAILED " .. err) end ngx.say("log lines:", #res / 3) tab_clear(res) res, err = errlog.get_logs(2, res) if not res then error("FAILED " .. err) end ngx.say("log lines:", #res / 3) } } --- request GET /t --- response_body log lines:2 log lines:1 --- skip_nginx: 2: <1.11.2 === TEST 15: wrong argument --- http_config lua_capture_error_log 4m; --- config location /t { access_by_lua_block { local errlog = require "ngx.errlog" local status, err = errlog.set_filter_level() if not status then error(err) end } } --- request GET /t --- error_code: 500 --- response_body_like: 500 --- grep_error_log eval qr/missing \"level\" argument/ --- grep_error_log_out eval [ "missing \"level\" argument ", "missing \"level\" argument ", ] --- skip_nginx: 3: <1.11.2 === TEST 16: check the captured error log body --- http_config lua_capture_error_log 4m; --- config location /t { access_by_lua_block { local errlog = require "ngx.errlog" local status, err = errlog.set_filter_level(ngx.WARN) if not status then error(err) end ngx.log(ngx.INFO, "-->1") ngx.log(ngx.WARN, "-->2") ngx.log(ngx.ERR, "-->3") } content_by_lua_block { local errlog = require "ngx.errlog" local res = errlog.get_logs() for i = 1, #res, 3 do ngx.say("log level:", res[i]) ngx.say("log body:", res[i + 2]) end } } --- log_level: info --- request GET /t --- response_body_like log level:5 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[warn\] (\d+).*access_by_lua\(nginx.conf:\d+\):\d+: -->2, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*access_by_lua\(nginx.conf:\d+\):\d+: -->3, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" --- grep_error_log eval qr/-->\d+/ --- grep_error_log_out eval [ "-->1 -->2 -->3 ", "-->1 -->2 -->3 " ] --- skip_nginx: 3: <1.11.2 === TEST 17: flood the capturing buffer (4k) --- http_config lua_capture_error_log 4k; --- config location /t { access_by_lua_block { local errlog = require "ngx.errlog" local status, err = errlog.set_filter_level(ngx.WARN) if not status then error(err) end for i = 1, 100 do ngx.log(ngx.INFO, "--> ", i) ngx.log(ngx.WARN, "--> ", i) ngx.log(ngx.ERR, "--> ", i) end } content_by_lua_block { local errlog = require "ngx.errlog" local res = errlog.get_logs(1000) ngx.say("log lines: #", #res / 3) -- first 3 logs for i = 1, 3 * 3, 3 do ngx.say("log level:", res[i]) ngx.say("log body:", res[i + 2]) end -- last 3 logs for i = #res - 8, #res, 3 do ngx.say("log level:", res[i]) ngx.say("log body:", res[i + 2]) end } } --- log_level: info --- request GET /t --- response_body_like chomp \A(?:log lines: #21 log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*access_by_lua\(nginx.conf:\d+\):\d+: --> 90, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" log level:5 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[warn\] (\d+).*access_by_lua\(nginx.conf:\d+\):\d+: --> 91, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*access_by_lua\(nginx.conf:\d+\):\d+: --> 99, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" log level:5 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[warn\] (\d+).*access_by_lua\(nginx.conf:\d+\):\d+: --> 100, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*access_by_lua\(nginx.conf:\d+\):\d+: --> 100, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" |log lines: #20 log level:5 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[warn\] (\d+).*access_by_lua\(nginx.conf:\d+\):\d+: --> 91, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*access_by_lua\(nginx.conf:\d+\):\d+: --> 91, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" log level:5 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[warn\] (\d+).*access_by_lua\(nginx.conf:\d+\):\d+: --> 92, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*access_by_lua\(nginx.conf:\d+\):\d+: --> 99, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" log level:5 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[warn\] (\d+).*access_by_lua\(nginx.conf:\d+\):\d+: --> 100, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*access_by_lua\(nginx.conf:\d+\):\d+: --> 100, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" )\z --- skip_nginx: 2: <1.11.2 --- wait: 0.1 === TEST 18: flood the capturing buffer (5k) --- http_config lua_capture_error_log 5k; --- config location /t { access_by_lua_block { local errlog = require "ngx.errlog" local status, err = errlog.set_filter_level(ngx.WARN) if not status then error(err) end for i = 1, 100 do ngx.log(ngx.INFO, "--> ", i) ngx.log(ngx.WARN, "--> ", i) ngx.log(ngx.ERR, "--> ", i) end } content_by_lua_block { local errlog = require "ngx.errlog" local res = errlog.get_logs(1000) ngx.say("log lines: #", #res / 3) -- first 3 logs for i = 1, 3 * 3, 3 do ngx.say("log level:", res[i]) ngx.say("log body:", res[i + 2]) end -- last 3 logs for i = #res - 8, #res, 3 do ngx.say("log level:", res[i]) ngx.say("log body:", res[i + 2]) end } } --- log_level: info --- request GET /t --- response_body_like chomp \Alog lines: #26 log level:5 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[warn\] (\d+).*access_by_lua\(nginx.conf:\d+\):\d+: --> 88, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*access_by_lua\(nginx.conf:\d+\):\d+: --> 88, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" log level:5 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[warn\] (\d+).*access_by_lua\(nginx.conf:\d+\):\d+: --> 89, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*access_by_lua\(nginx.conf:\d+\):\d+: --> 99, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" log level:5 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[warn\] (\d+).*access_by_lua\(nginx.conf:\d+\):\d+: --> 100, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*access_by_lua\(nginx.conf:\d+\):\d+: --> 100, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" \z --- skip_nginx: 2: <1.11.2 === TEST 19: fetch a few and generate a few, then fetch again (overflown again) --- http_config lua_capture_error_log 5k; --- config location /t { access_by_lua_block { local errlog = require "ngx.errlog" local status, err = errlog.set_filter_level(ngx.WARN) if not status then error(err) end for i = 1, 100 do ngx.log(ngx.INFO, "--> ", i) ngx.log(ngx.WARN, "--> ", i) ngx.log(ngx.ERR, "--> ", i) end } content_by_lua_block { local errlog = require "ngx.errlog" local res = errlog.get_logs(3) ngx.say("msg count: ", #res / 3) -- first 3 logs for i = 1, #res, 3 do ngx.say("log level:", res[i]) ngx.say("log body:", res[i + 2]) end ngx.log(ngx.ERR, "--> 101") ngx.log(ngx.ERR, "--> 102") ngx.log(ngx.ERR, "--> 103") ngx.log(ngx.ERR, "--> 104") local res = errlog.get_logs(3) ngx.say("msg count: ", #res / 3) -- first 3 logs for i = 1, #res, 3 do ngx.say("log level:", res[i]) ngx.say("log body:", res[i + 2]) end local res = errlog.get_logs(1000) -- last 3 logs for i = #res - 8, #res, 3 do ngx.say("log level:", res[i]) ngx.say("log body:", res[i + 2]) end } } --- log_level: info --- request GET /t --- response_body_like chomp \Amsg count: 3 log level:5 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[warn\] (\d+).*?access_by_lua\(nginx.conf:\d+\):\d+: --> 88, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?access_by_lua\(nginx.conf:\d+\):\d+: --> 88, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" log level:5 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[warn\] (\d+).*?access_by_lua\(nginx.conf:\d+\):\d+: --> 89, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" msg count: 3 log level:5 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[warn\] (\d+).*?access_by_lua\(nginx.conf:\d+\):\d+: --> 90, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?access_by_lua\(nginx.conf:\d+\):\d+: --> 90, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" log level:5 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[warn\] (\d+).*?access_by_lua\(nginx.conf:\d+\):\d+: --> 91, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: --> 102, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: --> 103, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: --> 104, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" \z --- skip_nginx: 2: <1.11.2 === TEST 20: fetch a few and generate a few, then fetch again (not overflown again) --- http_config lua_capture_error_log 5k; --- config location /t { access_by_lua_block { local errlog = require "ngx.errlog" local status, err = errlog.set_filter_level(ngx.WARN) if not status then error(err) end for i = 1, 100 do ngx.log(ngx.INFO, "--> ", i) ngx.log(ngx.WARN, "--> ", i) ngx.log(ngx.ERR, "--> ", i) end } content_by_lua_block { local errlog = require "ngx.errlog" local res = errlog.get_logs(3) ngx.say("msg count: ", #res / 3) -- first 3 logs for i = 1, #res, 3 do ngx.say("log level:", res[i]) ngx.say("log body:", res[i + 2]) end ngx.log(ngx.ERR, "howdy, something new!") ngx.log(ngx.ERR, "howdy, something even newer!") local res = errlog.get_logs(3) ngx.say("msg count: ", #res / 3) -- first 3 logs for i = 1, #res, 3 do ngx.say("log level:", res[i]) ngx.say("log body:", res[i + 2]) end local res = errlog.get_logs(1000) -- last 3 logs for i = #res - 8, #res, 3 do ngx.say("log level:", res[i]) ngx.say("log body:", res[i + 2]) end } } --- log_level: info --- request GET /t --- response_body_like chomp \Amsg count: 3 log level:5 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[warn\] (\d+).*?access_by_lua\(nginx.conf:\d+\):\d+: --> 88, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?access_by_lua\(nginx.conf:\d+\):\d+: --> 88, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" log level:5 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[warn\] (\d+).*?access_by_lua\(nginx.conf:\d+\):\d+: --> 89, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" msg count: 3 log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?access_by_lua\(nginx.conf:\d+\):\d+: --> 89, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" log level:5 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[warn\] (\d+).*?access_by_lua\(nginx.conf:\d+\):\d+: --> 90, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?access_by_lua\(nginx.conf:\d+\):\d+: --> 90, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?access_by_lua\(nginx.conf:\d+\):\d+: --> 100, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: howdy, something new!, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: howdy, something even newer!, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" \z --- skip_nginx: 2: <1.11.2 === TEST 21: multi-line error log --- http_config lua_capture_error_log 4k; --- config location /t { access_by_lua_block { local errlog = require "ngx.errlog" local status, err = errlog.set_filter_level(ngx.WARN) if not status then error(err) end ngx.log(ngx.ERR, "-->\n", "new line") } content_by_lua_block { local errlog = require "ngx.errlog" local res = errlog.get_logs() ngx.say("log lines: #", #res / 3) for i = 1, #res, 3 do ngx.say("log level:", res[i]) ngx.say("log body:", res[i + 2]) end } } --- log_level: info --- request GET /t --- response_body_like chomp \Alog lines: #1 log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*access_by_lua\(nginx.conf:\d+\):\d+: --> new line, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" \z --- skip_nginx: 2: <1.11.2 === TEST 22: user-supplied Lua table to hold the result (get one log + no log) --- http_config lua_capture_error_log 4k; --- config location /t { access_by_lua_block { local errlog = require "ngx.errlog" local status, err = errlog.set_filter_level(ngx.WARN) if not status then error(err) end ngx.log(ngx.ERR, "-->\n", "new line") } content_by_lua_block { local errlog = require "ngx.errlog" local t = {} for i = 1, 2 do local res = errlog.get_logs(10, t) ngx.say("maybe log lines: #", #res / 3) for j = 1, #res, 3 do local level, msg = res[j], res[j + 2] if not level then break end ngx.say("log level:", level) ngx.say("log body:", msg) end ngx.say("end") end } } --- log_level: info --- request GET /t --- response_body_like chomp \Amaybe log lines: #1 log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*access_by_lua\(nginx.conf:\d+\):\d+: --> new line, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" end maybe log lines: #1 end \z --- skip_nginx: 2: <1.11.2 === TEST 23: the system default filter level is "debug" --- config location /t { content_by_lua_block { local errlog = require "ngx.errlog" ngx.print('Is "debug" the system default filter level? ', errlog.get_sys_filter_level() == ngx.DEBUG) } } --- log_level: debug --- request GET /t --- response_body chomp Is "debug" the system default filter level? true === TEST 24: the system default filter level is "emerg" --- config location /t { content_by_lua_block { local errlog = require "ngx.errlog" ngx.print('Is "emerg" the system default filter level? ', errlog.get_sys_filter_level() == ngx.EMERG) } } --- log_level: emerg --- request GET /t --- response_body chomp Is "emerg" the system default filter level? true === TEST 25: get system default filter level during Nginx starts (init) --- init_by_lua_block local errlog = require "ngx.errlog" package.loaded.log_level = errlog.get_sys_filter_level() --- config location /t { content_by_lua_block { local log_level = package.loaded.log_level if log_level >= ngx.WARN then ngx.log(ngx.WARN, "log a warning event") else ngx.log(ngx.WARN, "do not log another warning event") end } } --- log_level: warn --- request GET /t --- error_log log a warning event --- no_error_log do not log another warning event === TEST 26: get system default filter level during Nginx worker starts (init worker) --- http_config init_worker_by_lua_block { local errlog = require "ngx.errlog" package.loaded.log_level = errlog.get_sys_filter_level() } --- config location /t { content_by_lua_block { local log_level = package.loaded.log_level if log_level >= ngx.WARN then ngx.log(ngx.WARN, "log a warning event") else ngx.log(ngx.WARN, "do not log another warning event") end } } --- log_level: warn --- request GET /t --- error_log log a warning event --- no_error_log do not log another warning event === TEST 27: sanity (with log time) --- http_config lua_capture_error_log 4m; --- config location /t { access_by_lua_block { ngx.log(ngx.ERR, "enter 1") ngx.log(ngx.ERR, "enter 11") local errlog = require "ngx.errlog" local res, err = errlog.get_logs(nil, nil, {fetch_time = true}) if not res then error("FAILED " .. err) end ngx.say("log lines:", #res / 3) } } --- request GET /t --- response_body log lines:2 --- grep_error_log eval qr/enter \d+/ --- grep_error_log_out eval [ "enter 1 enter 11 ", "enter 1 enter 11 " ] --- skip_nginx: 3: <1.11.2 === TEST 28: log time eq ngx.now --- http_config lua_capture_error_log 4m; --- config location /t { access_by_lua_block { local now = ngx.now() ngx.log(ngx.CRIT, "enter 1") ngx.log(ngx.ERR, "enter 11") local errlog = require "ngx.errlog" local res, err = errlog.get_logs(nil, nil, {fetch_time = true}) if not res then error("FAILED " .. err) end ngx.say("log lines: ", #res / 3) for i = 1, #res, 3 do ngx.say("log level: ", res[i]) ngx.say("log time: ", res[i + 1]) ngx.say("log body: ", res[i + 2]) ngx.say("same with now: ", res[i + 1] == now) end } } --- request GET /t --- response_body_like chomp \Alog lines: 2 log level: 3 log time: \d+(?:\.\d+)? log body: \d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[crit\] (\d+).*?access_by_lua\(nginx.conf:\d+\):\d+: enter 1, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" same with now: true log level: 4 log time: \d{10}(?:\.\d+)? log body: \d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?access_by_lua\(nginx.conf:\d+\):\d+: enter 11, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" same with now: true --- grep_error_log eval qr/enter \d+/ --- grep_error_log_out eval [ "enter 1 enter 11 ", "enter 1 enter 11 " ] --- skip_nginx: 3: <1.11.2 === TEST 29: ringbuf overflow bug --- http_config lua_capture_error_log 4k; --- config location /t { access_by_lua_block { local errlog = require "ngx.errlog" local msg = string.rep("*", 10) for i = 1, 2 do ngx.log(ngx.ERR, msg .. i) end } content_by_lua_block { local errlog = require "ngx.errlog" local msg = string.rep("*", 10) for i = 1, 40 do local res = errlog.get_logs(1) if res and #res then ngx.log(ngx.ERR, msg .. i) end end local res = errlog.get_logs() for i = 1, #res, 3 do ngx.say("log level: ", res[i]) ngx.say("log time: ", res[i + 1]) ngx.say("log body: ", res[i + 2]) end } } --- log_level: info --- request GET /t --- response_body_like chomp log level: 4 log time: \d+(?:\.\d+)? log body: \d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: \*\*\*\*\*\*\*\*\*\*39, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" log level: 4 log time: \d{10}(?:\.\d+)? log body: \d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: \*\*\*\*\*\*\*\*\*\*40, client: 127.0.0.1, server: localhost, request: "GET /t HTTP/1.1", host: "localhost" --- skip_nginx: 2: <1.11.2 === TEST 30: ringbuf sentinel bug1 --- http_config lua_capture_error_log 4k; --- config location /t { access_by_lua_block { local errlog = require "ngx.errlog" local msg = string.rep("a", 20) local bigmsg = string.rep("A", 3000) for i = 1, 10 do ngx.log(ngx.ERR, msg) end ngx.log(ngx.ERR, bigmsg) ngx.log(ngx.ERR, msg) } content_by_lua_block { local errlog = require "ngx.errlog" local res = errlog.get_logs(2) ngx.say("log lines: #", #res / 3) for i = 1, #res, 3 do ngx.say(string.gsub(res[i + 2], "^.*([Aa][Aa][Aa]).*$", "%1"), "") end } } --- log_level: info --- request GET /t --- response_body log lines: #2 AAA aaa --- skip_nginx: 2: <1.11.2 === TEST 31: ringbuf sentinel bug2 --- http_config lua_capture_error_log 4k; --- config location /t { access_by_lua_block { local errlog = require "ngx.errlog" local msg = string.rep("a", 20) for i = 1, 20 do ngx.log(ngx.ERR, msg) end } content_by_lua_block { local errlog = require "ngx.errlog" local msg = string.rep("a", 20) local res = errlog.get_logs(18) ngx.say("log lines: #", #res / 3) ngx.flush(true) for i = 1, 18 do ngx.log(ngx.ERR, msg) end local bigmsg = string.rep("A", 2000) ngx.log(ngx.ERR, bigmsg) local res = errlog.get_logs() ngx.say("log lines: #", #res / 3) ngx.flush(true) } } --- log_level: info --- request GET /t --- response_body log lines: #18 log lines: #8 --- skip_nginx: 2: <1.11.2 lua-resty-core-0.1.31/t/exit.t000066400000000000000000000061211474236722600160650ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(1014); #master_process_enabled(1); log_level('warn'); repeat_each(120); #repeat_each(2); plan tests => repeat_each() * (blocks() * 5); add_block_preprocessor(sub { my $block = shift; my $http_config = $block->http_config || ''; my $init_by_lua_block = $block->init_by_lua_block || ''; $http_config .= <<_EOC_; lua_package_path '\$prefix/html/?.lua;$t::TestCore::lua_package_path'; init_by_lua_block { $t::TestCore::init_by_lua_block $init_by_lua_block } _EOC_ $block->set_value("http_config", $http_config); }); #no_diff(); #no_long_string(); run_tests(); __DATA__ === TEST 1: sanity --- config location = /t { content_by_lua_block { ngx.exit(403) } } --- request GET /t --- response_body_like: 403 Forbidden --- error_code: 403 --- no_error_log eval ["[error]", qr/ -- NYI: (?!FastFunc coroutine.yield)/, " bad argument"] === TEST 2: call ngx.exit() from a custom lua module --- config location = /t { content_by_lua_block { local foo = require "foo" foo.go() } } --- user_files >>> foo.lua local exit = ngx.exit local function go() exit(403) return end return { go = go } --- request GET /t --- response_body_like: 403 Forbidden --- error_code: 403 --- no_error_log eval ["[error]", qr/ -- NYI: (?!FastFunc coroutine.yield)/, " bad argument"] === TEST 3: accepts NGX_OK --- config location = /t { content_by_lua_block { ngx.exit(ngx.OK) } } --- request GET /t --- response_body --- no_error_log eval ["[error]", qr/ -- NYI: (?!FastFunc coroutine.yield)/, " bad argument"] === TEST 4: accepts NGX_ERROR --- config location = /t { content_by_lua_block { ngx.exit(ngx.ERROR) } } --- request GET /t --- error_code: --- response_body --- no_error_log eval ["[error]", qr/ -- NYI: (?!FastFunc coroutine.yield)/, " bad argument"] === TEST 5: accepts NGX_DECLINED --- config location = /t { content_by_lua_block { ngx.exit(ngx.DECLINED) } } --- request GET /t --- error_code: --- response_body --- no_error_log eval ["[error]", qr/ -- NYI: (?!FastFunc coroutine.yield)/, " bad argument"] === TEST 6: refuses NGX_AGAIN --- config location = /t { content_by_lua_block { ngx.exit(ngx.AGAIN) } } --- request GET /t --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log eval qr/\[error\] .*? bad argument to 'ngx.exit': does not accept NGX_AGAIN or NGX_DONE/ --- no_error_log eval qr/ -- NYI: (?!FastFunc coroutine.yield)/ [crit] === TEST 7: refuses NGX_DONE --- config location = /t { content_by_lua_block { ngx.exit(ngx.DONE) } } --- request GET /t --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log eval qr/\[error\] .*? bad argument to 'ngx.exit': does not accept NGX_AGAIN or NGX_DONE/ --- no_error_log eval qr/ -- NYI: (?!FastFunc coroutine.yield)/ [crit] lua-resty-core-0.1.31/t/lib/000077500000000000000000000000001474236722600154755ustar00rootroot00000000000000lua-resty-core-0.1.31/t/lib/helper.lua000066400000000000000000000026371474236722600174670ustar00rootroot00000000000000local _M = {} local run_lua_with_graceful_shutdown do local function set_up_ngx_conf(dir, code) local conf = [[ error_log stderr error; master_process off; daemon off; events { worker_connections 64; } http { init_worker_by_lua_block { ngx.timer.at(0, function () ]] .. code .. [[ require("ngx.process").signal_graceful_exit() end) } } ]] assert(os.execute("mkdir -p " .. dir .. "/logs")) local conf_file = dir .. "/nginx.conf" local f, err = io.open(conf_file, "w") if not f then ngx.log(ngx.ERR, err) return end assert(f:write(conf)) f:close() return conf_file end local function get_ngx_bin_path() local ffi = require "ffi" ffi.cdef[[char **ngx_argv;]] return ffi.string(ffi.C.ngx_argv[0]) end function run_lua_with_graceful_shutdown(dir, code) local ngx_pipe = require "ngx.pipe" local conf_file = set_up_ngx_conf(dir, code) local nginx = get_ngx_bin_path() local cmd = nginx .. " -p " .. dir .. " -c " .. conf_file return ngx_pipe.spawn(cmd) end end _M.run_lua_with_graceful_shutdown = run_lua_with_graceful_shutdown return _M lua-resty-core-0.1.31/t/master-pid-single-process.t000066400000000000000000000023021474236722600221110ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(1014); #master_process_enabled(1); #log_level('warn'); #master_on(); repeat_each(2); plan tests => repeat_each() * (blocks() * 6); #no_diff(); #no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: sanity --- config location = /t { content_by_lua_block { local process = require "ngx.process" local v local get_pid = process.get_master_pid for i = 1, 400 do v = get_pid() end local f = assert(io.open(ngx.config.prefix() .. "/logs/nginx.pid", "r")) local str = assert(f:read("*l")) local expected = str if tostring(v) == expected then ngx.say("ok") else ngx.say("expected: ", expected) end f:close() ngx.say("got: ", v, " (", type(v), ")") } } --- request GET /t --- response_body_like chop \Aok got: \d+ \(number\) \z --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):\d loop\]/ --- no_error_log [error] -- NYI: stitch --- skip_nginx: 6: < 1.13.8 lua-resty-core-0.1.31/t/master-pid.t000066400000000000000000000023011474236722600171550ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(1014); #master_process_enabled(1); #log_level('warn'); master_on(); repeat_each(2); plan tests => repeat_each() * (blocks() * 6); #no_diff(); #no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: sanity --- config location = /t { content_by_lua_block { local process = require "ngx.process" local v local get_pid = process.get_master_pid for i = 1, 400 do v = get_pid() end local f = assert(io.open(ngx.config.prefix() .. "/logs/nginx.pid", "r")) local str = assert(f:read("*l")) local expected = str if tostring(v) == expected then ngx.say("ok") else ngx.say("expected: ", expected) end f:close() ngx.say("got: ", v, " (", type(v), ")") } } --- request GET /t --- response_body_like chop \Aok got: \d+ \(number\) \z --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):\d loop\]/ --- no_error_log [error] -- NYI: stitch --- skip_nginx: 6: < 1.13.8 lua-resty-core-0.1.31/t/md5-bin.t000066400000000000000000000036071474236722600163550ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(1014); #master_process_enabled(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 4); #no_diff(); #no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: set md5_bin (string) --- config location = /md5_bin { content_by_lua_block { local s for i = 1, 100 do s = ngx.md5_bin("hello") end ngx.say(string.len(s)) } } --- request GET /md5_bin --- response_body 16 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] === TEST 2: set md5_bin (nil) --- config location = /md5_bin { content_by_lua_block { local s for i = 1, 100 do s = ngx.md5_bin(nil) end ngx.say(string.len(s)) } } --- request GET /md5_bin --- response_body 16 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] === TEST 3: set md5_bin (number) --- config location = /md5_bin { content_by_lua_block { local s for i = 1, 100 do s = ngx.md5_bin(3.14) end ngx.say(string.len(s)) } } --- request GET /md5_bin --- response_body 16 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] === TEST 4: set md5_bin (boolean) --- config location = /md5_bin { content_by_lua_block { local s for i = 1, 100 do s = ngx.md5_bin(true) end ngx.say(string.len(s)) } } --- request GET /md5_bin --- response_body 16 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] lua-resty-core-0.1.31/t/md5.t000066400000000000000000000036151474236722600156060ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(1014); #master_process_enabled(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 4); #no_diff(); #no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: set md5 hello --- config location = /md5 { content_by_lua_block { local s for i = 1, 100 do s = ngx.md5("hello") end ngx.say(s) } } --- request GET /md5 --- response_body 5d41402abc4b2a76b9719d911017c592 --- error_log eval qr/\[TRACE\s+1 content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] === TEST 2: nil string to ngx.md5 --- config location = /md5 { content_by_lua_block { local s for i = 1, 100 do s = ngx.md5(nil) end ngx.say(s) } } --- request GET /md5 --- response_body d41d8cd98f00b204e9800998ecf8427e --- error_log eval qr/\[TRACE\s+1 content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] === TEST 3: empty string to ngx.md5 --- config location /md5 { content_by_lua_block { local s for i = 1, 100 do s = ngx.md5("") end ngx.say(s) } } --- request GET /md5 --- response_body d41d8cd98f00b204e9800998ecf8427e --- error_log eval qr/\[TRACE\s+1 content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] === TEST 4: number to ngx.md5 --- config location /md5 { content_by_lua_block { local s for i = 1, 100 do s = ngx.md5(3.14) end ngx.say(s) } } --- request GET /md5 --- response_body 4beed3b9c4a886067de0e3a094246f78 --- error_log eval qr/\[TRACE\s+1 content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] lua-resty-core-0.1.31/t/misc.t000066400000000000000000000100011474236722600160370ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(1014); #master_process_enabled(1); log_level('warn'); #repeat_each(120); repeat_each(2); plan tests => repeat_each() * (blocks() * 6); #no_diff(); #no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: ngx.is_subrequest --- config location = /t { return 201; header_filter_by_lua_block { local rc for i = 1, 100 do rc = ngx.is_subrequest end ngx.log(ngx.WARN, "is subrequest: ", rc) } } --- request GET /t --- response_body --- error_code: 201 --- no_error_log [error] bad argument --- error_log eval ["is subrequest: false,", qr/\[TRACE\s+\d+\s+header_filter_by_lua\(nginx.conf:58\):3 loop\]/ ] === TEST 2: ngx.headers_sent (false) --- config location = /t { content_by_lua_block { local rc for i = 1, 100 do rc = ngx.headers_sent end ngx.say("headers sent: ", rc) } } --- request GET /t --- response_body headers sent: false --- no_error_log [error] -- NYI: bad argument --- error_log eval qr/\[TRACE\s+\d+\s+content_by_lua\(nginx\.conf:\d+\):3 loop\]/ === TEST 3: ngx.headers_sent (true) --- config location = /t { content_by_lua_block { ngx.send_headers() local rc for i = 1, 100 do rc = ngx.headers_sent end ngx.say("headers sent: ", rc) } } --- request GET /t --- response_body headers sent: true --- no_error_log [error] -- NYI: bad argument --- error_log eval qr/\[TRACE\s+\d+\s+content_by_lua\(nginx\.conf:\d+\):4 loop\]/ === TEST 4: base.check_subsystem --- config location = /t { content_by_lua_block { local base = require "resty.core.base" base.allows_subsystem('http', 'stream') base.allows_subsystem('http') ngx.say("ok") } } --- request GET /t --- response_body ok --- no_error_log [error] [crit] -- NYI: bad argument === TEST 5: base.check_subsystem with non-http subsystem --- config location = /t { content_by_lua_block { local base = require "resty.core.base" base.allows_subsystem('stream') ngx.say("ok") } } --- request GET /t --- error_code: 500 --- no_error_log [alert] [crit] -- NYI: bad argument --- error_log unsupported subsystem: http === TEST 6: not internal request --- http_config eval: $::HttpConfig --- config location /test { rewrite ^/test$ /lua last; } location /lua { content_by_lua_block { if ngx.req.is_internal() then ngx.say("internal") else ngx.say("not internal") end } } --- request GET /lua --- response_body not internal --- no_error_log [error] [alert] [crit] -- NYI: === TEST 7: internal request --- http_config eval: $::HttpConfig --- config location /test { rewrite ^/test$ /lua last; } location /lua { content_by_lua_block { if ngx.req.is_internal() then ngx.say("internal") else ngx.say("not internal") end } } --- request GET /test --- response_body internal --- no_error_log [error] [alert] [crit] -- NYI: === TEST 8: bad context --- http_config eval: $::HttpConfig --- config location /lua { content_by_lua_block { local function test() local ok, err = pcall(ngx.req.is_internal) package.loaded.bad_context = {ok, err} end ngx.timer.at(0, test) ngx.sleep(0.02) local ctx = package.loaded.bad_context ngx.say(ctx[1]) local i = string.find(ctx[2], "API disabled in the current context") ngx.say(i > 1) } } --- request GET /lua --- response_body false true --- no_error_log [error] [alert] [crit] -- NYI: lua-resty-core-0.1.31/t/ndk.t000066400000000000000000000123601474236722600156720ustar00rootroot00000000000000use lib '.'; use t::TestCore; repeat_each(2); plan tests => repeat_each() * (blocks() * 5 + 4); add_block_preprocessor(sub { my $block = shift; my $http_config = $block->http_config || ''; $http_config .= <<_EOC_; $t::TestCore::HttpConfig _EOC_ $block->set_value("http_config", $http_config); if (!defined $block->error_log) { my $no_error_log = <<_EOC_; [error] [alert] [emerg] -- NYI: stitch _EOC_ $block->set_value("no_error_log", $no_error_log); } if (!defined $block->request) { $block->set_value("request", "GET /t"); } }); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: sanity --- config location /t { content_by_lua_block { local s = ndk.set_var.set_escape_uri(" :") local r = ndk.set_var.set_unescape_uri("a%20b") ngx.say(s) ngx.say(r) local set_escape_uri = ndk.set_var.set_escape_uri local set_unescape_uri = ndk.set_var.set_unescape_uri ngx.say(set_escape_uri(" :")) ngx.say(set_unescape_uri("a%20b")) local res for i = 1, $TEST_NGINX_HOTLOOP * 10 do res = set_escape_uri(" :") end for i = 1, $TEST_NGINX_HOTLOOP * 10 do res = set_unescape_uri("a%20b") end } } --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):13 loop\]/, qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):17 loop\]/ --- no_error_log [error] [alert] [emerg] -- NYI: stitch --- response_body %20%3A a b %20%3A a b === TEST 2: directive not found --- config location /t { content_by_lua_block { local s = ndk.set_var.set_escape_uri_blah_blah(" :") ngx.say(s) } } --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log ndk.set_var: directive "set_escape_uri_blah_blah" not found or does not use ndk_set_var_value === TEST 3: ndk.set_var initialize ngx_http_variable_value_t variable properly --- config location /t { content_by_lua_block { local version = '2011.10.13+0000' local e_version = ndk.set_var.set_encode_base32(version) local s_version= ndk.set_var.set_quote_sql_str(version) ngx.say(e_version) ngx.say(s_version) } } --- response_body 68o32c9e64o2sc9j5co30c1g '2011.10.13+0000' === TEST 4: set directive not allowed --- config location /t { content_by_lua_block { ndk.set_var.set_escape_uri = "hack it" } } --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log not allowed === TEST 5: call directive failed --- config location /t { content_by_lua_block { ndk.set_var.set_decode_hex('a') } } --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log calling directive set_decode_hex failed with code -1 === TEST 6: convert directive type to string --- config location /t { content_by_lua_block { ndk.set_var[1]() } } --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log ndk.set_var: directive "1" not found or does not use ndk_set_var_value === TEST 7: convert directive argument to string --- config location /t { content_by_lua_block { local s = ndk.set_var.set_escape_uri(1) ngx.say(s) } } --- response_body 1 === TEST 8: call in set_by_lua --- config location /t { set_by_lua_block $s { return ndk.set_var.set_escape_uri(" :") } echo $s; } --- response_body %20%3A === TEST 9: call in timer --- config location /t { content_by_lua_block { ngx.timer.at(0, function() local s = ndk.set_var.set_escape_uri(" :") ngx.log(ngx.WARN, "s = ", s) end) ngx.sleep(0.01) } } --- error_log s = %20%3A --- no_error_log [error] === TEST 10: call in header_filter_by_lua --- config location /t { content_by_lua_block { ngx.send_headers() ngx.say(package.loaded.s) } header_filter_by_lua_block { package.loaded.s = ndk.set_var.set_escape_uri(" :") } } --- response_body %20%3A === TEST 11: call in log_by_lua --- config location /t { echo ok; log_by_lua_block { local s = ndk.set_var.set_escape_uri(" :") ngx.log(ngx.WARN, "s = ", s) } } --- response_body ok --- error_log s = %20%3A --- no_error_log [error] === TEST 12: call in init_worker_by_lua --- http_config init_worker_by_lua_block { package.loaded.s = ndk.set_var.set_escape_uri(" :") } --- config location /t { content_by_lua_block { ngx.say(package.loaded.s) } } --- response_body %20%3A === TEST 13: cache the function in init_worker_by_lua and call in other phases --- http_config init_worker_by_lua_block { package.loaded.set_escape_uri = ndk.set_var.set_escape_uri } --- config location /t { content_by_lua_block { ngx.say(package.loaded.set_escape_uri(" :")) } } --- response_body %20%3A lua-resty-core-0.1.31/t/ngx-req.t000066400000000000000000000163071474236722600165040ustar00rootroot00000000000000use lib '.'; use t::TestCore; repeat_each(2); plan tests => repeat_each() * (blocks() * 3); add_block_preprocessor(sub { my $block = shift; if (!defined $block->error_log) { $block->set_value("no_error_log", "[error]"); } if (!defined $block->request) { $block->set_value("request", "GET /t"); } }); no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: ngx_req.add_header (jitted) --- config location = /t { content_by_lua_block { local ngx_req = require "ngx.req" for i = 1, $TEST_NGINX_HOTLOOP * 20 do ngx_req.add_header("Foo", "bar") end } } --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] === TEST 2: ngx_req.add_header (single value) --- config location = /t { content_by_lua_block { local ngx_req = require "ngx.req" ngx.req.set_header("Foo", "bar") ngx_req.add_header("Foo", "baz") ngx_req.add_header("Foo", 2) ngx.say("Foo: ", table.concat(ngx.req.get_headers()["Foo"], ", ")) } } --- response_body Foo: bar, baz, 2 === TEST 3: ngx_req.add_header (empty single value) --- config location = /t { content_by_lua_block { local ngx_req = require "ngx.req" ngx.req.set_header("Foo", "bar") ngx_req.add_header("Foo", "") ngx.say("Foo: [", table.concat(ngx.req.get_headers()["Foo"], ", "), ']') } } --- response_body Foo: [bar, ] === TEST 4: ngx_req.add_header (non-string single value) --- config location = /t { content_by_lua_block { local ngx_req = require "ngx.req" ngx.req.set_header("Foo", "bar") ngx_req.add_header("Foo", 123) ngx.say("Foo: [", table.concat(ngx.req.get_headers()["Foo"], ", "), ']') } } --- response_body Foo: [bar, 123] === TEST 5: ngx_req.add_header (non-string header name) --- config location = /t { content_by_lua_block { local ngx_req = require "ngx.req" ngx_req.add_header(123, 456) ngx_req.add_header(123, 789) ngx.say("123: [", table.concat(ngx.req.get_headers()[123], ", "), ']') } } --- response_body 123: [456, 789] === TEST 6: ngx_req.add_header (multiple values) --- config location = /t { content_by_lua_block { local ngx_req = require "ngx.req" ngx.req.set_header("Foo", "bar") ngx_req.add_header("Foo", { "baz", 123 }) ngx.say("Foo: ", table.concat(ngx.req.get_headers()["Foo"], ", ")) } } --- response_body Foo: bar, baz, 123 === TEST 7: ngx_req.add_header (override builtin header) --- config location = /t { content_by_lua_block { local ngx_req = require "ngx.req" ngx_req.add_header("User-Agent", "Mozilla/5.0 (Android; Mobile; rv:13.0) Gecko/13.0 Firefox/13.0") ngx.say("UA: ", ngx.var.http_user_agent) } } --- response_body UA: Mozilla/5.0 (Android; Mobile; rv:13.0) Gecko/13.0 Firefox/13.0 === TEST 8: ngx_req.add_header (added header is inherited by subrequests) --- config location = /sub { content_by_lua_block { ngx.say("Foo: ", table.concat(ngx.req.get_headers()["Foo"], ", ")) } } location = /t { content_by_lua_block { local ngx_req = require "ngx.req" ngx.req.set_header("Foo", "bar") ngx_req.add_header("Foo", {"baz", 2}) local res = ngx.location.capture("/sub") ngx.print(res.body) } } --- response_body Foo: bar, baz, 2 === TEST 9: ngx_req.add_header (invalid context) --- http_config init_worker_by_lua_block { local ngx_req = require "ngx.req" ngx_req.add_header("Foo", "baz") } --- config location /t { return 200; } --- response_body --- error_log API disabled in the current context === TEST 10: ngx_req.add_header (header names edge-cases) --- config location = /t { content_by_lua_block { local ngx_req = require "ngx.req" local function check_invalid_header_name(header_name) local ok, err = pcall(ngx_req.add_header, header_name, "bar") if not ok then ngx.say(err) else ngx.say("ok") end end check_invalid_header_name() check_invalid_header_name("") check_invalid_header_name({}) } } --- response_body bad 'name' argument: string expected, got nil ok ok === TEST 11: ngx_req.add_header (invalid header values) --- config location = /t { content_by_lua_block { local ngx_req = require "ngx.req" local function check_invalid_header_value(...) local ok, err = pcall(ngx_req.add_header, "Foo", ...) if not ok then ngx.say(err) else ngx.say("ok") end end check_invalid_header_value() check_invalid_header_value(nil) check_invalid_header_value({}) } } --- response_body bad 'value' argument: string or table expected, got nil bad 'value' argument: string or table expected, got nil bad 'value' argument: non-empty table expected === TEST 12: ngx_req.add_header (header name with control characters) --- config location /bar { access_by_lua_block { local ngx_req = require "ngx.req" ngx_req.add_header("header\r\nabc", "value") } proxy_pass http://127.0.0.1:$server_port/foo; } location = /foo { echo $echo_client_request_headers; } --- request GET /bar --- response_body_like chomp \bheader%0D%0Aabc: value\r\n === TEST 13: ngx_req.add_header (header value with control characters) --- config location /bar { access_by_lua_block { local ngx_req = require "ngx.req" ngx_req.add_header("header", "value\r\nabc") } proxy_pass http://127.0.0.1:$server_port/foo; } location = /foo { echo $echo_client_request_headers; } --- request GET /bar --- response_body_like chomp \bheader: value%0D%0Aabc\r\n === TEST 14: ngx_req.add_header (header name with Chinese characters) --- config location /bar { access_by_lua_block { local ngx_req = require "ngx.req" ngx_req.add_header("header中文", "value") } proxy_pass http://127.0.0.1:$server_port/foo; } location = /foo { echo $echo_client_request_headers; } --- request GET /bar --- response_body_like chomp \bheader%E4%B8%AD%E6%96%87: value === TEST 15: ngx_req.add_header (header value with Chinese characters) --- config location /bar { access_by_lua_block { local ngx_req = require "ngx.req" ngx_req.add_header("header", "value中文") } proxy_pass http://127.0.0.1:$server_port/foo; } location = /foo { echo $echo_client_request_headers; } --- request GET /bar --- response_body_like chomp \bheader: value中文 lua-resty-core-0.1.31/t/ngx-resp.t000066400000000000000000000101211474236722600166520ustar00rootroot00000000000000use lib '.'; use t::TestCore; repeat_each(2); plan tests => repeat_each() * (blocks() * 3 + 4); add_block_preprocessor(sub { my $block = shift; if (!defined $block->error_log) { $block->set_value("no_error_log", "[error]"); } if (!defined $block->request) { $block->set_value("request", "GET /t"); } }); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: ngx.resp.add_header (single value) --- config location = /t { set $foo hello; content_by_lua_block { local ngx_resp = require "ngx.resp" ngx_resp.add_header("Foo", "bar") ngx_resp.add_header("Foo", 2) ngx.say("Foo: ", table.concat(ngx.header["Foo"], ", ")) } } --- response_body Foo: bar, 2 === TEST 2: ngx.resp.add_header (nil) --- config location = /t { content_by_lua_block { local ngx_resp = require "ngx.resp" local ok, err = pcall(ngx_resp.add_header, "Foo") if not ok then ngx.say(err) else ngx.say('ok') end } } --- response_body invalid header value === TEST 3: ngx.resp.add_header (multi-value) --- config location = /t { set $foo hello; content_by_lua_block { local ngx_resp = require "ngx.resp" ngx_resp.add_header('Foo', {'bar', 'baz'}) local v = ngx.header["Foo"] ngx.say("Foo: ", table.concat(ngx.header["Foo"], ", ")) } } --- response_body Foo: bar, baz === TEST 4: ngx.resp.add_header (append header) --- config location = /t { set $foo hello; content_by_lua_block { local ngx_resp = require "ngx.resp" ngx.header["fruit"] = "apple" ngx_resp.add_header("fruit", "banana") ngx_resp.add_header("fruit", "cherry") ngx.say("fruit: ", table.concat(ngx.header["fruit"], ", ")) } } --- response_body fruit: apple, banana, cherry === TEST 5: ngx.resp.add_header (override builtin header) --- config location = /t { set $foo hello; content_by_lua_block { local ngx_resp = require "ngx.resp" ngx_resp.add_header("Date", "now") ngx.say("Date: ", ngx.header["Date"]) } } --- response_body Date: now === TEST 6: ngx.resp.add_header (empty table) --- config location = /t { content_by_lua_block { local ngx_resp = require "ngx.resp" ngx.header["Foo"] = "aaa" local ok, err = pcall(ngx_resp.add_header, "Foo", {}) if not ok then ngx.say(err) else ngx.say("Foo: ", ngx.header["Foo"]) end } } --- response_body Foo: aaa === TEST 7: ngx.resp.add_header (header name with control characters) --- config location = /t { content_by_lua_block { local ngx_resp = require "ngx.resp" ngx_resp.add_header("head\r\n", "value") ngx.say("OK") } } --- response_body OK --- response_headers head%0D%0A: value === TEST 8: ngx.resp.add_header (header value with control characters) --- config location = /t { content_by_lua_block { local ngx_resp = require "ngx.resp" ngx_resp.add_header("head", "value\r\n") ngx.say("OK") } } --- response_body OK --- response_headers head: value%0D%0A === TEST 9: ngx.resp.add_header (header name with Chinese characters) --- config location = /t { content_by_lua_block { local ngx_resp = require "ngx.resp" ngx_resp.add_header("head中文", "value") ngx.say("OK") } } --- response_body OK --- response_headers head%E4%B8%AD%E6%96%87: value === TEST 10: ngx.resp.add_header (header value with Chinese characters) --- config location = /t { content_by_lua_block { local ngx_resp = require "ngx.resp" ngx_resp.add_header("head", "value中文") ngx.say("OK") } } --- response_body OK --- response_headers head: value中文 lua-resty-core-0.1.31/t/ocsp.t000066400000000000000000001377041474236722600160740ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(10140); #workers(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 6 + 13); no_long_string(); #no_diff(); $ENV{TEST_NGINX_LUA_PACKAGE_PATH} = "$t::TestCore::lua_package_path"; $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); run_tests(); __DATA__ === TEST 1: get OCSP responder (good case) --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ocsp = require "ngx.ocsp" local f = assert(io.open("t/cert/ocsp/chain.pem")) local cert_data = f:read("*a") f:close() local err cert_data, err = ssl.cert_pem_to_der(cert_data) if not cert_data then ngx.log(ngx.ERR, "failed to convert pem cert to der cert: ", err) return end -- specify the max length explicitly here, since string buf size may be too short local url, err = ocsp.get_ocsp_responder_from_der_chain(cert_data, 128) if not url then ngx.log(ngx.ERR, "failed to get OCSP responder: ", err) return end ngx.log(ngx.WARN, "OCSP url found: ", url) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_verify_depth 3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local err local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) end -- do } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata --- error_log lua ssl server name: "test.com" OCSP url found: http://127.0.0.1:8888/ocsp?foo=1, --- no_error_log [error] [alert] [emerg] === TEST 2: get OCSP responder (not found) --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ocsp = require "ngx.ocsp" local f = assert(io.open("t/cert/chain/chain.pem")) local cert_data = f:read("*a") f:close() local err cert_data, err = ssl.cert_pem_to_der(cert_data) if not cert_data then ngx.log(ngx.ERR, "failed to convert pem cert to der cert: ", err) return end local url, err = ocsp.get_ocsp_responder_from_der_chain(cert_data) if not url then if err then ngx.log(ngx.ERR, "failed to get OCSP responder: ", err) else ngx.log(ngx.WARN, "OCSP responder not found") end return end ngx.log(ngx.WARN, "OCSP url found: ", url) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_verify_depth 3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) end -- do } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata --- error_log lua ssl server name: "test.com" OCSP responder not found --- no_error_log [error] [alert] [emerg] === TEST 3: get OCSP responder (no issuer cert at all) --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ocsp = require "ngx.ocsp" local f = assert(io.open("t/cert/ocsp/test-com.crt")) local cert_data = f:read("*a") f:close() local err cert_data, err = ssl.cert_pem_to_der(cert_data) if not cert_data then ngx.log(ngx.ERR, "failed to convert pem cert to der cert: ", err) return end local url, err = ocsp.get_ocsp_responder_from_der_chain(cert_data) if not url then if err then ngx.log(ngx.ERR, "failed to get OCSP responder: ", err) else ngx.log(ngx.WARN, "OCSP responder not found") end return end ngx.log(ngx.WARN, "OCSP url found: ", url) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_verify_depth 3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) end -- do } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata --- error_log lua ssl server name: "test.com" failed to get OCSP responder: no issuer certificate in chain --- no_error_log [alert] [emerg] === TEST 4: get OCSP responder (issuer cert not next to the leaf cert) --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ocsp = require "ngx.ocsp" local f = assert(io.open("t/cert/ocsp/wrong-issuer-order-chain.pem")) local cert_data = f:read("*a") f:close() local err cert_data, err = ssl.cert_pem_to_der(cert_data) if not cert_data then ngx.log(ngx.ERR, "failed to convert pem cert to der cert: ", err) return end local url, err = ocsp.get_ocsp_responder_from_der_chain(cert_data) if not url then if err then ngx.log(ngx.ERR, "failed to get OCSP responder: ", err) else ngx.log(ngx.WARN, "OCSP responder not found") end return end ngx.log(ngx.WARN, "OCSP url found: ", url) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_verify_depth 3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) end -- do } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata --- error_log lua ssl server name: "test.com" failed to get OCSP responder: issuer certificate not next to leaf --- no_error_log [alert] [emerg] === TEST 5: get OCSP responder (truncated) --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ocsp = require "ngx.ocsp" local f = assert(io.open("t/cert/ocsp/chain.pem")) local cert_data = f:read("*a") f:close() local err cert_data, err = ssl.cert_pem_to_der(cert_data) if not cert_data then ngx.log(ngx.ERR, "failed to convert pem cert to der cert: ", err) return end local url, err = ocsp.get_ocsp_responder_from_der_chain(cert_data, 6) if not url then if err then ngx.log(ngx.ERR, "failed to get OCSP responder: ", err) else ngx.log(ngx.WARN, "OCSP responder not found") end return end if err then ngx.log(ngx.WARN, "still get an error: ", err) end ngx.log(ngx.WARN, "OCSP url found: ", url) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_verify_depth 3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) end -- do } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata --- error_log lua ssl server name: "test.com" OCSP url found: http:/, still get an error: truncated --- no_error_log [error] [alert] [emerg] === TEST 6: create OCSP request (good) --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ocsp = require "ngx.ocsp" local f = assert(io.open("t/cert/ocsp/chain.pem")) local cert_data = f:read("*a") f:close() local err cert_data, err = ssl.cert_pem_to_der(cert_data) if not cert_data then ngx.log(ngx.ERR, "failed to convert pem cert to der cert: ", err) return end -- specify the max length explicitly here, since string buf size may be too short local req, err = ocsp.create_ocsp_request(cert_data, 128) if not req then ngx.log(ngx.ERR, "failed to create OCSP request: ", err) return end ngx.log(ngx.WARN, "OCSP request created with length ", #req) local f = assert(io.open("t/cert/ocsp/ocsp-req.der", "r")) local expected = assert(f:read("*a")) f:close() if req ~= expected then ngx.log(ngx.ERR, "ocsp responder: got unexpected OCSP request") end } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_verify_depth 3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) end -- do } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata --- error_log lua ssl server name: "test.com" OCSP request created with length 68 --- no_error_log [error] [alert] [emerg] === TEST 7: create OCSP request (buffer too small) --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ocsp = require "ngx.ocsp" local f = assert(io.open("t/cert/ocsp/chain.pem")) local cert_data = f:read("*a") f:close() local err cert_data, err = ssl.cert_pem_to_der(cert_data) if not cert_data then ngx.log(ngx.ERR, "failed to convert pem cert to der cert: ", err) return end local req, err = ocsp.create_ocsp_request(cert_data, 67) if not req then ngx.log(ngx.ERR, "failed to create OCSP request: ", err) return end ngx.log(ngx.WARN, "OCSP request created with length ", #req) local bytes = {string.byte(req, 1, #req)} for i, byte in ipairs(bytes) do bytes[i] = string.format("%02x", byte) end ngx.log(ngx.WARN, "OCSP request content: ", table.concat(bytes, " ")) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_verify_depth 3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) end -- do } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata --- error_log lua ssl server name: "test.com" failed to create OCSP request: output buffer too small: 68 > 67 --- no_error_log [alert] [emerg] === TEST 8: create OCSP request (empty string cert chain) --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ocsp = require "ngx.ocsp" local cert_data = "" local req, err = ocsp.create_ocsp_request(cert_data, 67) if not req then ngx.log(ngx.ERR, "failed to create OCSP request: ", err) return ngx.exit(ngx.ERROR) end ngx.log(ngx.WARN, "OCSP request created with length ", #req) local bytes = {string.byte(req, 1, #req)} for i, byte in ipairs(bytes) do bytes[i] = string.format("%02x", byte) end ngx.log(ngx.WARN, "OCSP request content: ", table.concat(bytes, " ")) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_verify_depth 3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) end -- do } } --- request GET /t --- response_body connected: 1 failed to do SSL handshake: handshake failed --- error_log lua ssl server name: "test.com" failed to create OCSP request: d2i_X509_bio() failed --- no_error_log [alert] [emerg] === TEST 9: create OCSP request (no issuer cert in the chain) --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ocsp = require "ngx.ocsp" local f = assert(io.open("t/cert/ocsp/test-com.crt")) local cert_data = f:read("*a") f:close() local err cert_data, err = ssl.cert_pem_to_der(cert_data) if not cert_data then ngx.log(ngx.ERR, "failed to convert pem cert to der cert: ", err) return end local req, err = ocsp.create_ocsp_request(cert_data, 67) if not req then ngx.log(ngx.ERR, "failed to create OCSP request: ", err) return end ngx.log(ngx.WARN, "OCSP request created with length ", #req) local bytes = {string.byte(req, 1, #req)} for i, byte in ipairs(bytes) do bytes[i] = string.format("%02x", byte) end ngx.log(ngx.WARN, "OCSP request content: ", table.concat(bytes, " ")) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_verify_depth 3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) end -- do } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata --- error_log lua ssl server name: "test.com" failed to create OCSP request: no issuer certificate in chain --- no_error_log [alert] [emerg] === TEST 10: validate good OCSP response --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ocsp = require "ngx.ocsp" local f = assert(io.open("t/cert/ocsp/chain.pem")) local cert_data = f:read("*a") f:close() local err cert_data, err = ssl.cert_pem_to_der(cert_data) if not cert_data then ngx.log(ngx.ERR, "failed to convert pem cert to der cert: ", err) return end local f = assert(io.open("t/cert/ocsp/ocsp-resp.der")) local resp = f:read("*a") f:close() local ok, next_update_or_err = ocsp.validate_ocsp_response(resp, cert_data) if not ok then ngx.log(ngx.ERR, "failed to validate OCSP response: ", next_update_or_err) return end ngx.log(ngx.WARN, "OCSP response validation ok, next_update: ", next_update_or_err) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_verify_depth 3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) end -- do } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata --- error_log lua ssl server name: "test.com" OCSP response validation ok, next_update: nil --- no_error_log [error] [alert] [emerg] === TEST 11: fail to validate OCSP response - no issuer cert --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ocsp = require "ngx.ocsp" local f = assert(io.open("t/cert/ocsp/test-com.crt")) local cert_data = f:read("*a") f:close() local err cert_data, err = ssl.cert_pem_to_der(cert_data) if not cert_data then ngx.log(ngx.ERR, "failed to convert pem cert to der cert: ", err) return end local f = assert(io.open("t/cert/ocsp/ocsp-resp.der")) local resp = f:read("*a") f:close() -- specify the max length explicitly here, since string buf size may be too short local req, err = ocsp.validate_ocsp_response(resp, cert_data, 128) if not req then ngx.log(ngx.ERR, "failed to validate OCSP response: ", err) return end ngx.log(ngx.WARN, "OCSP response validation ok") } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_verify_depth 3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) end -- do } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata --- error_log lua ssl server name: "test.com" failed to validate OCSP response: no issuer certificate in chain --- no_error_log OCSP response validation ok [alert] [emerg] === TEST 12: validate good OCSP response - no certs in response --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ocsp = require "ngx.ocsp" local f = assert(io.open("t/cert/ocsp/chain.pem")) local cert_data = f:read("*a") f:close() local err cert_data, err = ssl.cert_pem_to_der(cert_data) if not cert_data then ngx.log(ngx.ERR, "failed to convert pem cert to der cert: ", err) return end local f = assert(io.open("t/cert/ocsp/ocsp-resp-no-certs.der")) local resp = f:read("*a") f:close() local req, err = ocsp.validate_ocsp_response(resp, cert_data) if not req then ngx.log(ngx.ERR, "failed to validate OCSP response: ", err) return end ngx.log(ngx.WARN, "OCSP response validation ok") } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_verify_depth 3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) end -- do } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata --- error_log lua ssl server name: "test.com" OCSP response validation ok --- no_error_log [error] [alert] [emerg] === TEST 13: validate OCSP response - OCSP response signed by an unknown cert and the OCSP response contains the unknown cert FIXME: we should complain in this case. --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ocsp = require "ngx.ocsp" local f = assert(io.open("t/cert/ocsp/chain.pem")) local cert_data = f:read("*a") f:close() local err cert_data, err = ssl.cert_pem_to_der(cert_data) if not cert_data then ngx.log(ngx.ERR, "failed to convert pem cert to der cert: ", err) return end local f = assert(io.open("t/cert/ocsp/ocsp-resp-signed-by-orphaned.der")) local resp = f:read("*a") f:close() local req, err = ocsp.validate_ocsp_response(resp, cert_data) if not req then ngx.log(ngx.ERR, "failed to validate OCSP response: ", err) return end ngx.log(ngx.WARN, "OCSP response validation ok") } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_verify_depth 3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) end -- do } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata --- error_log lua ssl server name: "test.com" OCSP response validation ok --- no_error_log [error] [alert] [emerg] === TEST 14: fail to validate OCSP response - OCSP response signed by an unknown cert and the OCSP response does not contain the unknown cert --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ocsp = require "ngx.ocsp" local f = assert(io.open("t/cert/ocsp/chain.pem")) local cert_data = f:read("*a") f:close() local err cert_data, err = ssl.cert_pem_to_der(cert_data) if not cert_data then ngx.log(ngx.ERR, "failed to convert pem cert to der cert: ", err) return end local f = assert(io.open("t/cert/ocsp/ocsp-resp-signed-by-orphaned-no-certs.der")) local resp = f:read("*a") f:close() -- specify the max length explicitly here, since string buf size may be too short local req, err = ocsp.validate_ocsp_response(resp, cert_data, 128) if not req then ngx.log(ngx.ERR, "failed to validate OCSP response: ", err) return end ngx.log(ngx.WARN, "OCSP response validation ok") } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_verify_depth 3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) end -- do } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata --- error_log lua ssl server name: "test.com" failed to validate OCSP response: OCSP_basic_verify() failed --- no_error_log OCSP response validation ok [alert] [emerg] === TEST 15: fail to validate OCSP response - OCSP response returns revoked status --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ocsp = require "ngx.ocsp" local f = assert(io.open("t/cert/ocsp/revoked-chain.pem")) local cert_data = f:read("*a") f:close() local err cert_data, err = ssl.cert_pem_to_der(cert_data) if not cert_data then ngx.log(ngx.ERR, "failed to convert pem cert to der cert: ", err) return ngx.exit(ngx.ERROR) end local f = assert(io.open("t/cert/ocsp/revoked-ocsp-resp.der")) local resp = f:read("*a") f:close() -- specify the max length explicitly here, since string buf size may be too short local req, err = ocsp.validate_ocsp_response(resp, cert_data, 128) if not req then ngx.log(ngx.ERR, "failed to validate OCSP response: ", err) return ngx.exit(ngx.ERROR) end ngx.log(ngx.WARN, "OCSP response validation ok") } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_verify_depth 3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) end -- do } } --- request GET /t --- response_body connected: 1 failed to do SSL handshake: handshake failed --- error_log lua ssl server name: "test.com" failed to validate OCSP response: certificate status "revoked" in the OCSP response --- no_error_log OCSP response validation ok [alert] [emerg] === TEST 16: good status req from client FIXME: check the OCSP staple actually received by the ssl client --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen 127.0.0.2:$TEST_NGINX_RAND_PORT_1 ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ocsp = require "ngx.ocsp" local f = assert(io.open("t/cert/ocsp/ocsp-resp.der")) local resp = assert(f:read("*a")) f:close() print("resp len: ", #resp) local ok, err = ocsp.set_ocsp_status_resp(resp) if not ok then ngx.log(ngx.ERR, "failed to set ocsp status resp: ", err) return end ngx.log(ngx.WARN, "ocsp status resp set ok: ", err) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_verify_depth 3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("127.0.0.2", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true, true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) end -- do } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata --- error_log lua ssl server name: "test.com" ocsp status resp set ok: nil, --- no_error_log [error] [alert] [emerg] === TEST 17: no status req from client --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen 127.0.0.2:$TEST_NGINX_RAND_PORT_1 ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ocsp = require "ngx.ocsp" local f = assert(io.open("t/cert/ocsp/ocsp-resp.der")) local resp = assert(f:read("*a")) f:close() print("resp len: ", #resp) local ok, err = ocsp.set_ocsp_status_resp(resp) if not ok then ngx.log(ngx.ERR, "failed to set ocsp status resp: ", err) return end ngx.log(ngx.WARN, "ocsp status resp set ok: ", err) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_verify_depth 3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("127.0.0.2", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true, false) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) end -- do } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata --- error_log lua ssl server name: "test.com" ocsp status resp set ok: no status req, --- no_error_log [error] [alert] [emerg] === TEST 18: good OCSP response with nextUpdate present --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ocsp = require "ngx.ocsp" local f = assert(io.open("t/cert/ocsp/cfssl/leaf-bundle.pem")) local cert_data = f:read("*a") f:close() local err cert_data, err = ssl.cert_pem_to_der(cert_data) if not cert_data then ngx.log(ngx.ERR, "failed to convert pem cert to der cert: ", err) return end local f = assert(io.open("t/cert/ocsp/cfssl/ocsp-response-good-response.der")) local resp = f:read("*a") f:close() local ok, next_update_or_err = ocsp.validate_ocsp_response(resp, cert_data) if not ok then ngx.log(ngx.ERR, "failed to validate OCSP response: ", next_update_or_err) return end ngx.log(ngx.WARN, "OCSP response validation ok, next_update: ", next_update_or_err) } ssl_certificate ../../cert/ocsp/cfssl/leaf-bundle.pem; ssl_certificate_key ../../cert/ocsp/cfssl/leaf-key.pem; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/ocsp/cfssl/leaf-bundle.pem; lua_ssl_verify_depth 3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) end -- do } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata --- error_log lua ssl server name: "test.com" OCSP response validation ok, next_update: 1587585600 --- no_error_log [error] [alert] [emerg] --- SKIP === TEST 19: revoked OCSP response with nextUpdate present --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ocsp = require "ngx.ocsp" local f = assert(io.open("t/cert/ocsp/cfssl/leaf-bundle.pem")) local cert_data = f:read("*a") f:close() local err cert_data, err = ssl.cert_pem_to_der(cert_data) if not cert_data then ngx.log(ngx.ERR, "failed to convert pem cert to der cert: ", err) return end local f = assert(io.open("t/cert/ocsp/cfssl/ocsp-response-revoked-response.der")) local resp = f:read("*a") f:close() local ok, next_update_or_err = ocsp.validate_ocsp_response(resp, cert_data) if not ok then ngx.log(ngx.ERR, "failed to validate OCSP response: ", next_update_or_err) return end ngx.log(ngx.WARN, "OCSP response validation ok") } ssl_certificate ../../cert/ocsp/cfssl/leaf-bundle.pem; ssl_certificate_key ../../cert/ocsp/cfssl/leaf-key.pem; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/ocsp/cfssl/leaf-bundle.pem; lua_ssl_verify_depth 3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) end -- do } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata --- error_log lua ssl server name: "test.com" failed to validate OCSP response: certificate status "revoked" in the OCSP response. next_update: nil --- no_error_log OCSP response validation ok [alert] [emerg] --- SKIP lua-resty-core-0.1.31/t/os-getenv-hup.t000066400000000000000000000063451474236722600176250ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: our $SkipReason; BEGIN { if ($ENV{TEST_NGINX_CHECK_LEAK}) { $SkipReason = "unavailable for the hup tests"; } else { undef $ENV{TEST_NGINX_USE_STAP}; } } use lib '.'; use t::TestCore $SkipReason ? (skip_all => $SkipReason) : (); plan tests => repeat_each() * (blocks() * 4); add_block_preprocessor(sub { my $block = shift; if (!defined $block->error_log) { $block->set_value("error_log", qr/\[notice\] .*? \(SIGHUP\) received/); } if (!defined $block->no_error_log) { $block->set_value("no_error_log", "[error]"); } if (!defined $block->request) { $block->set_value("request", "GET /t"); } }); no_shuffle(); use_hup(); $ENV{TEST_NGINX_BAR} = 'old'; $ENV{TEST_NGINX_LUA_PACKAGE_PATH} = "$t::TestCore::lua_package_path"; run_tests(); __DATA__ === TEST 1: env directive explicit value is visible within init_by_lua* --- main_config env FOO=old; --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { require "resty.core" package.loaded.foo = os.getenv("FOO") } --- config location /t { content_by_lua_block { ngx.say(package.loaded.foo) } } --- response_body old --- error_log [notice] === TEST 2: HUP reload changes env value (1/3) --- main_config env FOO=new; --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { require "resty.core" package.loaded.foo = os.getenv("FOO") } --- config location /t { content_by_lua_block { ngx.say(package.loaded.foo) } } --- response_body new === TEST 3: HUP reload changes env value (2/3) --- main_config env FOO=; --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { require "resty.core" package.loaded.foo = os.getenv("FOO") } --- config location /t { content_by_lua_block { ngx.say(package.loaded.foo) } } --- response_body_like chomp \s === TEST 4: HUP reload changes env value (3/3) --- main_config env FOO; --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { require "resty.core" package.loaded.foo = os.getenv("FOO") } --- config location /t { content_by_lua_block { ngx.say(package.loaded.foo) } } --- response_body nil === TEST 5: HUP reload changes visible environment variable (1/2) --- main_config env TEST_NGINX_BAR; --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { require "resty.core" package.loaded.test_nginx_bar = os.getenv("TEST_NGINX_BAR") } --- config location /t { content_by_lua_block { ngx.say(package.loaded.test_nginx_bar) } } --- response_body old === TEST 6: HUP reload changes visible environment variable (2/2) --- main_config env TEST_NGINX_BAR=new; --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { require "resty.core" package.loaded.test_nginx_bar = os.getenv("TEST_NGINX_BAR") } --- config location /t { content_by_lua_block { ngx.say(package.loaded.test_nginx_bar) } } --- response_body new lua-resty-core-0.1.31/t/os-getenv.t000066400000000000000000000120751474236722600170300ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; plan tests => repeat_each() * (blocks() * 3 + 1); add_block_preprocessor(sub { my $block = shift; if (!defined $block->error_log) { $block->set_value("no_error_log", "[error]"); } if (!defined $block->request) { $block->set_value("request", "GET /t"); } }); $ENV{TEST_NGINX_BAR} = 'world'; $ENV{TEST_NGINX_LUA_PACKAGE_PATH} = "$t::TestCore::lua_package_path"; run_tests(); __DATA__ === TEST 1: env directive explicit value is visible within init_by_lua* --- main_config env FOO=hello; --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { require "resty.core" package.loaded.foo = os.getenv("FOO") } --- config location /t { content_by_lua_block { ngx.say(package.loaded.foo, "\n", os.getenv("FOO")) } } --- response_body hello hello === TEST 2: env directive explicit value is visible within init_by_lua* with lua_shared_dict --- main_config env FOO=hello; --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; lua_shared_dict dogs 24k; init_by_lua_block { require "resty.core" package.loaded.foo = os.getenv("FOO") } --- config location /t { content_by_lua_block { ngx.say(package.loaded.foo, "\n", os.getenv("FOO")) } } --- response_body hello hello === TEST 3: env directive explicit value is case-sensitive within init_by_lua* --- main_config env FOO=hello; --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { require "resty.core" package.loaded.foo = os.getenv("foo") } --- config location /t { content_by_lua_block { ngx.say(package.loaded.foo, "\n", os.getenv("foo")) } } --- response_body nil nil === TEST 4: env directives with no value are ignored --- main_config env FOO; --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { require "resty.core" package.loaded.foo = os.getenv("FOO") } --- config location /t { content_by_lua_block { ngx.say(package.loaded.foo, "\n", os.getenv("FOO")) } } --- response_body nil nil === TEST 5: env is visible from environment --- main_config env TEST_NGINX_BAR; --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { require "resty.core" package.loaded.foo = os.getenv("TEST_NGINX_BAR") } --- config location /t { content_by_lua_block { ngx.say(package.loaded.foo, "\n", os.getenv("TEST_NGINX_BAR")) } } --- response_body world world === TEST 6: env explicit set vs environment set --- main_config env TEST_NGINX_BAR=goodbye; --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { require "resty.core" package.loaded.foo = os.getenv("TEST_NGINX_BAR") } --- config location /t { content_by_lua_block { ngx.say(package.loaded.foo, "\n", os.getenv("TEST_NGINX_BAR")) } } --- response_body goodbye goodbye === TEST 7: env directive with empty value --- main_config env FOO=; --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { require "resty.core" package.loaded.foo = os.getenv("FOO") } --- config location /t { content_by_lua_block { ngx.say("in init: ", package.loaded.foo, "\n", "in content: ", os.getenv("FOO")) } } --- response_body_like in init:\s+ in content:\s+ === TEST 8: os.getenv() overwrite is reverted in worker phases --- main_config env FOO=hello; --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { package.loaded.init_os_getenv = os.getenv } --- config location /t { content_by_lua_block { ngx.say("FOO=", os.getenv("FOO")) if os.getenv ~= package.loaded.init_os_getenv then ngx.say("os.getenv() overwrite was reverted") else ngx.say("os.getenv() overwrite was not reverted") end } } --- response_body FOO=hello os.getenv() overwrite was reverted === TEST 9: os.getenv() can be localized after loading resty.core --- main_config env FOO=hello; --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { do local getenv = os.getenv package.loaded.f = function () ngx.log(ngx.NOTICE, "FOO: ", getenv("FOO")) end end require "resty.core" package.loaded.f() package.loaded.is_os_getenv = os.getenv == package.loaded.os_getenv } --- config location /t { content_by_lua_block { package.loaded.f() package.loaded.f() if os.getenv ~= package.loaded.init_os_getenv then ngx.say("os.getenv() overwrite was reverted") else ngx.say("os.getenv() overwrite was not reverted") end } } --- response_body os.getenv() overwrite was reverted --- grep_error_log eval qr/FOO: [a-z]+/ --- grep_error_log_out FOO: hello FOO: hello FOO: hello lua-resty-core-0.1.31/t/param.t000066400000000000000000000025051474236722600162160ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(1014); #master_process_enabled(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 4 + 1); #no_diff(); #no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: ngx.arg getter in set_by_lua --- config location = /t { # set_by_lua_block doesn't support arguments set_by_lua $res ' local arg = ngx.arg local val for i = 1, 30 do val = arg[1] + arg[2] end return val ' $arg_a $arg_b; echo $res; } --- request GET /t?a=1&b=2 --- response_body 3 --- error_log eval qr/\[TRACE\s+\d+ set_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] -- NYI: (?!return to lower frame) === TEST 2: ngx.arg getter in body_filter_by_lua --- config location = /t { echo hello; body_filter_by_lua_block { local arg = ngx.arg local eof local body = "" for i = 1, 30 do body = body .. arg[1] eof = arg[2] end } } --- request GET /t --- error_log eval qr/\[TRACE\s+\d+ body_filter_by_lua\(nginx\.conf:\d+\):5 loop\]/ --- no_error_log [error] -- NYI: (?!return to lower frame) lua-resty-core-0.1.31/t/phase.t000066400000000000000000000011071474236722600162130ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; repeat_each(2); plan tests => repeat_each() * (blocks() * 5); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: get_phase --- config location /lua { content_by_lua_block { local phase for i = 1, 100 do phase = ngx.get_phase() end ngx.say(phase) } } --- request GET /lua --- response_body content --- no_error_log [error] -- NYI: --- error_log eval qr/\[TRACE\s+\d+\s+content_by_lua\(nginx\.conf:\d+\):3 loop\]/ lua-resty-core-0.1.31/t/pipe-cpu-affinity.t000066400000000000000000000037171474236722600204550ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; repeat_each(2); plan tests => repeat_each() * (blocks() * 3 + 2); add_block_preprocessor(sub { my $block = shift; if (!defined $block->error_log) { $block->set_value("no_error_log", "[error]\n[alert]\n[emerg]"); } if (!defined $block->request) { $block->set_value("request", "GET /t"); } }); env_to_nginx("PATH"); master_on(); no_long_string(); run_tests(); __DATA__ === TEST 1: reset the cpu affinity in the sub-process --- main_config worker_cpu_affinity 0001; --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local nproc, err = ngx_pipe.spawn({"nproc"}) if not nproc then ngx.say(err) return end local ncpu, err = nproc:stdout_read_line() if not ncpu then ngx.say(err) return end if tonumber(ncpu) < 2 then -- when ncpu is 1, this test is a smoking test. -- We could not ensure the affinity is reset, but we could -- ensure no error occurs. ngx.say("ok") return end local proc, err = ngx_pipe.spawn({"sleep", 3600}) if not proc then ngx.say(err) return end -- ensure affinity is already reset before running taskset ngx.sleep(0.1) local taskset, err = ngx_pipe.spawn({"taskset", "-pc", proc:pid()}) if not taskset then ngx.say(err) return end local report, err = taskset:stdout_read_line() if not report then ngx.say(err) return end ngx.say(report) } } --- response_body_like (ok|pid \d+'s current affinity list: 0[-,]\d+) lua-resty-core-0.1.31/t/pipe-multi-workers.t000066400000000000000000000016141474236722600206750ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; workers(2); master_on(); repeat_each(1); plan tests => repeat_each() * (blocks() * 2); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: ngx.worker.count --- http_config init_worker_by_lua_block { ngx.timer.at(0, function() local ngx_pipe = require "ngx.pipe" local function check_error(...) local data, err = pcall(...) if not data then ngx.log(ngx.ERR, err) end end check_error(ngx_pipe.spawn, {"ls"}) end) } --- config listen $TEST_NGINX_RAND_PORT_1 reuseport; location = /t { content_by_lua_block { ngx.sleep(0.01) -- ensure timer is fired ngx.say("ok") } } --- request GET /t --- no_error_log failed (9: Bad file descriptor) lua-resty-core-0.1.31/t/pipe-stderr.t000066400000000000000000000473311474236722600173620ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; use Cwd qw(abs_path realpath cwd); use File::Basename; repeat_each(2); plan tests => repeat_each() * (blocks() * 3 + 5); add_block_preprocessor(sub { my $block = shift; my $http_config = $block->http_config || ''; my $init_by_lua_block = $block->init_by_lua_block || ''; $http_config .= <<_EOC_; lua_package_path '$t::TestCore::lua_package_path'; init_by_lua_block { $t::TestCore::init_by_lua_block $init_by_lua_block } _EOC_ $block->set_value("http_config", $http_config); if (!defined $block->error_log) { $block->set_value("no_error_log", "[error]"); } if (!defined $block->request) { $block->set_value("request", "GET /t"); } }); $ENV{TEST_NGINX_CERT_DIR} ||= dirname(realpath(abs_path(__FILE__))); my $port = server_port; if ($port < 65535) { $port++; } else { $port--; } $ENV{TEST_NGINX_SERVER_SSL_PORT} = $port; $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); env_to_nginx("PATH"); no_long_string(); run_tests(); __DATA__ === TEST 1: read stderr, pattern is read line --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sh", "-c", ">&2 echo hello world"}) local data, err = proc:stderr_read_line() if not data then ngx.say(err) else ngx.say(data) end } } --- response_body hello world === TEST 2: read stderr, pattern is read bytes --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sh", "-c", ">&2 echo hello world"}) local data, err = proc:stderr_read_bytes(5) if not data then ngx.say(err) else ngx.say(data) end data, err = proc:stderr_read_bytes(6) if not data then ngx.say(err) else ngx.say(data) end } } --- response_body hello world === TEST 3: read stderr, bytes length is zero --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sh", "-c", ">&2 echo hello world"}) local data, err = proc:stderr_read_bytes(0) if not data then ngx.say(err) else ngx.say("data:", data) end } } --- response_body data: === TEST 4: read stderr, bytes length is less than zero --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sh", "-c", ">&2 echo hello world"}) local ok, err = pcall(proc.stderr_read_bytes, proc, -1) if not ok then ngx.say(err) end } } --- response_body bad len argument === TEST 5: read stderr, bytes length is more than data --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sh", "-c", ">&2 echo hello world"}) local data, err = proc:stderr_read_bytes(20) if not data then ngx.say(err) else ngx.say("data:", data) end } } --- response_body closed === TEST 6: read stderr, pattern is read all --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sh", "-c", ">&2 echo -n hello && sleep 0.05 && >&2 echo -n world"}) local data, err = proc:stderr_read_all() if not data then ngx.say(err) else ngx.say(data) end } } --- response_body helloworld === TEST 7: read stderr, pattern is read any --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sh", "-c", ">&2 echo -n hello && sleep 0.05 && >&2 echo -n world"}) local data, err = proc:stderr_read_any(1024) if not data then ngx.say(err) else ngx.say(data) end data, err = proc:stderr_read_any(1024) if not data then ngx.say(err) else ngx.say(data) end } } --- response_body hello world === TEST 8: read stderr, pattern is read any, with limited, max <= 0 --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sh", "-c", ">&2 echo -n hello && sleep 0.05 && >&2 echo -n world"}) local ok, err = pcall(proc.stderr_read_any, proc, 0) if not ok then ngx.say(err) end } } --- response_body bad max argument === TEST 9: read stderr, without yield --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sh", "-c", ">&2 echo hello world"}) ngx.sleep(0.05) local data, err = proc:stderr_read_line() if not data then ngx.say(err) else ngx.say(data) end } } --- response_body hello world === TEST 10: read stderr, without yield, pattern is read bytes --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sh", "-c", ">&2 echo hello world"}) ngx.sleep(0.05) local data, err = proc:stderr_read_bytes(7) if not data then ngx.say(err) else ngx.say(data) end } } --- response_body hello w === TEST 11: read stderr, without yield, pattern is read all --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sh", "-c", ">&2 echo hello && >&2 echo world"}) ngx.sleep(0.05) local data, err = proc:stderr_read_all() if not data then ngx.say(err) else ngx.print(data) end } } --- response_body hello world === TEST 12: read stderr, without yield, pattern is read any --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sh", "-c", ">&2 echo -n hello && sleep 0.01 && >&2 echo -n world"}) ngx.sleep(0.05) local data, err = proc:stderr_read_any(1024) if not data then ngx.say(err) else ngx.say(data) end } } --- response_body helloworld === TEST 13: read stderr, mix read pattern and stdout/stderr --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local script = [[ echo -n hello >&2 echo world >&2 echo -n more sleep 0.1 >&2 echo -n da sleep 0.1 >&2 echo ta echo more >&2 echo -n data ]] local proc = ngx_pipe.spawn({"sh", "-c", script}) local function check_call(proc, func, ...) local data, err = func(proc, ...) if not data then ngx.say(err) ngx.exit(ngx.OK) end ngx.say(data) end ngx.sleep(0.05) ngx.say("reading any") check_call(proc, proc.stderr_read_any, 1024) ngx.say("reading 3") check_call(proc, proc.stderr_read_bytes, 3) ngx.say("reading line") check_call(proc, proc.stderr_read_line) ngx.say("reading all") check_call(proc, proc.stderr_read_all) } } --- response_body reading any world more reading 3 dat reading line a reading all data === TEST 14: read stderr, timeout --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sleep", "10s"}) proc:set_timeouts(nil, 4000, 100) local ok, err = proc:stderr_read_line() if not ok then ngx.say(err) else ngx.say("ok") end } } --- response_body timeout --- no_error_log [error] --- error_log lua pipe add timer for reading: 100(ms) === TEST 15: read stderr, aborted by uthread kill --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sh", "-c", "sleep 0.1 && >&2 echo hello"}) local function read() proc:stderr_read_line() ngx.log(ngx.ERR, "can't reach here") end local th = ngx.thread.spawn(read) ngx.thread.kill(th) local data, err = proc:stderr_read_line() if not data then ngx.say(err) else ngx.say(data) end } } --- response_body hello --- no_error_log [error] --- error_log lua pipe read process: lua pipe proc read stderr cleanup === TEST 16: more than one coroutines read stderr of a process --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sh", "-c", "sleep 0.1 && >&2 echo hello && >&2 echo world"}) local function read() local data, err = proc:stderr_read_line() if not data then ngx.say(err) else ngx.say(data) end end local th1 = ngx.thread.spawn(read) local th2 = ngx.thread.spawn(read) ngx.thread.wait(th1) ngx.thread.wait(th2) ngx.thread.spawn(read) } } --- response_body pipe busy reading hello world === TEST 17: read stderr while read stdout in other request --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" package.loaded.proc = ngx_pipe.spawn({"sh", "-c", [[ echo hello >&2 echo world sleep 0.1 >&2 echo more echo -n da sleep 0.1 echo ta echo -n more >&2 echo -n data ]]}) local res1, res2 = ngx.location.capture_multi{{"/req1"}, {"/req2"}} ngx.say("stderr:") ngx.print(res1.body) ngx.say("stdout:") ngx.print(res2.body) } } location = /req1 { content_by_lua_block { while true do local data, err = package.loaded.proc:stderr_read_any(1024) if data then ngx.print(data) else if err ~= 'closed' then ngx.say(err) end break end end ngx.say('') } } location = /req2 { content_by_lua_block { while true do local data, err = package.loaded.proc:stdout_read_any(1024) if data then ngx.print(data) else if err ~= 'closed' then ngx.say(err) end break end end ngx.say('') } } --- response_body stderr: world more data stdout: hello data more === TEST 18: read stderr while read stdout in other request, individual error --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" package.loaded.proc = ngx_pipe.spawn({"sleep", 0.5}) package.loaded.proc:set_timeouts(nil, 100) local res1, res2 = ngx.location.capture_multi{{"/req1"}, {"/req2"}} ngx.say("stderr:") ngx.print(res1.body) ngx.say("stdout:") ngx.print(res2.body) } } location = /req1 { content_by_lua_block { local data, err = package.loaded.proc:stderr_read_line() if not data then ngx.say(err) else ngx.say(data) end } } location = /req2 { content_by_lua_block { local data, err = package.loaded.proc:stdout_read_line() if not data then ngx.say(err) else ngx.say(data) end } } --- response_body stderr: closed stdout: timeout === TEST 19: read stderr while read stdout in other request, individual result --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" package.loaded.proc = ngx_pipe.spawn({"sh", "-c", ">&2 echo hello"}) local res1, res2 = ngx.location.capture_multi{{"/req1"}, {"/req2"}} ngx.say("stderr:") ngx.print(res1.body) ngx.say("stdout:") ngx.print(res2.body) } } location = /req1 { content_by_lua_block { local data, err = package.loaded.proc:stderr_read_line() if not data then ngx.say(err) else ngx.say(data) end } } location = /req2 { content_by_lua_block { local data, err = package.loaded.proc:stdout_read_line() if not data then ngx.say(err) else ngx.say(data) end } } --- response_body stderr: hello stdout: closed === TEST 20: read stdout as stderr, mix read pattern and stdout/stderr, merge_stderr is true --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local script = [[ echo hello sleep 0.1 >&2 echo world >&2 echo more sleep 0.1 >&2 echo -n da sleep 0.1 >&2 echo ta echo more >&2 echo -n data ]] local proc = ngx_pipe.spawn({"sh", "-c", script}, {merge_stderr = true}) ngx.say("reading stdout all") local data, err = proc:stdout_read_all() if not data then ngx.say(err) ngx.exit(ngx.OK) end ngx.say(data) proc = ngx_pipe.spawn({"sh", "-c", script}, {merge_stderr = true}) ngx.say("reading any") local i = 1 while true do local data, err = proc:stdout_read_any(1024) i = i + 1 if data then ngx.print(data) else if err ~= 'closed' then ngx.say(err) end break end end ngx.say('') } } --- error_log eval qr/lua pipe spawn process:[0-9A-F]+ pid:\d+ merge_stderr:1 buffer_size:4096/ --- no_error_log [error] --- response_body reading stdout all hello world more data more data reading any hello world more data more data === TEST 21: read stderr, merge_stderr is true --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local args = {"sh", "-c", ">&2 echo hello world"} local proc = ngx_pipe.spawn(args, {merge_stderr = true}) local data, err = proc:stderr_read_all() if not data then ngx.say(err) else ngx.say(data) end local data, err = proc:stderr_read_any(1024) if not data then ngx.say(err) else ngx.say(data) end local data, err = proc:stderr_read_bytes(1) if not data then ngx.say(err) else ngx.say(data) end local data, err = proc:stderr_read_line() if not data then ngx.say(err) else ngx.say(data) end } } --- response_body merged to stdout merged to stdout merged to stdout merged to stdout === TEST 22: read stdout as stderr, aborted by uthread kill, merge_stderr is true --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local args = {"sh", "-c", "sleep 0.1 && >&2 echo hello && echo world"} local proc = ngx_pipe.spawn(args, {merge_stderr = true}) local function read() proc:stdout_read_line() ngx.log(ngx.ERR, "can't reach here") end local th = ngx.thread.spawn(read) ngx.thread.kill(th) local data, err = proc:stdout_read_line() if not data then ngx.say("err: ", err) else ngx.say(data) end local data, err = proc:stdout_read_line() if not data then ngx.say("err: ", err) else ngx.say(data) end } } --- response_body hello world === TEST 23: read stderr, aborted by uthread kill, with graceful shutdown --- user_files >>> a.lua local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"bash"}) local function func() proc:stderr_read_line() ngx.log(ngx.ERR, "can't reach here") end local th = ngx.thread.spawn(func) ngx.thread.kill(th) local data, err = proc:kill(9) -- SIGKILL if not data then io.stdout:write("proc:kill(9) err: ", err) else io.stdout:write("ok") end --- config location = /t { content_by_lua_block { local helper = require "helper" local f = io.open("$TEST_NGINX_HTML_DIR/a.lua") local code = f:read("*a") local proc = helper.run_lua_with_graceful_shutdown("$TEST_NGINX_HTML_DIR", code) proc:set_timeouts(300, 300, 300, 300) local data, err = proc:stdout_read_all() if not data then ngx.say("stdout err: ", err) else ngx.say("stdout: ", data) end local data, err = proc:stderr_read_any(4096) if not data then ngx.say("stderr err: ", err) else ngx.say("stderr: ", data) end } } --- response_body stdout: ok stderr err: closed --- no_error_log [error] === TEST 24: spawn process with stderr_read_timeout option --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sleep", "10s"}, { stderr_read_timeout = 100 }) local data, err = proc:stderr_read_line() if not data then ngx.say("stderr err: ", err) else ngx.say("stderr: ", data) end } } --- response_body stderr err: timeout --- error_log lua pipe add timer for reading: 100(ms) --- no_error_log [error] lua-resty-core-0.1.31/t/pipe-stdin.t000066400000000000000000000320611474236722600171720ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; repeat_each(2); plan tests => repeat_each() * (blocks() * 3 + 10); add_block_preprocessor(sub { my $block = shift; my $http_config = $block->http_config || ''; my $init_by_lua_block = $block->init_by_lua_block || ''; $http_config .= <<_EOC_; lua_package_path '$t::TestCore::lua_package_path'; init_by_lua_block { $t::TestCore::init_by_lua_block $init_by_lua_block } _EOC_ $block->set_value("http_config", $http_config); if (!defined $block->error_log) { $block->set_value("no_error_log", "[error]"); } if (!defined $block->request) { $block->set_value("request", "GET /t"); } }); $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); env_to_nginx("PATH"); no_long_string(); run_tests(); __DATA__ === TEST 1: write process --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({'tee'}) local function write(...) local bytes, err = proc:write(...) if not bytes then ngx.say(err) return end ngx.say(bytes) end write('') write('hello') write(' world') local data, err = proc:stdout_read_any(1024) if not data then ngx.say(err) else ngx.say(data) end } } --- response_body 0 5 6 hello world === TEST 2: write process, bad pipe --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({'echo', 'a'}) ngx.sleep(0.1) local bytes, err = proc:write("test") if not bytes then ngx.say(err) return end ngx.say(bytes) } } --- response_body closed --- error_log eval qr/lua pipe write data error pipe:[0-9A-F]+ \(\d+: Broken pipe\)/ === TEST 3: write process after waiting --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"echo", "hello world"}) local ok, err = proc:wait() if not ok then ngx.say("wait failed: ", err) return end local data, err = proc:write("a") if not data then ngx.say(err) else ngx.say(data) end } } --- response_body closed === TEST 4: write process, timeout --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn({"sleep", 1}) if not proc then ngx.say(err) return end local data = ("1234"):rep(2048) proc:set_timeouts(100) local total = 0 local step = #data while true do local data, err = proc:write(data) if not data then ngx.say(err) break end total = total + step if total > 64 * step then break end end ngx.log(ngx.WARN, "total write before timeout:", total) } } --- response_body timeout --- no_error_log [error] --- error_log lua pipe add timer for writing: 100(ms) lua pipe write yielding === TEST 5: write process, yield and write again --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn({"tee"}) if not proc then ngx.say(err) return end local data = ("1234"):rep(2048) proc:set_timeouts(100) local total = 0 local step = #data while true do local data, err = proc:write(data) if not data then ngx.say(err) break end total = total + step if total > 64 * step then break end end ngx.log(ngx.WARN, "total write before timeout:", total) local function drain() local data, err = proc:stdout_read_bytes(#data / 2) if not data then ngx.log(ngx.ERR, "drain failed: ", err) end end ngx.thread.spawn(function() drain() ngx.sleep(0.1) drain() end) proc:set_timeouts(400) local bytes, err = proc:write(data) if not bytes then ngx.say(err) else ngx.say(bytes) end } } --- response_body timeout 8192 --- no_error_log [error] --- error_log lua pipe write yielding === TEST 6: more than one coroutines write --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn({"sleep", 1}) if not proc then ngx.say(err) return end local data = ("1234"):rep(2048) proc:set_timeouts(100) local total = 0 local step = #data -- make writers blocked later while true do local data, err = proc:write(data) if not data then ngx.say(err) break end total = total + step if total > 64 * step then break end end local function write() local data, err = proc:write(data) if not data then ngx.say(err) else ngx.say(data) end end local th1 = ngx.thread.spawn(write) local th2 = ngx.thread.spawn(write) ngx.thread.wait(th1) ngx.thread.wait(th2) ngx.thread.spawn(write) } } --- response_body timeout pipe busy writing timeout timeout --- no_error_log [error] --- error_log lua pipe add timer for writing: 100(ms) lua pipe write yielding === TEST 7: write process, aborted by uthread kill --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn({"sleep", 1}) if not proc then ngx.say(err) return end local data = ("1234"):rep(2048) proc:set_timeouts(100) local total = 0 local step = #data -- make writers blocked later while true do local data, err = proc:write(data) if not data then ngx.say(err) break end total = total + step if total > 64 * step then break end end local function write() proc:write(data) ngx.log(ngx.ERR, "can't reach here") end local th = ngx.thread.spawn(write) ngx.thread.kill(th) local data, err = proc:write(data) if not data then ngx.say(err) else ngx.say(data) end } } --- response_body timeout timeout --- no_error_log [error] --- error_log lua pipe add timer for writing: 100(ms) lua pipe write yielding lua pipe proc write cleanup === TEST 8: write and read process --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" package.loaded.proc = ngx_pipe.spawn({'tee'}) local res1, res2 = ngx.location.capture_multi{{"/req1"}, {"/req2"}} ngx.print(res1.body) ngx.print(res2.body) } } location = /req1 { content_by_lua_block { local proc = package.loaded.proc local data, err = proc:stdout_read_any(1024) if not data then ngx.say(err) end data, err = proc:write(data) if not data then ngx.say(err) end } } location = /req2 { content_by_lua_block { local proc = package.loaded.proc local data, err = proc:write("payload") if not data then ngx.say(err) end ngx.sleep(0.2) -- yield to let other req read and write the data data, err = proc:stdout_read_any(1024) if not data then ngx.say(err) else ngx.say(data) end } } --- response_body payload === TEST 9: write process, support table, number and boolean arguments --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({'tee'}) local function write(...) local bytes, err = proc:write(...) if not bytes then ngx.say(err) return end ngx.say(bytes) end write(10) write({"hello", " ", "world"}) local data, err = proc:stdout_read_any(1024) if not data then ngx.say(err) else ngx.say(data) end } } --- response_body 2 11 10hello world === TEST 10: write process, throw error if bad argument is written --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({'tee'}) local function write(...) local ok, err = pcall(proc.write, proc, ...) if not ok then ngx.say(err) return end end write(true) write(nil) write(ngx.null) } } --- response_body bad data arg: string, number, or table expected, got boolean bad data arg: string, number, or table expected, got nil bad data arg: string, number, or table expected, got userdata === TEST 11: write process, aborted by uthread kill, with graceful shutdown --- user_files >>> a.lua local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"bash"}) -- make writers blocked later local data = ("1234"):rep(2048) proc:set_timeouts(300) local total = 0 local step = #data while true do local data, err = proc:write(data) if not data then ngx.log(ngx.ERR, "proc write error: ", err) break end total = total + step if total > 64 * step then break end end local function func() proc:write("blah blah") end local th = ngx.thread.spawn(func) ngx.thread.kill(th) local data, err = proc:kill(9) if not data then io.stdout:write("proc:kill(9) err: ", err) else io.stdout:write("ok") end --- config location = /t { content_by_lua_block { local helper = require "helper" local spawn = helper.run_lua_with_graceful_shutdown local f = io.open("$TEST_NGINX_HTML_DIR/a.lua") local code = f:read("*a") local proc = spawn("$TEST_NGINX_HTML_DIR", code) proc:set_timeouts(nil, 1000, 1000) local data, err = proc:stdout_read_all() if not data then ngx.say("stdout err: ", err) else ngx.say("stdout: ", data) end local data, err = proc:stderr_read_any(4096) if not data then ngx.say("stderr err: ", err) else ngx.say("stderr: ", data) end } } --- response_body stdout: ok stderr err: closed --- no_error_log [error] === TEST 12: spawn process with write_timeout option --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn({"sleep", 1}, { write_timeout = 100 }) local data = ("1234"):rep(2048) local total = 0 local step = #data while true do local data, err = proc:write(data) if not data then ngx.say(err) break end total = total + step if total > 64 * step then break end end } } --- response_body timeout --- error_log lua pipe add timer for writing: 100(ms) lua pipe write yielding --- no_error_log [error] lua-resty-core-0.1.31/t/pipe-stdout.t000066400000000000000000000606161474236722600174020ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; use Cwd qw(abs_path realpath cwd); use File::Basename; repeat_each(2); plan tests => repeat_each() * (blocks() * 3 + 6); add_block_preprocessor(sub { my $block = shift; my $http_config = $block->http_config || ''; my $init_by_lua_block = $block->init_by_lua_block || ''; $http_config .= <<_EOC_; lua_package_path '$t::TestCore::lua_package_path'; init_by_lua_block { $t::TestCore::init_by_lua_block $init_by_lua_block } _EOC_ $block->set_value("http_config", $http_config); if (!defined $block->error_log) { $block->set_value("no_error_log", "[error]"); } if (!defined $block->request) { $block->set_value("request", "GET /t"); } }); $ENV{TEST_NGINX_CERT_DIR} ||= dirname(realpath(abs_path(__FILE__))); my $port = server_port; if ($port < 65535) { $port++; } else { $port--; } $ENV{TEST_NGINX_SERVER_SSL_PORT} = $port; $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); env_to_nginx("PATH"); no_long_string(); run_tests(); __DATA__ === TEST 1: read process, pattern is read line --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"echo", "hello world"}) local data, err = proc:stdout_read_line() if not data then ngx.say(err) else ngx.say(data) end } } --- response_body hello world === TEST 2: read process, read line without line break --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"echo", "-n", "hello world"}) local data, err, partial = proc:stdout_read_line() if not data then ngx.say(err) ngx.say(partial) else ngx.say(data) end } } --- response_body closed hello world === TEST 3: read process, pattern is read bytes --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"echo", "hello world"}) local data, err = proc:stdout_read_bytes(5) if not data then ngx.say(err) else ngx.say(data) end data, err = proc:stdout_read_bytes(6) if not data then ngx.say(err) else ngx.say(data) end } } --- response_body hello world === TEST 4: read process, bytes length is zero --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"echo", "hello world"}) local data, err = proc:stdout_read_bytes(0) if not data then ngx.say(err) else ngx.say("data:", data) end } } --- response_body data: === TEST 5: read process, bytes length is less than zero --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"echo", "hello world"}) local ok, err = pcall(proc.stdout_read_bytes, proc, -1) if not ok then ngx.say(err) end } } --- response_body bad len argument === TEST 6: read process, bytes length is more than data --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"echo", "hello world"}) local data, err = proc:stdout_read_bytes(20) if not data then ngx.say(err) else ngx.say("data:", data) end } } --- response_body closed === TEST 7: read process, pattern is read all --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sh", "-c", "echo -n hello && sleep 0.05 && echo -n world"}) local data, err = proc:stdout_read_all() if not data then ngx.say(err) else ngx.say(data) end } } --- response_body helloworld === TEST 8: read process, pattern is read any --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sh", "-c", "echo -n hello && sleep 0.05 && echo -n world"}) -- increase timeout to ensure read_any could return before timeout proc:set_timeouts(5000, 5000, 5000, nil) local data, err = proc:stdout_read_any(1024) if not data then ngx.say(err) else ngx.say(data) end data, err = proc:stdout_read_any(1024) if not data then ngx.say(err) else ngx.say(data) end } } --- response_body hello world === TEST 9: read process, pattern is read any, with limited, max <= 0 --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sh", "-c", "echo -n hello && sleep 0.05 && echo -n world"}) local ok, err = pcall(proc.stdout_read_any, proc, 0) if not ok then ngx.say(err) end } } --- response_body bad max argument === TEST 10: read process, pattern is read any, with limited, limit larger than read data --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sh", "-c", "echo -n hello && sleep 0.05 && echo -n world"}) local data, err = proc:stdout_read_any(1024) if not data then ngx.say(err) else ngx.say(data) end data, err = proc:stdout_read_any(512) if not data then ngx.say(err) else ngx.say(data) end } } --- response_body hello world === TEST 11: read process, pattern is read any, with limited, limit smaller than read data --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sh", "-c", "echo -n hello && sleep 0.05 && echo -n world"}) local data, err = proc:stdout_read_any(4) if not data then ngx.say(err) else ngx.say(data) end data, err = proc:stdout_read_any(3) if not data then ngx.say(err) else ngx.say(data) end data, err = proc:stdout_read_any(1024) if not data then ngx.say(err) else ngx.say(data) end } } --- response_body hell o world === TEST 12: read process, without yield --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"echo", "hello world"}) ngx.sleep(0.05) local data, err = proc:stdout_read_line() if not data then ngx.say(err) else ngx.say(data) end } } --- response_body hello world === TEST 13: read process, without yield, get partial data --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"echo", "-n", "hello world"}) ngx.sleep(0.05) local data, err, partial = proc:stdout_read_line() if not data then ngx.say(err) ngx.say(partial) else ngx.say(data) end } } --- response_body closed hello world === TEST 14: read process, without yield, pattern is read bytes --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"echo", "hello world"}) ngx.sleep(0.05) local data, err = proc:stdout_read_bytes(9) if not data then ngx.say(err) else ngx.say(data) end } } --- response_body hello wor === TEST 15: read process, without yield, pattern is read all --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sh", "-c", "echo hello && echo world"}) ngx.sleep(0.05) local data, err = proc:stdout_read_all() if not data then ngx.say(err) else ngx.print(data) end } } --- response_body hello world === TEST 16: read process, without yield, pattern is read any --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sh", "-c", "echo -n hello && sleep 0.01 && echo -n world"}) ngx.sleep(0.05) local data, err = proc:stdout_read_any(1024) if not data then ngx.say(err) else ngx.say(data) end } } --- response_body helloworld === TEST 17: read process, without yield, read more data than preallocated buffer --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local s = ("0123"):rep(1024) local proc = ngx_pipe.spawn({"echo", "-n", s}) ngx.sleep(0.05) local data, err = proc:stdout_read_all() if not data then ngx.say(err) elseif data ~= s then ngx.say("actual read:", data) else ngx.say("ok") end } } --- response_body ok === TEST 18: read process, without yield, read more partial data than preallocated buffer --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local s = ("0123"):rep(1024) local proc = ngx_pipe.spawn({"echo", "-n", s}) ngx.sleep(0.05) local data, err, partial = proc:stdout_read_line() if not data then ngx.say(err) if partial ~= s then ngx.say("actual read:", data) else ngx.say("ok") end end } } --- response_body closed ok === TEST 19: read process, with yield, read more data than preallocated buffer --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local s = ("0123"):rep(1024) local proc = ngx_pipe.spawn({"echo", "-n", s}) local data, err = proc:stdout_read_all() if not data then ngx.say(err) elseif data ~= s then ngx.say("actual read:", data) else ngx.say("ok") end } } --- response_body ok --- no_error_log [error] --- error_log lua pipe read yielding === TEST 20: read process, with yield, read more partial data than preallocated buffer --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local s = ("0123"):rep(1024) local proc = ngx_pipe.spawn({"echo", "-n", s}) local data, err, partial = proc:stdout_read_line() if not data then ngx.say(err) if partial ~= s then ngx.say("actual read:", data) else ngx.say("ok") end end } } --- no_error_log [error] --- error_log lua pipe read yielding --- response_body closed ok === TEST 21: read process, mix read pattern --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local script = [[ echo -n hello sleep 0.1 echo world echo more sleep 0.1 echo -n da sleep 0.1 echo -n ta ]] local proc = ngx_pipe.spawn({"sh", "-c", script}) local function check_call(proc, func, ...) local data, err = func(proc, ...) if not data then ngx.say(err) ngx.exit(ngx.OK) end ngx.say(data) end ngx.say("reading any") check_call(proc, proc.stdout_read_any, 1024) ngx.say("reading 3") check_call(proc, proc.stdout_read_bytes, 3) ngx.say("reading line") check_call(proc, proc.stdout_read_line) ngx.say("reading 2") check_call(proc, proc.stdout_read_bytes, 2) ngx.say("reading any") check_call(proc, proc.stdout_read_any, 1024) ngx.say("reading all") check_call(proc, proc.stdout_read_all) } } --- response_body reading any hello reading 3 wor reading line ld reading 2 mo reading any re reading all data === TEST 22: read process, no data to read --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sleep", 0.01}) local data, err = proc:stdout_read_any(1024) if not data then ngx.say(err) else ngx.say("data:", data) end } } --- response_body closed === TEST 23: read process, no data to read, use read all --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sleep", 0.01}) local data, err = proc:stdout_read_all() if not data then ngx.say(err) else ngx.say("data:", data) end } } --- response_body data: === TEST 24: read process after waiting --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"echo", "hello world"}) local ok, err = proc:wait() if not ok then ngx.say("wait failed: ", err) return end local data, err = proc:stdout_read_line() if not data then ngx.say(err) else ngx.say(data) end } } --- response_body closed === TEST 25: more than one coroutines read a process --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sh", "-c", "sleep 0.1 && echo hello && echo world"}) local function read() local data, err = proc:stdout_read_line() if not data then ngx.say(err) else ngx.say(data) end end local th1 = ngx.thread.spawn(read) local th2 = ngx.thread.spawn(read) ngx.thread.wait(th1) ngx.thread.wait(th2) ngx.thread.spawn(read) } } --- response_body pipe busy reading hello world === TEST 26: read process, timeout --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sleep", "10s"}) proc:set_timeouts(nil, 100) local ok, err = proc:stdout_read_line() if not ok then ngx.say(err) else ngx.say("ok") end } } --- response_body timeout --- no_error_log [error] --- error_log lua pipe add timer for reading: 100(ms) === TEST 27: read process, aborted by uthread kill --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sh", "-c", "sleep 0.1 && echo hello"}) local function read() proc:stdout_read_line() ngx.log(ngx.ERR, "can't reach here") end local th = ngx.thread.spawn(read) ngx.thread.kill(th) local data, err = proc:stdout_read_line() if not data then ngx.say(err) else ngx.say(data) end } } --- response_body hello --- no_error_log [error] --- error_log lua pipe read process: lua pipe proc read stdout cleanup === TEST 28: read process while waiting process in other request --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" package.loaded.proc = ngx_pipe.spawn({"sh", "-c", "sleep 0.01 && echo hello world && exit 2"}) local res1 = ngx.location.capture("/req1") local res2 = ngx.location.capture("/req2") ngx.print(res1.body) ngx.print(res2.body) } } location = /req1 { content_by_lua_block { local data, err = package.loaded.proc:stdout_read_line() if not data then ngx.say(err) else ngx.say(data) end } } location = /req2 { content_by_lua_block { local ok, reason, status = package.loaded.proc:wait() if not ok then ngx.say(reason) ngx.say(status) end } } --- response_body hello world exit 2 === TEST 29: read process while waiting process in other request, return error --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" package.loaded.proc = ngx_pipe.spawn({"sh", "-c", "sleep 10s"}) local res1, res2 = ngx.location.capture_multi{{"/req1"}, {"/req2"}} ngx.print(res1.body) ngx.print(res2.body) } } location = /req1 { content_by_lua_block { local proc = package.loaded.proc proc:set_timeouts(nil, 100) local data, err = proc:stdout_read_line() if not data then ngx.say(err) else ngx.say(data) end } } location = /req2 { content_by_lua_block { local proc = package.loaded.proc -- sleep to ensure proc is already spawned under Valgrind ngx.sleep(0.2) os.execute("kill -TERM " .. proc:pid()) local ok, reason, status = proc:wait() if not ok then ngx.say(reason) ngx.say(status) end } } --- response_body timeout signal 15 === TEST 30: user case with read and wait --- no_checke_leak --- http_config server { listen $TEST_NGINX_SERVER_SSL_PORT ssl; server_name test.com; ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; } --- config lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; location /t { set $addr 127.0.0.1:$TEST_NGINX_SERVER_SSL_PORT; content_by_lua_block { local ngx_pipe = require "ngx.pipe" local addr = ngx.var.addr; local f, err = ngx_pipe.spawn({"sh", "-c", "echo 'Q' | openssl s_client -connect " .. addr}) if not f then ngx.say(err) return end local out = f:stdout_read_all() if out:find("CONNECTED", 1, true) ~= 1 then ngx.say("could not find CONNECTED in output: ", out) local stderr_out = f:stderr_read_all() ngx.say("the message from stderr is: ", stderr_out) return end local ok, reason = f:wait() if not ok then ngx.say(reason) else ngx.say('ok') ngx.say(reason) end } } --- response_body ok exit === TEST 31: ensure reading process in phases without yield support is disabled --- http_config init_worker_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"echo", "hello world"}) local ok, err = pcall(proc.stdout_read_line, proc) if not ok then package.loaded.res = err end } --- config location = /t { content_by_lua_block { ngx.say(package.loaded.res) } } --- response_body_like .+ API disabled in the context of init_worker_by_lua\* === TEST 32: but we could spawn it in init_worker_by_lua and read it later --- http_config init_worker_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"echo", "hello world"}) package.loaded.proc = proc } --- config location = /t { content_by_lua_block { local proc = package.loaded.proc if proc then local data, err = proc:stdout_read_line() if not data then ngx.say(err) else ngx.say(data) end -- we could only read once as we only spawn the proess once package.loaded.proc = nil else -- so just return the expected data in repeated tests. ngx.say("closed") end } } --- response_body closed === TEST 33: read process, aborted by uthread kill, with graceful shutdown --- user_files >>> a.lua local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"bash"}) local function func() proc:stdout_read_line() ngx.log(ngx.ERR, "can't reach here") end local th = ngx.thread.spawn(func) ngx.thread.kill(th) local data, err = proc:kill(9) -- SIGKILL if not data then io.stdout:write("proc:kill(9) err: ", err) else io.stdout:write("ok") end --- config location = /t { content_by_lua_block { local helper = require "helper" local f = io.open("$TEST_NGINX_HTML_DIR/a.lua") local code = f:read("*a") local proc = helper.run_lua_with_graceful_shutdown("$TEST_NGINX_HTML_DIR", code) proc:set_timeouts(100, 100, 100, 100) local data, err = proc:stdout_read_all() if not data then ngx.say("stdout err: ", err) else ngx.say("stdout: ", data) end local data, err = proc:stderr_read_any(4096) if not data then ngx.say("stderr err: ", err) else ngx.say("stderr: ", data) end } } --- response_body stdout: ok stderr err: closed --- no_error_log [error] === TEST 34: spawn process with stdout_read_timeout option --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sleep", "10s"}, { stdout_read_timeout = 100 }) local data, err = proc:stdout_read_line() if not data then ngx.say("stdout err: ", err) else ngx.say("stdout: ", data) end } } --- response_body stdout err: timeout --- error_log lua pipe add timer for reading: 100(ms) --- no_error_log [error] === TEST 35: start a daemon process --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sh", "-c", "daemonize /usr/bin/sleep 30 >/dev/null 2>&1"}) local data, err = proc:stdout_read_all() if not data then ngx.say(err) end ngx.say("OK") } } --- response_body OK --- no_error_log [error] lua-resty-core-0.1.31/t/pipe.t000066400000000000000000001364121474236722600160600ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; repeat_each(2); plan tests => repeat_each() * (blocks() * 3 + 20) + 2; add_block_preprocessor(sub { my $block = shift; my $http_config = $block->http_config || ''; my $init_by_lua_block = $block->init_by_lua_block || ''; $http_config .= <<_EOC_; lua_package_path '$t::TestCore::lua_package_path'; init_by_lua_block { $t::TestCore::init_by_lua_block $init_by_lua_block } _EOC_ $block->set_value("http_config", $http_config); if (!defined $block->error_log) { $block->set_value("no_error_log", "[error]"); } if (!defined $block->request) { $block->set_value("request", "GET /t"); } }); $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); $ENV{TEST_NGINX_LUA_PACKAGE_PATH} = "$t::TestCore::lua_package_path"; env_to_nginx("PATH"); no_long_string(); run_tests(); __DATA__ === TEST 1: check pipe spawn arguments --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local function check_error(...) local data, err = pcall(...) if not data then ngx.say(err) else ngx.say('ok') end end check_error(ngx_pipe.spawn, nil) check_error(ngx_pipe.spawn, {}) check_error(ngx_pipe.spawn, {"ls"}, {buffer_size = 0}) check_error(ngx_pipe.spawn, {"ls"}, {buffer_size = 0.5}) check_error(ngx_pipe.spawn, {"ls"}, {buffer_size = "1"}) check_error(ngx_pipe.spawn, {"ls"}, {buffer_size = true}) } } --- response_body bad args arg: table expected, got nil bad args arg: non-empty table expected bad buffer_size option bad buffer_size option ok bad buffer_size option === TEST 2: spawn process, with buffer_size option --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn({"ls"}, {buffer_size = 256}) if not proc then ngx.say(err) else ngx.say('ok') end } } --- response_body ok --- error_log eval qr/lua pipe spawn process:[0-9A-F]+ pid:\d+ merge_stderr:0 buffer_size:256/ --- no_error_log [error] === TEST 3: ensure process is destroyed in GC --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" do local proc, err = ngx_pipe.spawn({"ls", "-l"}) if not proc then ngx.say(err) return end end collectgarbage() ngx.say("ok") } } --- response_body ok --- no_error_log [error] --- error_log lua pipe destroy process: === TEST 4: check phase for process wait --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn({"sleep", 0.1}) if not proc then ngx.say(err) return end package.loaded.proc = proc } log_by_lua_block { package.loaded.proc:wait() } } --- error_log API disabled in the context of log_by_lua === TEST 5: check process wait arguments --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn({"sleep", 0.1}) proc.wait() } } --- error_code: 500 --- ignore_response_body --- error_log eval qr/\[error\] .*? runtime error: content_by_lua\(nginx\.conf\:\d+\):\d+: not a process instance/ --- no_error_log [crit] === TEST 6: wait an already waited process --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn({"ls"}) if not proc then ngx.say(err) return end local ok, err = proc:wait() if not ok then ngx.say(err) return end local ok, err = proc:wait() if not ok then ngx.say(err) end } } --- response_body exited === TEST 7: more than one coroutines wait a process --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn({"sleep", 0.1}) if not proc then ngx.say(err) return end local function wait() local ok, err = proc:wait() if not ok then ngx.say(err) end end local th1 = ngx.thread.spawn(wait) local th2 = ngx.thread.spawn(wait) ngx.thread.wait(th1) ngx.thread.wait(th2) ngx.thread.spawn(wait) } } --- response_body pipe busy waiting exited === TEST 8: wait process, process exited abnormally before waiting --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn({"sh", "-c", "sleep 0.1 && exit 2"}) if not proc then ngx.say(err) return end ngx.sleep(0.2) local ok, reason, status = proc:wait() if ok == false then ngx.say(reason, " status: ", status) elseif ok == nil then ngx.say(reason) else ngx.say("ok") end } } --- response_body exit status: 2 --- no_error_log [error] --- error_log lua pipe wait process: === TEST 9: wait process, process killed by signal before waiting --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn({"sleep", "10s"}) if not proc then ngx.say(err) return end -- sleep to ensure proc is already spawned under Valgrind ngx.sleep(0.2) os.execute("kill -INT " .. proc:pid()) ngx.sleep(0.2) local ok, reason, status = proc:wait() if ok == false then ngx.say(reason, " status: ", status) elseif ok == nil then ngx.say(reason) else ngx.say("ok") end } } --- response_body --- response_body signal status: 2 --- no_error_log [error] --- error_log lua pipe wait process: === TEST 10: wait process, process exited before waiting --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn({"sleep", 0.1}) if not proc then ngx.say(err) return end ngx.sleep(0.2) local ok, reason, status = proc:wait() if ok ~= nil then ngx.say("ok: ", ok) ngx.say(reason, " status: ", status) else ngx.say(reason) end } } --- response_body ok: true exit status: 0 --- no_error_log [error] --- error_log lua pipe wait process: === TEST 11: pid() return process pid --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn({"sleep", 0.1}) if not proc then ngx.say(err) return end local pid = proc:pid() ngx.say("pid: ", pid, " type: ", type(pid)) local ok, reason, status = proc:wait() if not ok then ngx.say(reason) return end pid = proc:pid() ngx.say("pid: ", pid, " type: ", type(pid)) } } --- response_body_like pid: \d+ type: number pid: \d+ type: number === TEST 12: wait process, aborted by uthread kill --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn({"sleep", "10s"}) if not proc then ngx.say(err) return end local function wait() proc:wait() ngx.log(ngx.ERR, "can't reach here") end local th = ngx.thread.spawn(wait) ngx.thread.kill(th) proc:set_timeouts(nil, nil, nil, 100) local ok, err = proc:wait() if not ok then ngx.say(err) else ngx.say("ok") end } } --- response_body timeout --- no_error_log [error] --- error_log lua pipe wait process: lua pipe proc wait cleanup === TEST 13: wait process which exited abnormally --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn({"sh", "-c", "sleep 0.1 && exit 2"}) if not proc then ngx.say(err) return end local ok, reason, status = proc:wait() if not ok then ngx.say(reason) ngx.say(status) else ngx.say("ok") end } } --- response_body exit 2 === TEST 14: wait process which terminated by signal --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn({"sleep", "5s"}) if not proc then ngx.say(err) return end local pid = proc:pid() local function wait() local ok, reason, status = proc:wait() if not ok then ngx.say(reason) ngx.say(status) else ngx.say("ok") end end ngx.thread.spawn(wait) -- sleep to ensure proc is already spawned under Valgrind ngx.sleep(0.2) os.execute("kill -TERM " .. pid) } } --- response_body signal 15 === TEST 15: avoid set_timeouts overflow --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn({"sleep", "5s"}) if not proc then ngx.say(err) return end local function check_timeouts_overflow(write, stdout_read, stderr_read, wait) local ok, err = pcall(proc.set_timeouts, proc, write, stdout_read, stderr_read, wait) if not ok then ngx.say("failed to set timeouts: ", err) else ngx.say("set_timeouts: ok") end end ngx.say("write_timeout:") check_timeouts_overflow((2 ^ 32) - 1, 500, 500, 500) check_timeouts_overflow(2 ^ 32, 500, 500, 500) ngx.say("\nstdout_read_timeout:") check_timeouts_overflow(500, (2 ^ 32) - 1, 500, 500) check_timeouts_overflow(500, 2 ^ 32, 500, 500) ngx.say("\nstderr_read_timeout:") check_timeouts_overflow(500, 500, (2 ^ 32) - 1, 500) check_timeouts_overflow(500, 500, 2 ^ 32, 500) ngx.say("\nwait_timeout:") check_timeouts_overflow(500, 500, 500, (2 ^ 32) - 1) check_timeouts_overflow(500, 500, 500, 2 ^ 32) } } --- response_body write_timeout: set_timeouts: ok failed to set timeouts: bad write_timeout option stdout_read_timeout: set_timeouts: ok failed to set timeouts: bad stdout_read_timeout option stderr_read_timeout: set_timeouts: ok failed to set timeouts: bad stderr_read_timeout option wait_timeout: set_timeouts: ok failed to set timeouts: bad wait_timeout option === TEST 16: avoid setting negative timeout --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn({"sleep", "5s"}) if not proc then ngx.say(err) return end local function check_timeouts(write, stdout_read, stderr_read, wait) local ok, err = pcall(proc.set_timeouts, proc, write, stdout_read, stderr_read, wait) if not ok then ngx.say("failed to set timeouts: ", err) else ngx.say("set_timeouts: ok") end end check_timeouts(0, 0, 0, 0) ngx.say("\nwrite_timeout:") check_timeouts(-1, 0, 0, 0) ngx.say("\nstdout_read_timeout:") check_timeouts(0, -1, 0, 0) ngx.say("\nstderr_read_timeout:") check_timeouts(0, 0, -1, 0) ngx.say("\nwait_timeout:") check_timeouts(0, 0, 0, -1) } } --- response_body set_timeouts: ok write_timeout: failed to set timeouts: bad write_timeout option stdout_read_timeout: failed to set timeouts: bad stdout_read_timeout option stderr_read_timeout: failed to set timeouts: bad stderr_read_timeout option wait_timeout: failed to set timeouts: bad wait_timeout option === TEST 17: wait process, timeout --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn({"sleep", "10s"}) if not proc then ngx.say(err) return end proc:set_timeouts(nil, nil, nil, 100) local ok, err = proc:wait() if not ok then ngx.say(err) else ngx.say("ok") end } } --- response_body timeout --- no_error_log [error] --- error_log lua pipe wait process: lua pipe add timer for waiting: 100(ms) === TEST 18: wait process, timeout, test for race condition --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" -- specify a larger timeout, so that there could be enough change -- to run posted event path local proc, err = ngx_pipe.spawn({"sleep", 1}) if not proc then ngx.say(err) return end proc:set_timeouts(nil, nil, nil, 1000) local ok, err = proc:wait() if not ok and err ~= 'timeout' then ngx.say(err) else ngx.say("ok") end } } --- response_body ok === TEST 19: user case with send and shutdown --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local function count_char(...) local proc = ngx_pipe.spawn({'wc', '-c'}) local args = {...} for i = 1, #args do local bytes, err = proc:write(args[i]) if not bytes then ngx.say(err) return end end local ok, err = proc:shutdown('stdin') if not ok then ngx.say(err) return end local data, err = proc:stdout_read_line() if not data then ngx.say(err) return end ngx.say(data) end count_char('') count_char('a') count_char('hello') count_char(("1234"):rep(2048)) } } --- response_body 0 1 5 8192 === TEST 20: shutdown before write/stdout_read/stderr_read --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sh", "-c", "echo 'he\nllo' && >&2 echo 'wo\nrld'"}) local function shutdown(direction) local ok, err = proc:shutdown(direction) if not ok then ngx.log(ngx.ERR, err) end end shutdown('stdin') local ok, err = proc:write("test") if not ok then ngx.say("stdin: ", err) end shutdown('stdout') local ok, err = proc:stdout_read_line() if not ok then ngx.say("stdout: ", err) end shutdown('stderr') local ok, err = proc:stderr_read_line() if not ok then ngx.say("stderr: ", err) end } } --- response_body stdin: closed stdout: closed stderr: closed === TEST 21: shutdown after write/stdout_read/stderr_read --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sh", "-c", "echo 'he\nllo' && >&2 echo 'wo\nrld'"}) local function shutdown(direction) local ok, err = proc:shutdown(direction) if not ok then ngx.log(ngx.ERR, err) end end proc:write("test") shutdown('stdin') local ok, err = proc:write("test") if not ok then ngx.say("stdin: ", err) end proc:stdout_read_line() shutdown('stdout') local ok, err = proc:stdout_read_line() if not ok then ngx.say("stdout: ", err) end proc:stderr_read_line() shutdown('stderr') local ok, err = proc:stderr_read_line() if not ok then ngx.say("stderr: ", err) end } } --- response_body stdin: closed stdout: closed stderr: closed === TEST 22: shutdown repeatedly is harmless --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sh", "-c", "echo 'he\nllo' && >&2 echo 'wo\nrld'"}) local function shutdown(direction) local ok, err = proc:shutdown(direction) if not ok then ngx.log(ngx.ERR, err) end end proc:write("test") shutdown('stdin') shutdown('stdin') local ok, err = proc:write("test") if not ok then ngx.say("stdin: ", err) end proc:stdout_read_line() shutdown('stdout') shutdown('stdout') local ok, err = proc:stdout_read_line() if not ok then ngx.say("stdout: ", err) end proc:stderr_read_line() shutdown('stderr') shutdown('stderr') local ok, err = proc:stderr_read_line() if not ok then ngx.say("stderr: ", err) end } } --- response_body stdin: closed stdout: closed stderr: closed === TEST 23: shutdown unknown direction --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sh", "-c", "echo hello && >&2 echo world"}) local function shutdown(direction) local ok, err = pcall(proc.shutdown, proc, direction) if not ok then ngx.say(err) end end shutdown("read") shutdown(0) } } --- response_body bad shutdown arg: read bad shutdown arg: 0 === TEST 24: shutdown a direction while a coroutine is waiting on it --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sleep", "10s"}) proc:set_timeouts(100, 100, 100) ngx.thread.spawn(function() local ok, err = proc:stdout_read_line() if not ok then ngx.say("read stdout err: ", err) else ngx.say("read stdout ok") end end) local ok, err = proc:shutdown('stdout') if not ok then ngx.say("shutdown stdout err: ", err) end ngx.thread.spawn(function() local ok, err = proc:stderr_read_line() if not ok then ngx.say("read stderr err: ", err) else ngx.say("read stderr ok") end end) local ok, err = proc:shutdown('stderr') if not ok then ngx.say("shutdown stderr err: ", err) end local data = ("1234"):rep(2048) local total = 0 local step = #data -- make writers blocked later while true do local data, err = proc:write(data) if not data then ngx.say("write stdin err: ", err) break end total = total + step if total > 64 * step then break end end ngx.thread.spawn(function() local ok, err = proc:write(data) if not ok then ngx.say("write stdin err: ", err) else ngx.say("write stdin ok") end end) local ok, err = proc:shutdown('stdin') if not ok then ngx.say("shutdown stdin err: ", err) end } } --- response_body read stdout err: aborted read stderr err: aborted write stdin err: timeout write stdin err: aborted --- no_error_log [error] --- grep_error_log eval qr/lua pipe \w+ yielding/ --- grep_error_log_out lua pipe read yielding lua pipe read yielding lua pipe write yielding lua pipe write yielding === TEST 25: shutdown when merge_stderr is true --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local args = {"sh", "-c", "echo 'he\nllo' && >&2 echo 'wo\nrld'"} local opts = {merge_stderr = true} local function shutdown(proc, direction) local ok, err = proc:shutdown(direction) if not ok then ngx.say("shutdown: ", err) end end local function read_proc(proc) local ok, err = proc:stdout_read_line() if not ok then ngx.say("stdout: ", err) end end ngx.say("shutdown stdout after read") local proc = ngx_pipe.spawn(args, opts) proc:stdout_read_line() shutdown(proc, 'stdout') read_proc(proc) ngx.say("shutdown stdout before read") local proc = ngx_pipe.spawn(args, opts) shutdown(proc, 'stdout') read_proc(proc) ngx.say("shutdown stderr") local proc = ngx_pipe.spawn(args, opts) shutdown(proc, 'stderr') } } --- response_body shutdown stdout after read stdout: closed shutdown stdout before read stdout: closed shutdown stderr shutdown: merged to stdout === TEST 26: interrupt signals which break io.popen should not break ngx.pipe IO github issue openresty/resty-cli#35 --- http_config lua_sa_restart off; --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local filename = "$TEST_NGINX_HTML_DIR/testfile" local f = io.open(filename, 'w') f:write("testfile") f:close() local proc = ngx_pipe.spawn({"openssl", "dgst", "-md5", filename}) local data, err = proc:stdout_read_all() if not data then ngx.say(err) else ngx.say(data) end } } --- response_body_like MD5\([^)]+\)= 8bc944dbd052ef51652e70a5104492e3 === TEST 27: ensure signals ignored by Nginx are reset. --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local binname = "$TEST_NGINX_HTML_DIR/sigpipe" local filename = "$TEST_NGINX_HTML_DIR/sigpipe.c" local f = io.open(filename, 'w') f:write([[ #include #include #include #include int main(void) { kill(getpid(), SIGPIPE); printf("I was not killed by SIGPIPE\n"); return 0; } ]]) f:close() local cmd = "gcc " .. filename .. " -o " .. binname local proc, err = ngx_pipe.spawn({"sh", "-c", cmd}) if not proc then ngx.say("spawn ", cmd, " failed: ", err) return end local msg = proc:stderr_read_all() local ok = proc:wait() if not ok then ngx.say("wait failed: ", msg) return end local proc, err = ngx_pipe.spawn({binname}) if not proc then ngx.say("spawn ", binname, " failed: ", err) return end local data, err = proc:stdout_read_line() if not data then ngx.say(err) else ngx.say(data) end } } --- response_body closed --- timeout: 10s === TEST 28: ensure spawning process in init_by_lua is disabled. --- init_by_lua_block local ngx_pipe = require "ngx.pipe" local ok, err = pcall(ngx_pipe.spawn, {"echo", "hello world"}) if not ok then package.loaded.res = err end --- config location = /t { content_by_lua_block { ngx.say(package.loaded.res) } } --- response_body API disabled in the current context === TEST 29: interact with bc --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"bc"}, {merge_stderr = true}) proc:set_timeouts(1000, 1000, 1000) local function check_call(proc, func, ...) local data, err = func(proc, ...) if not data then ngx.say("ERR: ", err) ngx.exit(ngx.OK) else ngx.log(ngx.WARN, "bc say ", data) end end local step = 0.05 ngx.sleep(step) proc:write("1 + 2\n") ngx.sleep(step) check_call(proc, proc.stdout_read_any, 1024) proc:write("2 ^ 3\n") ngx.sleep(step) check_call(proc, proc.stdout_read_any, 1024) proc:write("quit\n") local ok, reason, status = proc:wait() if not ok then ngx.say(reason) ngx.say(status) else ngx.say("ok") end } } --- response_body ok --- no_error_log [error] --- error_log bc say 3 bc say 8 === TEST 30: allow to specify nil as terminator --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local args = {"sh", "-c", "echo hello", nil, "echo world"} local proc, err = ngx_pipe.spawn(args) if not proc then ngx.say(err) return end local data, err = proc:stdout_read_line() if not data then ngx.say(err) else ngx.say(data) end } } --- response_body hello === TEST 31: specify a string to spawn works like os.execute --- config location = /t { content_by_lua_block { collectgarbage() local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn("echo 'hello' && >&2 echo 'world'") local data, err = proc:stdout_read_line() if not data then ngx.say("stdout: ", err) else ngx.say("stdout: ", data) end local data, err = proc:stderr_read_line() if not data then ngx.say("stderr: ", err) else ngx.say("stderr: ", data) end } } --- response_body stdout: hello stderr: world === TEST 32: wait process which executed failed When execvp failed, we let OS free the memory. Therefore we have to skip this test under Valgrind mode. --- skip_eval: 3: defined $ENV{TEST_NGINX_USE_VALGRIND} --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn({"/exit", "2"}) if not proc then ngx.say(err) return end local ok, reason, status = proc:wait() if not ok then ngx.say(reason) ngx.say(status) else ngx.say("ok") end } } --- response_body exit 1 --- error_log lua pipe child execvp() failed while executing /exit (2: No such file or directory) === TEST 33: wait process, process exited normally after waiting --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn({"sleep", 0.1}) if not proc then ngx.say(err) return end local ok, reason, status = proc:wait() if ok ~= nil then ngx.say("ok: ", ok) ngx.say(reason, " status: ", status) else ngx.say(reason) end } } --- response_body ok: true exit status: 0 --- no_error_log [error] --- error_log lua pipe wait process: === TEST 34: kill process with invalid signal --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sleep", 10}) local function check_pcall(f, ...) local ok, err = pcall(f, ...) if not ok then ngx.say(err) end end local function check_call(f, ...) local ok, err = f(...) if not ok then ngx.say(err) end end check_pcall(proc.kill, proc) check_call(proc.kill, proc, 10000) } } --- response_body bad signal arg: number expected, got nil invalid signal === TEST 35: kill exited process --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"sleep", 0.1}) local ok, err = proc:wait() if not ok then ngx.say(err) return end local function check_call(f, ...) local ok, err = f(...) if not ok then ngx.say(err) end end local SIGKILL = 9 check_call(proc.kill, proc, SIGKILL) proc = ngx_pipe.spawn({"sleep", 0.1}) ngx.sleep(0.5) check_call(proc.kill, proc, SIGKILL) } } --- response_body exited exited === TEST 36: wait process which is terminated by a signal, using proc.kill --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn({"sleep", "5s"}) if not proc then ngx.say(err) return end local pid = proc:pid() local function wait() local ok, reason, status = proc:wait() if not ok then ngx.say(reason) ngx.say(status) else ngx.say("ok") end end ngx.thread.spawn(wait) -- sleep to ensure proc is already spawned under Valgrind ngx.sleep(0.2) local SIGTERM = 15 local ok, err = proc:kill(SIGTERM) if not ok then ngx.say(err) end } } --- response_body signal 15 === TEST 37: kill living sub-process when the process instance is collected by GC. --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" do local proc, err = ngx_pipe.spawn({"sleep", 3600}) if not proc then ngx.say(err) return end end collectgarbage() ngx.say("ok") } } --- response_body ok --- no_error_log [error] --- error_log lua pipe destroy process: lua pipe kill process: === TEST 38: kill living sub-process during Lua VM destruction. --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn({"sleep", 3600}) if not proc then ngx.say(err) return end ngx.say("ok") } } --- response_body ok --- error_log lua pipe destroy process: lua pipe kill process: --- no_shutdown_error_log lua pipe destroy process: lua pipe kill process: === TEST 39: avoided overwritting log fd when stderr is used as destination. --- config location = /t { content_by_lua_block { local function get_ngx_bin_path() local ffi = require "ffi" ffi.cdef[[char **ngx_argv;]] return ffi.string(ffi.C.ngx_argv[0]) end local conf_file = "$TEST_NGINX_HTML_DIR/nginx.conf" local nginx = get_ngx_bin_path() local cmd = nginx .. " -p $TEST_NGINX_HTML_DIR -c " .. conf_file local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn(cmd) if not proc then ngx.log(ngx.ERR, err) return end local data, err = proc:stderr_read_all() if not data then ngx.log(ngx.ERR, err) return end ngx.say(data) } } --- user_files >>> nginx.conf events { worker_connections 64; } error_log stderr error; daemon off; master_process off; worker_processes 1; http { lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_worker_by_lua_block { ngx.timer.at(0, function() require "ngx.pipe".spawn{"no-such-cmd"}:wait() os.exit(0) end) } } >>> logs/error.log --- response_body_like lua pipe child execvp\(\) failed while executing no-such-cmd \(2: No such file or directory\) === TEST 40: avoid shell cmd's constants being GCed --- init_by_lua_block local ngx_pipe = require "ngx.pipe" package.loaded.pipe = ngx_pipe --- config location = /t { content_by_lua_block { collectgarbage() local proc, err = package.loaded.pipe.spawn("wc --help") if not proc then ngx.say(err) return end local ok, reason, status = proc:wait() if not ok then ngx.say(reason) ngx.say(status) else ngx.say("ok") end } } --- response_body ok === TEST 41: log the signal info like what Nginx does for SIGCHLD --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn({"ls"}) if not proc then ngx.say(err) return end local ok, err = proc:wait() if not ok then ngx.say(err) return end ngx.say('ok') } } --- response_body ok --- error_log eval qr/\[notice\] .* signal \d+ \(SIGCHLD\) received from \d+/ --- no_error_log [error] === TEST 42: return nil plus string 'timeout' when waiting process timed out --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn({"sleep", "10s"}) if not proc then ngx.say(err) return end proc:set_timeouts(nil, nil, nil, 10) local ok, err = proc:wait() if not ok then ngx.say(ok) ngx.say(err) else ngx.say("ok") end } } --- response_body nil timeout --- no_error_log [error] --- error_log lua pipe wait process: === TEST 43: spawn sub-process when error_log is configured with syslog --- config location = /t { content_by_lua_block { local function get_ngx_bin_path() local ffi = require "ffi" ffi.cdef[[char **ngx_argv;]] return ffi.string(ffi.C.ngx_argv[0]) end local conf_file = "$TEST_NGINX_HTML_DIR/nginx.conf" local nginx = get_ngx_bin_path() local cmd = nginx .. " -p $TEST_NGINX_HTML_DIR -c " .. conf_file local ngx_pipe = require "ngx.pipe" local ok, reason, status = ngx_pipe.spawn(cmd):wait() ngx.say(ok) ngx.say(reason) ngx.say(status) } } --- user_files >>> nginx.conf events { worker_connections 64; } error_log syslog:server=127.0.0.1:$TEST_NGINX_MEMCACHED_PORT,facility=local1 info; daemon off; master_process off; worker_processes 1; http { lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_worker_by_lua_block { ngx.timer.at(0, function() local ngx_pipe = require "ngx.pipe" local ok, reason, status = ngx_pipe.spawn("echo"):wait() if not ok then os.exit(status) end os.exit(0) end) } } >>> logs/error.log --- response_body true exit 0 --- no_error_log [error] === TEST 44: wait process, aborted by uthread kill, with graceful shutdown --- user_files >>> a.lua local ngx_pipe = require "ngx.pipe" local proc = ngx_pipe.spawn({"bash"}) local function func() proc:wait() ngx.log(ngx.ERR, "can't reach here") end local th = ngx.thread.spawn(func) ngx.thread.kill(th) local data, err = proc:kill(9) if not data then io.stdout:write("proc:kill(9) err: ", err) else io.stdout:write("ok") end --- config location = /t { content_by_lua_block { local helper = require "helper" local f = io.open("$TEST_NGINX_HTML_DIR/a.lua") local code = f:read("*a") local proc = helper.run_lua_with_graceful_shutdown("$TEST_NGINX_HTML_DIR", code) proc:set_timeouts(300, 300, 300, 300) local data, err = proc:stdout_read_all() if not data then ngx.say("stdout err: ", err) else ngx.say("stdout: ", data) end local data, err = proc:stderr_read_any(4096) if not data then ngx.say("stderr err: ", err) else ngx.say("stderr: ", data) end } } --- response_body stdout: ok stderr err: closed --- no_error_log [error] === TEST 45: spawn process, with environ option (sanity) --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn('echo $TEST_ENV', { environ = { "TEST_ENV=blahblah" } }) if not proc then ngx.say(err) return end local data, err = proc:stdout_read_line() if not data then ngx.say(err) else ngx.say(data) end } } --- response_body blahblah === TEST 46: spawn process, with environ option (multiple values) --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn('echo "$TEST_ENV $TEST_FOO"', { environ = { "TEST_ENV=blahblah", "TEST_FOO=hello" } }) if not proc then ngx.say(err) return end local data, err = proc:stdout_read_line() if not data then ngx.say(err) else ngx.say(data) end } } --- response_body blahblah hello === TEST 47: spawn process, with empty environ option (no values) --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn('echo "TEST_ENV:$TEST_ENV"', { environ = {} }) if not proc then ngx.say(err) return end local data, err = proc:stdout_read_line() if not data then ngx.say(err) else ngx.say(data) end } } --- response_body TEST_ENV: === TEST 48: spawn process, with invalid environ option --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local function spawn(environ) local pok, perr = pcall(ngx_pipe.spawn, 'echo $TEST_ENV', { environ = environ }) if not pok then ngx.say(perr) else ngx.say("ok") end end spawn("TEST_ENV=1") spawn({ "TEST_ENV=", 1 }) spawn({ "TEST_ENV" }) spawn({ "=1" }) } } --- response_body bad environ option: table expected, got string bad value at index 2 of environ option: string expected, got number bad value at index 1 of environ option: 'name=[value]' format expected, got 'TEST_ENV' bad value at index 1 of environ option: 'name=[value]' format expected, got '=1' === TEST 49: spawn process, with invalid environ option --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local function spawn(environ) local pok, perr = pcall(ngx_pipe.spawn, 'echo "TEST_ENV:$TEST_ENV"', { environ = environ }) if not pok then ngx.say(perr) return end local proc = perr local data, err = proc:stdout_read_line() if not data then ngx.say(err) else ngx.say(data) end end spawn({ "TEST_ENV =1" }) spawn({ "TEST_ENV= 1" }) spawn({ "TEST_ENV==1" }) } } --- response_body TEST_ENV: TEST_ENV: 1 TEST_ENV:=1 === TEST 50: spawn process, with environ option containing nil holes --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local function spawn(environ) local proc, err = ngx_pipe.spawn('echo "$TEST_ENV2$TEST_ENV"', { environ = environ }) if not proc then ngx.say(err) return end local data, err = proc:stdout_read_line() if not data then ngx.say(err) else ngx.say(data) end end spawn({ "TEST_ENV=1", nil, "TEST_ENV2=2", nil }) spawn({ "TEST_ENV=1", nil, "TEST_ENV2=2" }) spawn({ nil, "TEST_ENV=1", "TEST_ENV2=2"}) spawn({ hash_key = true, "TEST_ENV=1", nil, "TEST_ENV2=2", nil }) spawn({ hash_key = true, "TEST_ENV=1", nil, "TEST_ENV2=2" }) } } --- response_body 1 1 1 1 === TEST 51: spawn process with wait_timeout option --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local proc, err = ngx_pipe.spawn({"sleep", 1}, { wait_timeout = 100 }) local ok, err = proc:wait() if not ok then ngx.say(err) else ngx.say("ok") end } } --- response_body timeout === TEST 52: validate timeout options when spawning process --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local function spawn(opts) local ok, err = pcall(ngx_pipe.spawn, {"sleep", "5s"}, opts) if not ok then ngx.say(err) else ngx.say("ok") end end ngx.say("write_timeout:") spawn({write_timeout = 2 ^ 32}) spawn({write_timeout = -1}) ngx.say("\nstdout_read_timeout:") spawn({stdout_read_timeout = 2 ^ 32}) spawn({stdout_read_timeout = -1}) ngx.say("\nstderr_read_timeout:") spawn({stderr_read_timeout = 2 ^ 32}) spawn({stderr_read_timeout = -1}) ngx.say("\nwait_timeout:") spawn({wait_timeout = 2 ^ 32}) spawn({wait_timeout = -1}) } } --- response_body write_timeout: bad write_timeout option bad write_timeout option stdout_read_timeout: bad stdout_read_timeout option bad stdout_read_timeout option stderr_read_timeout: bad stderr_read_timeout option bad stderr_read_timeout option wait_timeout: bad wait_timeout option bad wait_timeout option === TEST 53: validate timeout options when spawning process --- config location = /t { content_by_lua_block { local ngx_pipe = require "ngx.pipe" local function spawn(opts) local ok, err = pcall(ngx_pipe.spawn, {"sleep", "5s"}, opts) if not ok then ngx.log(ngx.ERR, err) end end spawn({write_timeout = -1}) spawn({stdout_read_timeout = -1}) spawn({stderr_read_timeout = -1}) spawn({wait_timeout = -1}) } } --- ignore_response_body --- error_log eval [ qr/\[error\] .*? content_by_lua\(nginx\.conf:\d+\):\d+: .*? bad write_timeout option/, qr/\[error\] .*? content_by_lua\(nginx\.conf:\d+\):\d+: .*? bad stdout_read_timeout option/, qr/\[error\] .*? content_by_lua\(nginx\.conf:\d+\):\d+: .*? bad stderr_read_timeout option/, qr/\[error\] .*? content_by_lua\(nginx\.conf:\d+\):\d+: .*? bad wait_timeout option/ ] --- no_error_log [crit] lua-resty-core-0.1.31/t/process-type-cache.t000066400000000000000000000031671474236722600206210ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: BEGIN { undef $ENV{TEST_NGINX_USE_STAP}; } use lib '.'; use t::TestCore; #worker_connections(1014); master_on(); #log_level('info'); repeat_each(2); plan tests => repeat_each() * (blocks() * 5); our $HttpConfig = <<_EOC_; proxy_cache_path /tmp/proxy_cache_dir keys_zone=cache_one:200m; $t::TestCore::HttpConfig init_worker_by_lua_block { local base = require "resty.core.base" local v local typ = (require "ngx.process").type for i = 1, 400 do v = typ() end if v == "helper" then ngx.log(ngx.WARN, "process type: ", v) end } _EOC_ #no_diff(); #no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: sanity --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua_block { ngx.sleep(0.1) local v local typ = (require "ngx.process").type for i = 1, 200 do v = typ() end ngx.say("type: ", v) } } --- request GET /t --- response_body type: worker --- grep_error_log eval qr/\[TRACE\s+\d+ init_worker_by_lua\(nginx.conf:\d+\):\d+ loop\]|\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):\d loop\]/ --- grep_error_log_out eval [ qr/\[TRACE\s+\d+ init_worker_by_lua\(nginx.conf:\d+\):\d+ loop\] \[TRACE\s+\d+ content_by_lua\(nginx.conf:\d+\):\d+ loop\] /, qr/\[TRACE\s+\d+ init_worker_by_lua\(nginx.conf:\d+\):\d+ loop\] \[TRACE\s+\d+ content_by_lua\(nginx.conf:\d+\):\d+ loop\] / ] --- no_error_log [error] -- NYI: --- skip_nginx: 5: < 1.11.2 --- wait: 0.2 lua-resty-core-0.1.31/t/process-type-hup.t000066400000000000000000000036521474236722600203510ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: our $SkipReason; BEGIN { if ($ENV{TEST_NGINX_CHECK_LEAK}) { $SkipReason = "unavailable for the hup tests"; } else { $ENV{TEST_NGINX_USE_HUP} = 1; undef $ENV{TEST_NGINX_USE_STAP}; } } use lib '.'; use t::TestCore $SkipReason ? (skip_all => $SkipReason) : (); use Cwd qw(cwd); #worker_connections(1014); master_process_enabled(1); log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 4); my $pwd = cwd(); our $HttpConfig = <<_EOC_; lua_package_path '$t::TestCore::lua_package_path'; init_by_lua_block { $t::TestCore::init_by_lua_block local process = require "ngx.process" local ok, err = process.enable_privileged_agent() if not ok then ngx.log(ngx.ERR, "enable_privileged_agent failed: ", err) end } init_worker_by_lua_block { local base = require "resty.core.base" local typ = require "ngx.process".type if typ() == "privileged agent" then ngx.log(ngx.WARN, "process type: ", typ()) end } _EOC_ #no_diff(); no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: sanity --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua_block { local typ = require "ngx.process".type local f, err = io.open(ngx.config.prefix() .. "/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return end local pid = f:read() -- ngx.say("master pid: [", pid, "]") f:close() ngx.say("type: ", typ()) os.execute("kill -HUP " .. pid) } } --- request GET /t --- response_body type: worker --- error_log init_worker_by_lua(nginx.conf:48):6: process type: privileged --- no_error_log [error] --- skip_nginx: 4: < 1.11.2 lua-resty-core-0.1.31/t/process-type-master.t000066400000000000000000000023421474236722600210430ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: BEGIN { undef $ENV{TEST_NGINX_USE_STAP}; } use lib '.'; use t::TestCore; use Cwd qw(cwd); repeat_each(2); plan tests => repeat_each() * (blocks() * 5); my $pwd = cwd(); our $HttpConfig = <<_EOC_; lua_package_path "$t::TestCore::lua_package_path"; init_by_lua_block { $t::TestCore::init_by_lua_block local v local typ = (require "ngx.process").type for i = 1, 400 do v = typ() end package.loaded.process_type = v } _EOC_ #worker_connections(1014); master_on(); #log_level('error'); #no_diff(); #no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: sanity --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua_block { ngx.say("process type: ", package.loaded.process_type) } } --- request GET /t --- response_body process type: master --- grep_error_log eval qr/\[TRACE\s+\d+ init_by_lua\(nginx.conf:\d+\):\d+ loop\]/ --- grep_error_log_out eval [ qr/\A\[TRACE\s+\d+ init_by_lua\(nginx.conf:\d+\):\d+ loop\] \z/, qr/\A\[TRACE\s+\d+ init_by_lua\(nginx.conf:\d+\):\d+ loop\] \z/ ] --- no_error_log [error] -- NYI: --- skip_nginx: 5: < 1.11.2 lua-resty-core-0.1.31/t/process-type-privileged-agent-connections.t000066400000000000000000000172061474236722600253230ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; master_process_enabled(1); repeat_each(1); plan tests => repeat_each() * (blocks() * 5); $ENV{TEST_NGINX_LUA_PACKAGE_PATH} = $t::TestCore::lua_package_path; $ENV{TEST_NGINX_RANDOM_PORT} = Test::Nginx::Util::server_port(); run_tests(); __DATA__ === TEST 1: specify connections to enable_privileged_agent --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { local process = require "ngx.process" local ok, err = process.enable_privileged_agent(10) if not ok then ngx.log(ngx.ERR, "enable_privileged_agent failed: ", err) end } init_worker_by_lua_block { local base = require "resty.core.base" local typ = (require "ngx.process").type() if typ == "privileged agent" then ngx.log(ngx.WARN, "process type: ", typ) ngx.timer.at(0, function() local tcpsock = ngx.socket.tcp() local ok, err = tcpsock:connect("127.0.0.1", $TEST_NGINX_RANDOM_PORT) if ok then ngx.log(ngx.INFO, "connect ok ") else ngx.log(ngx.INFO, "connect failed " .. tostring(err)) end end) end } --- config location = /t { content_by_lua_block { ngx.sleep(0.1) local typ = require "ngx.process".type() ngx.say("type: ", typ) } } --- request GET /t --- response_body type: worker --- error_log connect ok --- no_error_log connect failed enable_privileged_agent failed --- skip_nginx: 5: < 1.11.2 --- wait: 0.2 === TEST 2: connections exceed limit the real connections you can create is always less than you set. timer will take fake connections. --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { local process = require "ngx.process" local ok, err = process.enable_privileged_agent(10) if not ok then ngx.log(ngx.ERR, "enable_privileged_agent failed: ", err) end } init_worker_by_lua_block { local base = require "resty.core.base" local typ = (require "ngx.process").type() if typ == "privileged agent" then ngx.log(ngx.WARN, "process type: ", typ) ngx.timer.at(0, function() for i = 1, 10 do local tcpsock = ngx.socket.tcp() local ok, err = tcpsock:connect("127.0.0.1", $TEST_NGINX_RANDOM_PORT) if ok then ngx.log(ngx.INFO, "connect ok ") else ngx.log(ngx.INFO, "connect failed " .. tostring(err)) end end end) end } --- config location = /t { content_by_lua_block { ngx.sleep(0.1) local typ = require "ngx.process".type() ngx.say("type: ", typ) } } --- request GET /t --- response_body type: worker --- error_log connect failed worker_connections are not enough --- no_error_log enable_privileged_agent failed --- skip_nginx: 5: < 1.11.2 --- wait: 0.2 === TEST 3: enable_privileged_agent with bad connections connections < 0 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { local process = require "ngx.process" local ok, err = process.enable_privileged_agent(-1) if not ok then ngx.log(ngx.ERR, "enable_privileged_agent failed: ", err) end } init_worker_by_lua_block { local base = require "resty.core.base" local typ = (require "ngx.process").type() if typ == "privileged agent" then ngx.log(ngx.WARN, "process type: ", typ) ngx.timer.at(0, function() for i = 1, 10 do local tcpsock = ngx.socket.tcp() local ok, err = tcpsock:connect("127.0.0.1", $TEST_NGINX_RANDOM_PORT) if ok then ngx.log(ngx.INFO, "connect ok ") else ngx.log(ngx.INFO, "connect failed " .. tostring(err)) end end end) end } --- config location = /t { content_by_lua_block { ngx.sleep(0.1) local typ = require "ngx.process".type() ngx.say("type: ", typ) } } --- request GET /t --- response_body type: worker --- error_log enable_privileged_agent failed: bad 'connections' argument --- no_error_log connect ok connect failed --- skip_nginx: 5: < 1.11.2 --- wait: 0.2 === TEST 4: enable_privileged_agent with bad connections connections is not a number --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { local process = require "ngx.process" local ok, err = process.enable_privileged_agent("10") if not ok then ngx.log(ngx.ERR, "enable_privileged_agent failed: ", err) end } init_worker_by_lua_block { local base = require "resty.core.base" local typ = (require "ngx.process").type() if typ == "privileged agent" then ngx.log(ngx.WARN, "process type: ", typ) ngx.timer.at(0, function() for i = 1, 10 do local tcpsock = ngx.socket.tcp() local ok, err = tcpsock:connect("127.0.0.1", $TEST_NGINX_RANDOM_PORT) if ok then ngx.log(ngx.INFO, "connect ok ") else ngx.log(ngx.INFO, "connect failed " .. tostring(err)) end end end) end } --- config location = /t { content_by_lua_block { ngx.sleep(0.1) local typ = require "ngx.process".type() ngx.say("type: ", typ) } } --- request GET /t --- response_body type: worker --- error_log enable_privileged_agent failed: bad 'connections' argument --- no_error_log connect ok connect failed --- skip_nginx: 5: < 1.11.2 --- wait: 0.2 === TEST 5: enable_privileged_agent with bad connections connections = 0 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { local process = require "ngx.process" local ok, err = process.enable_privileged_agent(0) if not ok then ngx.log(ngx.ERR, "enable_privileged_agent failed: ", err) end } init_worker_by_lua_block { local base = require "resty.core.base" local typ = (require "ngx.process").type() if typ == "privileged agent" then ngx.log(ngx.WARN, "process type: ", typ) ngx.timer.at(0, function() for i = 1, 10 do local tcpsock = ngx.socket.tcp() local ok, err = tcpsock:connect("127.0.0.1", $TEST_NGINX_RANDOM_PORT) if ok then ngx.log(ngx.INFO, "connect ok ") else ngx.log(ngx.INFO, "connect failed " .. tostring(err)) end end end) end } --- config location = /t { content_by_lua_block { ngx.sleep(0.1) local typ = require "ngx.process".type() ngx.say("type: ", typ) } } --- request GET /t --- response_body type: worker --- error_log 0 worker_connection is not enough, privileged agent process cannot be spawned --- no_error_log process type: privileged agent connect ok --- skip_nginx: 5: < 1.11.2 --- wait: 0.2 lua-resty-core-0.1.31/t/process-type-privileged-agent.t000066400000000000000000000105761474236722600230060ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: BEGIN { undef $ENV{TEST_NGINX_USE_STAP}; } use lib '.'; use t::TestCore; $ENV{TEST_NGINX_RANDOM_PORT} = Test::Nginx::Util::server_port(); #worker_connections(1014); master_process_enabled(1); #log_level('error'); repeat_each(2); plan tests => repeat_each() * (blocks() * 5 - 5); add_block_preprocessor(sub { my $block = shift; my $http_config = $block->http_config || ''; my $init_by_lua_block = $block->init_by_lua_block || ''; $http_config .= <<_EOC_; lua_package_path '$t::TestCore::lua_package_path'; init_by_lua_block { $t::TestCore::init_by_lua_block local process = require "ngx.process" local ok, err = process.enable_privileged_agent(8) if not ok then ngx.log(ngx.ERR, "enable_privileged_agent failed: ", err) end } init_worker_by_lua_block { local base = require "resty.core.base" local v local typ = (require "ngx.process").type for i = 1, 400 do v = typ() end if v == "privileged agent" then ngx.log(ngx.WARN, "process type: ", v) ngx.timer.at(0, function() for i = 1, 4 do local tcpsock = ngx.socket.tcp() local ok, err = tcpsock:connect("127.0.0.1", $ENV{TEST_NGINX_RANDOM_PORT}) if ok then ngx.log(ngx.INFO, "connect ok ") else ngx.log(ngx.INFO, "connect not ok " .. tostring(err)) end end end) end } _EOC_ $block->set_value("http_config", $http_config); }); #no_diff(); #no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: sanity --- config location = /t { content_by_lua_block { ngx.sleep(0.1) local v local typ = require "ngx.process".type for i = 1, 200 do v = typ() end ngx.say("type: ", v) } } --- request GET /t --- response_body type: worker --- grep_error_log eval qr/\[TRACE\s+\d+ init_worker_by_lua\(nginx.conf:\d+\):\d+ loop\]|\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):\d+ loop\]|init_worker_by_lua\(nginx.conf:\d+\):\d+: process type: \w+/ --- grep_error_log_out eval [ qr/\[TRACE\s+\d+ init_worker_by_lua\(nginx.conf:\d+\):\d+ loop\] (?:\[TRACE\s+\d+ init_worker_by_lua\(nginx.conf:\d+\):\d+ loop\] )?\[TRACE\s+\d+ content_by_lua\(nginx.conf:\d+\):\d+ loop\] init_worker_by_lua\(nginx.conf:\d+\):10: process type: privileged /, qr/\[TRACE\s+\d+ init_worker_by_lua\(nginx.conf:\d+\):\d+ loop\] (?:\[TRACE\s+\d+ init_worker_by_lua\(nginx.conf:\d+\):\d+ loop\] )?\[TRACE\s+\d+ content_by_lua\(nginx.conf:\d+\):\d+ loop\] init_worker_by_lua\(nginx.conf:\d+\):10: process type: privileged / ] --- no_error_log [error] -- NYI: --- skip_nginx: 5: < 1.11.2 --- wait: 0.2 === TEST 2: `enable_privileged_agent` disabled --- config location = /t { content_by_lua_block { local process = require "ngx.process" local ok, err = process.enable_privileged_agent() if not ok then error(err) end } } --- request GET /t --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log eval qr/\[error\] .*? API disabled in the current context/ --- skip_nginx: 3: < 1.11.2 === TEST 3: `enable_privileged_agent` not patched --- config location = /t { content_by_lua_block { local process = require "ngx.process" local ok, err = process.enable_privileged_agent() if not ok then error(err) end } } --- request GET /t --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log missing privileged agent process patch in the nginx core API disabled in the current context --- skip_nginx: 4: >= 1.11.2 === TEST 4: connections exceed limits --- config location = /t { content_by_lua_block { local process = require "ngx.process" local ok, err = process.enable_privileged_agent() if not ok then error(err) end } } --- request GET /t --- response_body_like: 500 Internal Server Error --- error_code: 500 --- error_log worker_connections are not enough --- skip_nginx: 3: < 1.11.2 lua-resty-core-0.1.31/t/process-type-single.t000066400000000000000000000043501474236722600210320ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: BEGIN { undef $ENV{TEST_NGINX_USE_STAP}; } use lib '.'; use t::TestCore; repeat_each(2); plan tests => repeat_each() * (blocks() * 5); our $HttpConfig = <<_EOC_; lua_package_path '$t::TestCore::lua_package_path'; init_by_lua_block { $t::TestCore::init_by_lua_block local v local typ = (require "ngx.process").type for i = 1, 400 do v = typ() end package.loaded.process_type = v } init_worker_by_lua_block { local v local typ = (require "ngx.process").type for i = 1, 400 do v = typ() end ngx.log(ngx.WARN, "process type in init_by_lua*: ", package.loaded.process_type) ngx.log(ngx.WARN, "process type: ", v) } _EOC_ #worker_connections(1014); #log_level('error'); #no_diff(); #no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: sanity --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua_block { local v local typ = (require "ngx.process").type for i = 1, 400 do v = typ() end ngx.say("process type: ", v) } } --- request GET /t --- response_body process type: single --- grep_error_log eval qr/\[TRACE\s+\d+ init_by_lua\(nginx.conf:\d+\):\d+ loop\]|\[TRACE\s+\d+ init_worker_by_lua\(nginx.conf:\d+\):\d loop\]|\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):\d loop\]|process type in init_by_lua\*: \w+|init_worker_by_lua\(nginx.conf:\d+\):\d+: process type: \w+/ --- grep_error_log_out eval [ qr/\[TRACE\s+\d+ init_by_lua\(nginx.conf:\d+\):\d+ loop\] \[TRACE\s+\d+ init_worker_by_lua\(nginx.conf:\d+\):\d+ loop\] \[TRACE\s+\d+ content_by_lua\(nginx.conf:\d+\):4 loop\] process type in init_by_lua\*: single init_worker_by_lua\(nginx.conf:\d+\):10: process type: single /, qr/\[TRACE\s+\d+ init_by_lua\(nginx.conf:\d+\):\d+ loop\] \[TRACE\s+\d+ init_worker_by_lua\(nginx.conf:\d+\):\d+ loop\] \[TRACE\s+\d+ content_by_lua\(nginx.conf:\d+\):4 loop\] process type in init_by_lua\*: single init_worker_by_lua\(nginx.conf:\d+\):10: process type: single / ] --- no_error_log [error] -- NYI: --- skip_nginx: 5: < 1.11.2 lua-resty-core-0.1.31/t/process-type-worker.t000066400000000000000000000031521474236722600210610ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: BEGIN { undef $ENV{TEST_NGINX_USE_STAP}; } use lib '.'; use t::TestCore; repeat_each(2); plan tests => repeat_each() * (blocks() * 5); our $HttpConfig = <<_EOC_; $t::TestCore::HttpConfig init_worker_by_lua_block { local v local typ = (require "ngx.process").type for i = 1, 400 do v = typ() end ngx.log(ngx.WARN, "process type: ", v) } _EOC_ #worker_connections(1014); master_on(); #log_level('error'); #no_diff(); #no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: sanity --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua_block { local v local typ = (require "ngx.process").type for i = 1, 400 do v = typ() end ngx.say("process type: ", v) } } --- request GET /t --- response_body process type: worker --- grep_error_log eval qr/\[TRACE\s+\d+ init_worker_by_lua\(nginx.conf:\d+\):\d loop\]|\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):\d loop\]|init_worker_by_lua\(nginx.conf:\d+\):\d: process type: \w+/ --- grep_error_log_out eval [ qr/\[TRACE\s+\d+ init_worker_by_lua\(nginx.conf:\d+\):4 loop\] \[TRACE\s+\d+ content_by_lua\(nginx.conf:\d+\):4 loop\] init_worker_by_lua\(nginx.conf:\d+\):8: process type: worker /, qr/\[TRACE\s+\d+ init_worker_by_lua\(nginx.conf:\d+\):4 loop\] \[TRACE\s+\d+ content_by_lua\(nginx.conf:\d+\):4 loop\] init_worker_by_lua\(nginx.conf:\d+\):8: process type: worker / ] --- no_error_log [error] -- NYI: --- skip_nginx: 5: < 1.11.2 lua-resty-core-0.1.31/t/re-base.t000066400000000000000000000116131474236722600164340ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; repeat_each(2); plan tests => repeat_each() * (blocks() * 3); no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: bad pattern --- config location /re { content_by_lua_block { local it, err = ngx.re.gmatch("hello\\nworld", "(abc") if not err then ngx.say("good") else ngx.say("error: ", err) end } } --- request GET /re --- response_body eval $Test::Nginx::Util::PcreVersion == 2 ? "error: pcre2_compile() failed: missing closing parenthesis in \"(abc\"\n" : "error: pcre_compile() failed: missing ) in \"(abc\"\n" --- no_error_log [error] === TEST 2: bad UTF-8 --- config location = /t { content_by_lua_block { local target = "你好" local regex = "你好" -- Note the D here local it, err = ngx.re.gmatch(string.sub(target, 1, 4), regex, "u") if err then ngx.say("error: ", err) return end local m, err = it() if err then ngx.say("error: ", err) return end if m then ngx.say("matched: ", m[0]) else ngx.say("not matched") end } } --- request GET /t --- response_body eval $Test::Nginx::Util::PcreVersion == 2 ? "error: pcre_exec\(\) failed: -4\n" : "error: pcre_exec\(\) failed: -10\n" --- no_error_log [error] === TEST 3: UTF-8 mode without UTF-8 sequence checks --- config location /re { content_by_lua_block { local it = ngx.re.gmatch("你好", ".", "U") local m = it() if m then ngx.say(m[0]) else ngx.say("not matched!") end } } --- stap probe process("$LIBPCRE_PATH").function("pcre_compile") { printf("compile opts: %x\n", $options) } probe process("$LIBPCRE_PATH").function("pcre_exec") { printf("exec opts: %x\n", $options) } --- stap_out compile opts: 800 exec opts: 2000 --- request GET /re --- response_body 你 --- no_error_log [error] === TEST 4: UTF-8 mode with UTF-8 sequence checks --- config location /re { content_by_lua_block { local it = ngx.re.gmatch("你好", ".", "u") local m = it() if m then ngx.say(m[0]) else ngx.say("not matched!") end } } --- stap probe process("$LIBPCRE_PATH").function("pcre_compile") { printf("compile opts: %x\n", $options) } probe process("$LIBPCRE_PATH").function("pcre_exec") { printf("exec opts: %x\n", $options) } # TODO: PCRE2 use different option values from PCRE --- stap_out compile opts: 800 exec opts: 0 --- request GET /re --- response_body 你 --- no_error_log [error] === TEST 5: just hit match limit --- http_config eval: "lua_regex_match_limit 5000;" . $t::TestCore::HttpConfig --- config location /re { content_by_lua_file html/a.lua; } --- user_files >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] local s = string.rep([[ABCDEFG]], 10) local it, err = ngx.re.gmatch(s, re, "o") if not it then ngx.say("failed to gen iterator: ", err) return end local res, err = it() if not res then if err then ngx.say("error: ", err) return end ngx.say("failed to match") return end --- request GET /re --- response_body eval # lua_regex_match_limit uses pcre_extra->match_limit in the PCRE, # but PCRE2 replaces this with pcre2_set_match_limit interface, # which has different effects. $Test::Nginx::Util::PcreVersion == 2 ? "failed to match\n" : "error: pcre_exec() failed: -8\n" === TEST 6: just not hit match limit --- http_config eval: "lua_regex_match_limit 5100;" . $t::TestCore::HttpConfig --- config location /re { content_by_lua_file html/a.lua; } --- user_files >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] local s = string.rep([[ABCDEFG]], 10) local it, err = ngx.re.gmatch(s, re, "o") if not it then ngx.say("failed to gen iterator: ", err) return end local res, err = it() if not res then if err then ngx.say("error: ", err) return end ngx.say("failed to match") return end --- request GET /re --- response_body failed to match lua-resty-core-0.1.31/t/re-bugs.t000066400000000000000000000072521474236722600164660ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; repeat_each(2); plan tests => repeat_each() * (blocks() * 4 - 4); add_block_preprocessor(sub { my $block = shift; my $http_config = $block->http_config || ''; my $init_by_lua_block = $block->init_by_lua_block || ''; $http_config .= <<_EOC_; lua_package_path '$t::TestCore::lua_package_path'; init_by_lua_block { $t::TestCore::init_by_lua_block $init_by_lua_block } _EOC_ $block->set_value("http_config", $http_config); }); no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: PCRE MAP_JIT workaround on macOS --- init_by_lua_block ngx.re.match("c", "test", "jo") --- config location /re { content_by_lua_block { ngx.say(ngx.re.sub("c", "a", "b", "")) ngx.say(ngx.re.sub("c", "a", "b", "jo")) } } --- request GET /re --- response_body c0 c0 --- grep_error_log eval qr/.+parse_regex_opts\(\): .*? disabled in init phase under macOS/ --- grep_error_log_out eval qr/parse_regex_opts\(\): regex compilation disabled in init phase under macOS .*?parse_regex_opts\(\): regex compilation cache disabled in init phase under macOS/s --- no_error_log [error] --- skip_eval 4: $^O ne 'darwin' === TEST 2: PCRE MAP_JIT workaround on macOS logs only once per flag --- init_by_lua_block jit.off() -- must disable in this test or logs will be fuzzy for i = 1, 2 do ngx.re.match("c", "test", "j") end for i = 1, 2 do ngx.re.match("c", "test", "o") end for i = 1, 2 do ngx.re.match("c", "test", "jo") end --- config location /re { content_by_lua_block { ngx.say(ngx.re.sub("c", "a", "b", "")) ngx.say(ngx.re.sub("c", "a", "b", "jo")) } } --- request GET /re --- response_body c0 c0 --- grep_error_log eval qr/parse_regex_opts\(\): .*? disabled in init phase under macOS/ --- grep_error_log_out eval qr/\A(?:parse_regex_opts\(\): regex compilation (?:cache )?disabled in init phase under macOS\s*){4}\z/ --- no_error_log [error] --- skip_eval 4: $^O ne 'darwin' === TEST 3: PCRE MAP_JIT workaround is reverted after init phase --- init_by_lua_block ngx.re.match("c", "test", "jo") --- config location /re { content_by_lua_block { ngx.say(ngx.re.sub("c", "a", "b", "")) ngx.say(ngx.re.sub("c", "a", "b", "jo")) } } --- request GET /re --- response_body c0 c0 --- no_error_log [error] disabled in init phase under macOS, client: --- skip_eval 4: $^O ne 'darwin' === TEST 4: PCRE MAP_JIT workaround is not in effect under other OSs --- init_by_lua_block ngx.re.match("c", "test", "jo") --- config location /re { content_by_lua_block { ngx.say(ngx.re.sub("c", "a", "b", "")) ngx.say(ngx.re.sub("c", "a", "b", "jo")) } } --- request GET /re --- response_body c0 c0 --- no_error_log [error] disabled in init phase under macOS --- skip_eval 4: $^O ne 'linux' === TEST 5: bug: sub incorrectly dropped the last character --- config location /re { content_by_lua_block { local s, n = ngx.re.sub("abcd", "(?<=c)", ".") ngx.say(s) ngx.say(n) } } --- request GET /re --- response_body abc.d 1 === TEST 6: bug: sub incorrectly dropped the last character(replace function) --- config location /re { content_by_lua_block { local function repl(m) return "[" .. m[0] .. "]" end local s, n = ngx.re.sub("abcd", "(?<=c)", repl) ngx.say(s) ngx.say(n) } } --- request GET /re --- response_body abc[]d 1 lua-resty-core-0.1.31/t/re-find.t000066400000000000000000000125401474236722600164420ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(1014); #master_process_enabled(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 5); #no_diff(); no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: matched, no submatch, no jit compile, no regex cache --- config location = /re { access_log off; content_by_lua_block { local from, to, err local find = ngx.re.find local s = "a" for i = 1, $TEST_NGINX_HOTLOOP * 20 do from, to, err = find(s, "a") end if err then ngx.log(ngx.ERR, "failed: ", err) return end if not from then ngx.log(ngx.ERR, "no match") return end ngx.say("from: ", from) ngx.say("to: ", to) ngx.say("matched: ", string.sub(s, from, to)) } } --- request GET /re --- response_body from: 1 to: 1 matched: a --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):5 loop\]/ --- no_error_log [error] bad argument type === TEST 2: matched, no submatch, jit compile, regex cache --- config location = /re { access_log off; content_by_lua_block { local from, to, err local find = ngx.re.find local s = "a" for i = 1, 200 do from, to, err = find(s, "a", "jo") end if err then ngx.log(ngx.ERR, "failed: ", err) return end if not from then ngx.log(ngx.ERR, "no match") return end ngx.say("from: ", from) ngx.say("to: ", to) ngx.say("matched: ", string.sub(s, from, to)) } } --- request GET /re --- response_body from: 1 to: 1 matched: a --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):5 loop\]/ --- no_error_log [error] NYI === TEST 3: not matched, no submatch, jit compile, regex cache --- config location = /re { access_log off; content_by_lua_block { local from, to, err local find = ngx.re.find local s = "b" for i = 1, 200 do from, to, err = find(s, "a", "jo") end if err then ngx.log(ngx.ERR, "failed: ", err) return end if not from then ngx.say("no match") return end ngx.say("from: ", from) ngx.say("to: ", to) ngx.say("matched: ", string.sub(s, from, to)) } } --- request GET /re --- response_body no match --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):5 loop\]/ --- no_error_log [error] NYI === TEST 4: nil submatch (2nd) --- config location /re { content_by_lua_block { local s = "hello, 1234" local from, to, err for i = 1, $TEST_NGINX_HOTLOOP * 20 do from, to, err = ngx.re.find(s, "([0-9])|(hello world)", "jo", nil, 2) end if from or to then ngx.say("from: ", from) ngx.say("to: ", to) ngx.say("matched: ", string.sub(s, from, to)) else if err then ngx.say("error: ", err) return end ngx.say("not matched!") end } } --- request GET /re --- response_body not matched! --- no_error_log [error] NYI --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ === TEST 5: nil submatch (1st) --- config location /re { content_by_lua_block { local s = "hello, 1234" local from, to, err for i = 1, 400 do from, to, err = ngx.re.find(s, "(hello world)|([0-9])", "jo", nil, 1) end if from or to then ngx.say("from: ", from) ngx.say("to: ", to) ngx.say("matched: ", string.sub(s, from, to)) else if err then ngx.say("error: ", err) return end ngx.say("not matched!") end } } --- request GET /re --- response_body not matched! --- no_error_log [error] NYI --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ === TEST 6: specify the group (2) --- config location /re { content_by_lua_block { local s = "hello, 1234" local from, to, err for i = 1, $TEST_NGINX_HOTLOOP * 20 do from, to, err = ngx.re.find(s, "([0-9])([0-9]+)", "jo", nil, 2) end if from then ngx.say("from: ", from) ngx.say("to: ", to) ngx.say("matched: ", string.sub(s, from, to)) else if err then ngx.say("error: ", err) end ngx.say("not matched!") end } } --- request GET /re --- response_body from: 9 to: 11 matched: 234 --- no_error_log [error] NYI --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ lua-resty-core-0.1.31/t/re-gmatch.t000066400000000000000000000255261474236722600167750ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(1014); #master_process_enabled(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 3 + 9); #no_diff(); no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: matched, no submatch, no jit compile, no regex cache --- config location = /re { content_by_lua_block { local m1, m2 local gmatch = ngx.re.gmatch for _ = 1, 200 do local iter = gmatch("hello, world", [[\w+]]) m1 = iter() m2 = iter() end ngx.say("matched: ", m1[0]) ngx.say("matched: ", m2[0]) } } --- request GET /re --- response_body matched: hello matched: world --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] === TEST 2: matched, no submatch, jit compile, regex cache --- config location = /re { content_by_lua_block { local m1, m2 local gmatch = ngx.re.gmatch for _ = 1, 200 do local iter = gmatch("hello, world", [[\w+]], "jo") m1 = iter() m2 = iter() end ngx.say("matched: ", m1[0]) ngx.say("matched: ", m2[0]) } } --- request GET /re --- response_body matched: hello matched: world --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] === TEST 3: not matched, no submatch, jit compile, regex cache --- config location = /re { content_by_lua_block { local m, err local gmatch = ngx.re.gmatch for _ = 1, 200 do local iter = gmatch("hello, world", "[abc]+", "jo") m, err = iter() if err then ngx.log(ngx.ERR, "failed: ", err) return end end if not m then ngx.say("no match") return end } } --- request GET /re --- response_body no match --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] === TEST 4: not matched, no submatch, no jit compile, no regex cache --- config location = /re { content_by_lua_block { local m, err local gmatch = ngx.re.gmatch for _ = 1, 200 do local iter = gmatch("hello, world", "[abc]+") m, err = iter() if err then ngx.log(ngx.ERR, "failed: ", err) return end end if not m then ngx.say("no match") return end } } --- request GET /re --- response_body no match --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] === TEST 5: submatches, matched, no regex cache --- config location = /re { content_by_lua_block { local m1, m2 local gmatch = ngx.re.gmatch for _ = 1, 200 do local iter = gmatch("hello, world", [[(\w)(\w+)]]) m1 = iter() m2 = iter() end ngx.say("matched: ", m1[0]) ngx.say("$1: ", m1[1]) ngx.say("$2: ", m1[2]) ngx.say("$3: ", m1[3]) ngx.say("matched: ", m2[0]) ngx.say("$1: ", m2[1]) ngx.say("$2: ", m2[2]) ngx.say("$3: ", m2[3]) } } --- request GET /re --- response_body matched: hello $1: h $2: ello $3: nil matched: world $1: w $2: orld $3: nil --- no_error_log [error] === TEST 6: submatches, matched, with regex cache --- config location = /re { content_by_lua_block { local m1, m2 local gmatch = ngx.re.gmatch for _ = 1, 200 do local iter = gmatch("hello, world", [[(\w)(\w+)]], "jo") m1 = iter() m2 = iter() end ngx.say("matched: ", m1[0]) ngx.say("$1: ", m1[1]) ngx.say("$2: ", m1[2]) ngx.say("$3: ", m1[3]) ngx.say("matched: ", m2[0]) ngx.say("$1: ", m2[1]) ngx.say("$2: ", m2[2]) ngx.say("$3: ", m2[3]) } } --- request GET /re --- response_body matched: hello $1: h $2: ello $3: nil matched: world $1: w $2: orld $3: nil --- error_log eval qr/\[TRACE\s+\d+\s+/ --- no_error_log [error] === TEST 7: named submatches --- config location = /re { content_by_lua_block { local m1, m2 local gmatch = ngx.re.gmatch for _ = 1, 200 do local iter = gmatch("hello,world", [[(?\w)(\w+)]], "jo") m1 = iter() m2 = iter() end ngx.say("matched: ", m1[0]) ngx.say("$1: ", m1[1]) ngx.say("$2: ", m1[2]) ngx.say("$first: ", m1.first) ngx.say("$second: ", m1.second) ngx.say("matched: ", m2[0]) ngx.say("$1: ", m2[1]) ngx.say("$2: ", m2[2]) ngx.say("$first: ", m2.first) ngx.say("$second: ", m2.second) } } --- request GET /re --- response_body matched: hello $1: h $2: ello $first: h $second: nil matched: world $1: w $2: orld $first: w $second: nil --- error_log eval qr/\[TRACE\s+\d+\s+/ --- no_error_log [error] === TEST 8: unmatched captures are false --- config location = /re { content_by_lua_block { local iter = ngx.re.gmatch( "hello! world!", [[(\w+)(, .+)?(!)]], "jo") if iter then while true do local m = iter() if not m then return end ngx.say(m[0]) ngx.say(m[1]) ngx.say(m[2]) ngx.say(m[3]) end end } } --- request GET /re --- response_body hello! hello false ! world! world false ! --- error_log eval qr/\[TRACE\s+\d+\s+/ --- no_error_log [error] === TEST 9: unmatched trailing captures are false --- config location = /re { content_by_lua_block { local iter = ngx.re.gmatch("hello", [[(\w+)(, .+)?(!)?]], "jo") if iter then while true do local m = iter() if not m then return end ngx.say(m[0]) ngx.say(m[1]) ngx.say(m[2]) ngx.say(m[3]) end end } } --- request GET /re --- response_body hello hello false false --- error_log eval qr/\[TRACE\s+\d+\s+/ --- no_error_log [error] === TEST 10: unmatched named captures are false --- config location = /re { content_by_lua_block { local iter = ngx.re.gmatch( "hello! world!", [[(?\w+)(?, .+)?(?!)]], "jo") if iter then while true do local m = iter() if not m then return end ngx.say(m[0]) ngx.say(m[1]) ngx.say(m[2]) ngx.say(m[3]) ngx.say(m.first) ngx.say(m.second) ngx.say(m.third) end end } } --- request GET /re --- response_body hello! hello false ! hello false ! world! world false ! world false ! --- error_log eval qr/\[TRACE\s+\d+\s+/ --- no_error_log [error] === TEST 11: subject is not a string type --- config location /re { content_by_lua_block { local iter = ngx.re.gmatch(120345, "[1-9]+", "jo") local m1 = iter() local m2 = iter() ngx.say(m1[0]) ngx.say(m2[0]) } } --- request GET /re --- response_body 12 345 --- no_error_log [error] attempt to get length of local 'subj' (a number value) === TEST 12: an exhausted gmatch iterator should return nil --- config location = /re { content_by_lua_block { local iter = ngx.re.gmatch("hello", [[\w+]]) local m = iter() ngx.say("matched: ", m[0]) ngx.say("matched: ", iter()) ngx.say("matched: ", iter()) } } --- request GET /re --- response_body matched: hello matched: nil matched: nil --- no_error_log [error] === TEST 13: an error-ed out gmatch iterator should return nil --- config location = /re { content_by_lua_block { local target = "你好" local regex = "你好" -- trigger a BADUTF8 error local iter = ngx.re.gmatch(string.sub(target, 1, 4), regex, "u") local m, err = iter() if err then ngx.say("error: ", err) local m = iter() if m then ngx.say("matched: ", m[0]) else ngx.say("not matched") end return end if m then ngx.say("matched: ", m[0]) else ngx.say("not matched") end } } --- request GET /re --- response_body eval # PCRE2_ERROR_UTF8_ERR2 (-4) # PCRE_ERROR_BADUTF8 (-10) $Test::Nginx::Util::PcreVersion == 2 ? "error: pcre_exec\(\) failed: -4\nnot matched\n" : "error: pcre_exec\(\) failed: -10\nnot matched\n" --- no_error_log [error] === TEST 14: each gmatch iterator is separate --- config location = /re { content_by_lua_block { local gmatch = ngx.re.gmatch local iter1 = gmatch("98", [[\d]]) local iter2 = gmatch("12", [[\d]]) local m1 = iter1() local m2 = iter2() ngx.say("matched iter1 (1/2): ", m1[0]) ngx.say("matched iter2 (1/2): ", m2[0]) m1 = iter1() m2 = iter2() ngx.say("matched iter1 (2/2): ", m1[0]) ngx.say("matched iter2 (2/2): ", m2[0]) } } --- request GET /re --- response_body matched iter1 (1/2): 9 matched iter2 (1/2): 1 matched iter1 (2/2): 8 matched iter2 (2/2): 2 --- no_error_log [error] === TEST 15: gmatch (empty matched string) --- config location /re { content_by_lua_block { for m in ngx.re.gmatch("hello", "a|") do if m then ngx.say("matched: [", m[0], "]") else ngx.say("not matched: ", m) end end } } --- request GET /re --- response_body matched: [] matched: [] matched: [] matched: [] matched: [] matched: [] lua-resty-core-0.1.31/t/re-match.t000066400000000000000000000300041474236722600166110ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(1014); #master_process_enabled(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 5 + 1); #no_diff(); no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: matched, no submatch, no jit compile, no regex cache --- config location = /re { access_log off; content_by_lua_block { local m, err local match = ngx.re.match for i = 1, 400 do m, err = match("a", "a") end if err then ngx.log(ngx.ERR, "failed: ", err) return end if not m then ngx.log(ngx.ERR, "no match") return end ngx.say("matched: ", m[0]) ngx.say("$1: ", m[1]) -- ngx.say("$2: ", m[2]) -- ngx.say("$3: ", m[3]) -- collectgarbage() } } --- request GET /re --- response_body matched: a $1: nil --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] bad argument type === TEST 2: matched, no submatch, jit compile, regex cache --- config location = /re { access_log off; content_by_lua_block { local m, err local match = ngx.re.match for i = 1, 400 do m, err = match("a", "a", "jo") end if err then ngx.log(ngx.ERR, "failed: ", err) return end if not m then ngx.log(ngx.ERR, "no match") return end ngx.say("matched: ", m[0]) ngx.say("$1: ", m[1]) -- collectgarbage() } } --- request GET /re --- response_body matched: a $1: nil --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] NYI === TEST 3: not matched, no submatch, jit compile, regex cache --- config location = /re { access_log off; content_by_lua_block { local m, err local match = ngx.re.match for i = 1, 200 do m, err = match("b", "a", "jo") end if err then ngx.log(ngx.ERR, "failed: ", err) return end if not m then ngx.say("no match") return end ngx.say("matched: ", m[0]) ngx.say("$1: ", m[1]) -- collectgarbage() } } --- request GET /re --- response_body no match --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] === TEST 4: not matched, no submatch, no jit compile, no regex cache --- config location = /re { access_log off; content_by_lua_block { local m, err local match = ngx.re.match for i = 1, 100 do m, err = match("b", "a") end if err then ngx.log(ngx.ERR, "failed: ", err) return end if not m then ngx.say("no match") return end ngx.say("matched: ", m[0]) ngx.say("$1: ", m[1]) -- collectgarbage() } } --- request GET /re --- response_body no match --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] bad argument type === TEST 5: submatches, matched, no regex cache --- config location = /re { access_log off; content_by_lua_block { local m, err local match = ngx.re.match for i = 1, 100 do m, err = match("hello, 1234", [[(\d)(\d+)]]) end if err then ngx.log(ngx.ERR, "failed: ", err) return end if not m then ngx.log(ngx.ERR, "no match") return end ngx.say("matched: ", m[0]) ngx.say("$1: ", m[1]) ngx.say("$2: ", m[2]) ngx.say("$3: ", m[3]) -- collectgarbage() } } --- request GET /re --- response_body matched: 1234 $1: 1 $2: 234 $3: nil --- no_error_log [error] bad argument type NYI === TEST 6: submatches, matched, with regex cache --- config location = /re { access_log off; content_by_lua_block { local m, err local match = ngx.re.match for i = 1, 100 do m, err = match("hello, 1234", [[(\d)(\d+)]], "jo") end if err then ngx.log(ngx.ERR, "failed: ", err) return end if not m then ngx.log(ngx.ERR, "no match") return end ngx.say("matched: ", m[0]) ngx.say("$1: ", m[1]) ngx.say("$2: ", m[2]) ngx.say("$3: ", m[3]) -- ngx.say(table.maxn(m)) -- collectgarbage() } } --- request GET /re --- response_body matched: 1234 $1: 1 $2: 234 $3: nil --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] bad argument type NYI === TEST 7: named subpatterns w/ extraction (matched) --- config location /re { content_by_lua_block { local m, err local match = ngx.re.match for i = 1, 100 do m, err = match("hello, 1234", "(?[a-z]+), [0-9]+", "jo") end if m then ngx.say(m[0]) ngx.say(m[1]) ngx.say(m.first) ngx.say(m.second) else if err then ngx.say("error: ", err) return end ngx.say("not matched!") end } } --- request GET /re --- response_body hello, 1234 hello hello nil --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] bad argument type NYI === TEST 8: named subpatterns w/ extraction (use of duplicate names in non-duplicate mode) --- config location /re { content_by_lua_block { local m, err local match = ngx.re.match for i = 1, 200 do m, err = match("hello, 1234", "(?[a-z])(?[a-z]+), [0-9]+", "jo") end if m then ngx.say(m[0]) ngx.say(m[1]) ngx.say(m.first) ngx.say(m.second) else if err then ngx.say("error: ", err) return end ngx.say("not matched!") end } } --- request GET /re --- response_body eval $Test::Nginx::Util::PcreVersion == 2 ? "error: pcre2_compile\(\) failed: two named subpatterns have the same name \(PCRE2_DUPNAMES not set\) in \"\(\?[a-z])\(\?[a-z]+\), [0-9]+\" at \"[a-z]+\), [0-9]+\"\n" : "error: pcre_compile\(\) failed: two named subpatterns have the same name in \"\(\?[a-z])\(\?[a-z]+\), [0-9]+\" at \">[a-z]+\), [0-9]+\"\n" --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] bad argument type NYI === TEST 9: named subpatterns w/ extraction (use of duplicate names in duplicate mode) --- config location /re { content_by_lua_block { local m, err local match = ngx.re.match for i = 1, 100 do m, err = match("hello, 1234", "(?[a-z])(?[a-z]+), [0-9]+", "joD") m, err = match("hello, 1234", "(?[a-z])(?[a-z]+), [0-9]+", "joD") m, err = match("hello, 1234", "(?[a-z])(?[a-z]+), [0-9]+", "joD") m, err = match("hello, 1234", "(?[a-z])(?[a-z]+), [0-9]+", "joD") m, err = match("hello, 1234", "(?[a-z])(?[a-z]+), [0-9]+", "joD") end if m then ngx.say(m[0]) ngx.say(m[1]) ngx.say(m[2]) ngx.say(table.concat(m.first, "|")) ngx.say(m.second) else if err then ngx.say("error: ", err) return end ngx.say("not matched!") end } } --- request GET /re --- response_body_like hello, 1234 h ello h|ello nil --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] bad argument type NYI === TEST 10: captures input table in ngx.re.match --- config location /re { content_by_lua_block { local new_tab = require "table.new" local clear_tab = require "table.clear" local m local res = new_tab(5, 0) res[5] = "hello" for i = 1, 100 do m = ngx.re.match("hello, 1234", "([0-9])([0-9])([0-9])([0-9])", "jo", nil, res) end if m then ngx.say(m[0]) ngx.say(m[1]) ngx.say(m[2]) ngx.say(m[3]) ngx.say(m[4]) ngx.say(m[5]) else ngx.say("not matched!") end } } --- request GET /re --- response_body 1234 1 2 3 4 hello --- no_error_log [error] NYI --- error_log eval qr/\[TRACE\s+\d+\s+/ === TEST 11: unmatched captures are false --- config location /re { content_by_lua_block { local m = ngx.re.match("hello!", "(hello)(, .+)?(!)", "jo") if m then ngx.say(m[0]) ngx.say(m[1]) ngx.say(m[2]) ngx.say(m[3]) else ngx.say("not matched!") end } } --- request GET /re --- response_body hello! hello false ! --- no_error_log [error] NYI --- error_log eval qr/\[TRACE\s+\d+\s+/ === TEST 12: unmatched trailing captures are false --- config location /re { content_by_lua_block { local m = ngx.re.match("hello", "(hello)(, .+)?(!)?", "jo") if m then ngx.say(m[0]) ngx.say(m[1]) ngx.say(m[2]) ngx.say(m[3]) else ngx.say("not matched!") end } } --- request GET /re --- response_body hello hello false false --- no_error_log [error] NYI --- error_log eval qr/\[TRACE\s+\d+\s+/ === TEST 13: unmatched named captures are false --- config location /re { content_by_lua_block { local m = ngx.re.match("hello!", "(?hello)(?, .+)?(?!)", "jo") if m then ngx.say(m[0]) ngx.say(m[1]) ngx.say(m[2]) ngx.say(m[3]) ngx.say(m.first) ngx.say(m.second) ngx.say(m.third) else ngx.say("not matched!") end } } --- request GET /re --- response_body hello! hello false ! hello false ! --- no_error_log [error] NYI --- error_log eval qr/\[TRACE\s+\d+\s+/ === TEST 14: subject is not a string type --- config location /re { content_by_lua_block { local m = ngx.re.match(12345, [=[(\d+)]=], "jo") if m then ngx.say(m[0]) ngx.say(m[1]) else ngx.say("not matched") end } } --- request GET /re --- response_body 12345 12345 --- no_error_log [error] attempt to get length of local 'subj' (a number value) === TEST 15: subject is not a string type --- config location /re { content_by_lua_block { local m = ngx.re.match(12345, "123", "jo") if m then ngx.say(m[0]) else ngx.say("not matched") end } } --- request GET /re --- response_body 123 --- no_error_log [error] attempt to get length of local 'regex' (a number value) lua-resty-core-0.1.31/t/re-opt.t000066400000000000000000000154041474236722600163260ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(1014); #master_process_enabled(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * blocks() * 3; no_diff(); no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: default jit_stack_size too small --- config location /re { content_by_lua_block { -- regex is taken from https://github.com/JuliaLang/julia/issues/8278 local very_long_string = [[71.163.72.113 - - [30/Jul/2014:16:40:55 -0700] "GET emptymind.org/thevacantwall/wp-content/uploads/2013/02/DSC_006421.jpg HTTP/1.1" 200 492513 "http://images.search.yahoo.com/images/view;_ylt=AwrB8py9gdlTGEwADcSjzbkF;_ylu=X3oDMTI2cGZrZTA5BHNlYwNmcC1leHAEc2xrA2V4cARvaWQDNTA3NTRiMzYzY2E5OTEwNjBiMjc2YWJhMjkxMTEzY2MEZ3BvcwM0BGl0A2Jpbmc-?back=http%3A%2F%2Fus.yhs4.search.yahoo.com%2Fyhs%2Fsearch%3Fei%3DUTF-8%26p%3Dapartheid%2Bwall%2Bin%2Bpalestine%26type%3Dgrvydef%26param1%3D1%26param2%3Dsid%253Db01676f9c26355f014f8a9db87545d61%2526b%253DChrome%2526ip%253D71.163.72.113%2526p%253Dgroovorio%2526x%253DAC811262A746D3CD%2526dt%253DS940%2526f%253D7%2526a%253Dgrv_tuto1_14_30%26hsimp%3Dyhs-fullyhosted_003%26hspart%3Dironsource&w=588&h=387&imgurl=occupiedpalestine.files.wordpress.com%2F2012%2F08%2F5-peeking-through-the-wall.jpg%3Fw%3D588%26h%3D387&rurl=http%3A%2F%2Fwww.stopdebezetting.com%2Fwereldpers%2Fcompare-the-berlin-wall-vs-israel-s-apartheid-wall-in-palestine.html&size=49.0KB&name=...+%3Cb%3EApartheid+wall+in+Palestine%3C%2Fb%3E...+%7C+Or+you+go+peeking+through+the+%3Cb%3Ewall%3C%2Fb%3E&p=apartheid+wall+in+palestine&oid=50754b363ca991060b276aba291113cc&fr2=&fr=&tt=...+%3Cb%3EApartheid+wall+in+Palestine%3C%2Fb%3E...+%7C+Or+you+go+peeking+through+the+%3Cb%3Ewall%3C%2Fb%3E&b=0&ni=21&no=4&ts=&tab=organic&sigr=13evdtqdq&sigb=19k7nsjvb&sigi=12o2la1db&sigt=12lia2m0j&sign=12lia2m0j&.crumb=.yUtKgFI6DE&hsimp=yhs-fullyhosted_003&hspart=ironsource" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36]] local very_complicated_regex = [[([\d\.]+) ([\w.-]+) ([\w.-]+) (\[.+\]) "([^"\r\n]*|[^"\r\n\[]*\[.+\][^"]+|[^"\r\n]+.[^"]+)" (\d{3}) (\d+|-) ("(?:[^"]|\")+)"? ("(?:[^"]|\")+)"?]] local from, to, err = ngx.re.find(very_long_string, very_complicated_regex, "jo") if from or to then ngx.say("from: ", from) ngx.say("to: ", to) else if err then ngx.say("error: ", err) return end ngx.say("not matched!") end } } --- request GET /re --- response_body eval # PCRE2_ERROR_JIT_STACKLIMIT (-46) # PCRE_ERROR_JIT_STACKLIMIT (-27) $Test::Nginx::Util::PcreVersion == 2 ? "error: pcre_exec\(\) failed: -46\n" : "error: pcre_exec\(\) failed: -27\n" --- no_error_log [error] --- timeout: 10 === TEST 2: increase jit_stack_size --- http_config eval qq{ lua_package_path '$t::TestCore::lua_package_path'; init_by_lua_block { $t::TestCore::init_by_lua_block local ngx_re = require "ngx.re" ngx_re.opt("jit_stack_size", 128 * 1024) } } --- config location /re { content_by_lua_block { -- regex is taken from https://github.com/JuliaLang/julia/issues/8278 local very_long_string = [[71.163.72.113 - - [30/Jul/2014:16:40:55 -0700] "GET emptymind.org/thevacantwall/wp-content/uploads/2013/02/DSC_006421.jpg HTTP/1.1" 200 492513 "http://images.search.yahoo.com/images/view;_ylt=AwrB8py9gdlTGEwADcSjzbkF;_ylu=X3oDMTI2cGZrZTA5BHNlYwNmcC1leHAEc2xrA2V4cARvaWQDNTA3NTRiMzYzY2E5OTEwNjBiMjc2YWJhMjkxMTEzY2MEZ3BvcwM0BGl0A2Jpbmc-?back=http%3A%2F%2Fus.yhs4.search.yahoo.com%2Fyhs%2Fsearch%3Fei%3DUTF-8%26p%3Dapartheid%2Bwall%2Bin%2Bpalestine%26type%3Dgrvydef%26param1%3D1%26param2%3Dsid%253Db01676f9c26355f014f8a9db87545d61%2526b%253DChrome%2526ip%253D71.163.72.113%2526p%253Dgroovorio%2526x%253DAC811262A746D3CD%2526dt%253DS940%2526f%253D7%2526a%253Dgrv_tuto1_14_30%26hsimp%3Dyhs-fullyhosted_003%26hspart%3Dironsource&w=588&h=387&imgurl=occupiedpalestine.files.wordpress.com%2F2012%2F08%2F5-peeking-through-the-wall.jpg%3Fw%3D588%26h%3D387&rurl=http%3A%2F%2Fwww.stopdebezetting.com%2Fwereldpers%2Fcompare-the-berlin-wall-vs-israel-s-apartheid-wall-in-palestine.html&size=49.0KB&name=...+%3Cb%3EApartheid+wall+in+Palestine%3C%2Fb%3E...+%7C+Or+you+go+peeking+through+the+%3Cb%3Ewall%3C%2Fb%3E&p=apartheid+wall+in+palestine&oid=50754b363ca991060b276aba291113cc&fr2=&fr=&tt=...+%3Cb%3EApartheid+wall+in+Palestine%3C%2Fb%3E...+%7C+Or+you+go+peeking+through+the+%3Cb%3Ewall%3C%2Fb%3E&b=0&ni=21&no=4&ts=&tab=organic&sigr=13evdtqdq&sigb=19k7nsjvb&sigi=12o2la1db&sigt=12lia2m0j&sign=12lia2m0j&.crumb=.yUtKgFI6DE&hsimp=yhs-fullyhosted_003&hspart=ironsource" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36]] local very_complicated_regex = [[([\d\.]+) ([\w.-]+) ([\w.-]+) (\[.+\]) "([^"\r\n]*|[^"\r\n\[]*\[.+\][^"]+|[^"\r\n]+.[^"]+)" (\d{3}) (\d+|-) ("(?:[^"]|\")+)"? ("(?:[^"]|\")+)"?]] local from, to, err = ngx.re.find(very_long_string, very_complicated_regex, "jo") if from or to then ngx.say("from: ", from) ngx.say("to: ", to) else if err then ngx.say("error: ", err) return end ngx.say("not matched!") end } } --- request GET /re --- response_body from: 1 to: 1563 --- no_error_log [error] --- timeout: 10 === TEST 3: jit_stack_size change disallowed once regex cache is populated --- config location /re { content_by_lua_block { local ngx_re = require "ngx.re" local status, err = pcall(ngx_re.opt, "jit_stack_size", 128 * 1024) if err then ngx.log(ngx.ERR, err) end local s = "hello, 1234" local from, to = ngx.re.find(s, "(hello world)|([0-9])", "jo") ngx.say("from: ", from) ngx.say("to: ", to) } } --- request GET /re --- response_body from: 8 to: 8 --- grep_error_log eval qr/changing jit stack size is not allowed when some regexs have already been compiled and cached/ --- grep_error_log_out eval ["", "changing jit stack size is not allowed when some regexs have already been compiled and cached\n"] --- timeout: 10 === TEST 4: passing unknown options to ngx_re.opt throws an error --- config location /re { content_by_lua_block { local ngx_re = require "ngx.re" local status, err = pcall(ngx_re.opt, "foo", 123) ngx.say(err) } } --- request GET /re --- response_body_like chomp unrecognized option name$ --- no_error_log [error] --- timeout: 10 lua-resty-core-0.1.31/t/re-split.t000066400000000000000000000567021474236722600166650ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(1014); #master_process_enabled(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * blocks() * 4 + (2 * repeat_each()); no_diff(); no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: split matches, no submatch, no jit compile, no regex cache --- config location = /re { content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("a,b,c,d", ",") if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end } } --- request GET /re --- response_body a b c d --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 2: split matches, no submatch, no jit compile, no regex cache --- config location = /re { content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("a;,b;,c;,d;e", ";,") if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end } } --- request GET /re --- response_body a b c d;e --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 3: split matches, no submatch, jit compile, regex cache --- config location = /re { content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("a,b,c,d", ",", "jo") if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end } } --- request GET /re --- response_body a b c d --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 4: split matches + submatch (matching) --- config location = /re { content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("a;,b;,c;,d,e", "(;),") if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end } } --- request GET /re --- response_body a ; b ; c ; d,e --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 5: split matches + submatch (not matching) --- config location = /re { content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("a,b,c,d,e", "(;)|,") if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end } } --- request GET /re --- response_body a b c d e --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 6: split matches + max limiter --- config location = /re { content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("a,b,c,d,e", ",", nil, nil, 3) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end } } --- request GET /re --- response_body a b c,d,e --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 7: split matches + submatch + max limiter --- config location = /re { content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("a,b,c,d,e", "(,)", nil, nil, 3) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end } } --- request GET /re --- response_body a , b , c,d,e --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 8: split matches + max limiter set to 0 --- config location = /re { content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("a,b,c,d,e", ",", nil, nil, 0) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end } } --- request GET /re --- response_body a b c d e --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 9: split matches + max limiter set to a negative value --- config location = /re { content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("a,b,c,d,e", ",", nil, nil, -1) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end } } --- request GET /re --- response_body a b c d e --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 10: split matches + max limiter set to 1 --- config location = /re { content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("a,b,c,d,e", ",", nil, nil, 1) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end } } --- request GET /re --- response_body a,b,c,d,e --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 11: split matches, provided res table --- config location = /re { content_by_lua_block { local ngx_re = require "ngx.re" local my_table = {} local res, err = ngx_re.split("a,b,c,d,e", ",", nil, nil, nil, my_table) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end } } --- request GET /re --- response_body a b c d e --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 12: split matches, provided res table (non-cleared) --- config location = /re { content_by_lua_block { local ngx_re = require "ngx.re" local my_table = {} for i = 1, 10 do my_table[i] = i.." hello world" end local res, err = ngx_re.split("a,b,c,d,e", ",", nil, nil, nil, my_table) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i in ipairs(my_table) do ngx.say(res[i]) end } } --- request GET /re --- response_body a b c d e --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 13: split matches, provided res table + max limiter --- config location = /re { content_by_lua_block { local ngx_re = require "ngx.re" local my_table = {"hello, world"} local res, err = ngx_re.split("a,b,c,d,e", ",", nil, nil, 3, my_table) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #my_table do ngx.say(res[i]) end } } --- request GET /re --- response_body a b c,d,e --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 14: split matches, provided res table (non-cleared) + max limiter --- config location = /re { content_by_lua_block { local ngx_re = require "ngx.re" local my_table = {} for i = 1, 10 do my_table[i] = i.." hello world" end local res, err = ngx_re.split("a,b,c,d,e", ",", nil, nil, 3, my_table) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i in ipairs(my_table) do ngx.say(res[i]) end } } --- request GET /re --- response_body a b c,d,e --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 15: split matches, provided res table + max limiter + sub-match capturing group --- config location = /re { content_by_lua_block { local ngx_re = require "ngx.re" local my_table = {"hello, world"} local res, err = ngx_re.split("a,b,c,d,e", "(,)", nil, nil, 3, my_table) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #my_table do ngx.say(res[i]) end } } --- request GET /re --- response_body a , b , c,d,e --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 16: split matches, ctx arg --- config location = /re { content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("a,b,c,d,e", ",", nil, { pos = 5 }) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end } } --- request GET /re --- response_body c d e --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 17: split matches, trailing subjects --- config location /re { content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split(",a,b,c,d,", ",") if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do if res[i] == "" then ngx.say("_blank_") else ngx.say(res[i]) end end } } --- request GET /re --- response_body _blank_ a b c d --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] attempt to get length of local 'regex' (a number value) === TEST 18: split matches, real use-case --- config location /re { content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("abcd,erfg,ghij;hello world;aaa", ",|;") if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end } } --- request GET /re --- response_body abcd erfg ghij hello world aaa --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 19: split no matches --- config location /re { content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("abcd", ",") if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end } } --- request GET /re --- response_body abcd --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 20: subject is not a string type --- config location /re { content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split(1234512345, "23", "jo") if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end } } --- request GET /re --- response_body 1 451 45 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] attempt to get length of local 'subj' (a number value) === TEST 21: split matches, pos is larger than subject length --- config location = /re { content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("a,b,c,d,e", ",", nil, { pos = 10 }) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end ngx.say("len: ", #res) } } --- request GET /re --- response_body len: 0 --- no_error_log [error] [TRACE === TEST 22: regex is "" --- config location /re { content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("12345", "", "jo") if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end ngx.say("len: ", #res) } } --- request GET /re --- response_body 1 2 3 4 5 len: 5 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 23: regex is "" with max --- config location /re { content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("12345", "", "jo", nil, 3) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end ngx.say("len: ", #res) } } --- request GET /re --- response_body 1 2 345 len: 3 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 24: regex is "" with pos --- config location /re { content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("12345", "", "jo", { pos = 2 }) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end ngx.say("len: ", #res) } } --- request GET /re --- response_body 2 3 4 5 len: 4 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 25: regex is "" with pos larger than subject length --- config location /re { content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("12345", "", "jo", { pos = 10 }) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end ngx.say("len: ", #res) } } --- request GET /re --- response_body len: 0 --- no_error_log [error] [TRACE === TEST 26: regex is "" with pos & max --- config location /re { content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("12345", "", "jo", { pos = 2 }, 2) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end ngx.say("len: ", #res) } } --- request GET /re --- response_body 2 345 len: 2 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 27: no match separator (github issue #104) --- config location /re { content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("abcd", "|") if err then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say(table.concat(res, ":")) ngx.say("len: ", #res) } } --- request GET /re --- response_body a:b:c:d len: 4 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 28: no match separator (github issue #104) & max --- config location /re { content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("abcd", "|", nil, nil, 2) if err then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say(table.concat(res, ":")) ngx.say("len: ", #res) } } --- request GET /re --- response_body a:bcd len: 2 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 29: no match separator bis (github issue #104) --- config location /re { content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("abcd", "()") if err then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say(table.concat(res, ":")) ngx.say("len: ", #res) } } --- request GET /re --- response_body a::b::c::d len: 7 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 30: behavior with /^/ differs from Perl's split --- config location /re { content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("ab\ncd\nef", "^") if err then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say(table.concat(res, ":")) ngx.say("len: ", #res) } } --- request GET /re --- response_body ab cd ef len: 1 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 31: behavior with /^/m --- config location /re { content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("ab\ncd\nef", "^", "m") if err then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say(table.concat(res, ":")) ngx.say("len: ", #res) } } --- request GET /re --- response_body ab :cd :ef len: 3 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 32: behavior with /^()/m (capture) --- config location /re { content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("ab\ncd\nef", "^()", "m") if err then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say(table.concat(res, ":")) ngx.say("len: ", #res) } } --- request GET /re --- response_body ab ::cd ::ef len: 5 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 33: behavior with /^/m & max --- config location /re { content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("ab\ncd\nef", "^", "m", nil, 2) if err then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say(table.concat(res, ":")) ngx.say("len: ", #res) } } --- request GET /re --- response_body ab :cd ef len: 2 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 34: behavior with /^\d/m --- config location /re { content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("ab\n1cdefg\n2hij", "^\\d", "m") if err then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say(table.concat(res, ":")) ngx.say("len: ", #res) } } --- request GET /re --- response_body ab :cdefg :hij len: 3 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 35: behavior with /^(\d)/m (capture) --- config location /re { content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("ab\n1cdefg\n2hij", "^(\\d)", "m") if err then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say(table.concat(res, ":")) ngx.say("len: ", #res) } } --- request GET /re --- response_body ab :1:cdefg :2:hij len: 5 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 36: split by unit separator 1/2 (GH issue lua-nginx-module #1217) --- config location /re { content_by_lua_block { local ngx_re = require "ngx.re" local subjs = { "1\x1fT\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f15", "1\x1fT\x1fT\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f15", "1\x1fT\x1fT\x1fT\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f15", } for _, subj in ipairs(subjs) do local col_list = ngx_re.split(subj, "\\x1f") ngx.say(#col_list, " ", table.concat(col_list, "|")) end } } --- request GET /re --- response_body 15 1|T|||||||||||||15 15 1|T|T||||||||||||15 15 1|T|T|T|||||||||||15 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 37: split by unit separator 2/2 (with ctx.pos) --- config location /re { content_by_lua_block { local ngx_re = require "ngx.re" local subjs = { "1\x1fT\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f15", "1\x1fT\x1fT\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f15", "1\x1fT\x1fT\x1fT\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f15", } for _, subj in ipairs(subjs) do local col_list = ngx_re.split(subj, "\\x1f", nil, { pos = 6 }) ngx.say(#col_list, " ", table.concat(col_list, "|")) end } } --- request GET /re --- response_body 12 |||||||||||15 13 ||||||||||||15 13 |T|||||||||||15 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 38: remaining characters are matched by regex (without max) --- config location /re { content_by_lua_block { local ngx_re = require "ngx.re" local subj = "a,b,cd,,," local res, err = ngx_re.split(subj, ",") if err then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say(#res, " ", table.concat(res, "|")) } } --- request GET /re --- response_body 3 a|b|cd --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 39: remaining characters are matched by regex (with max) --- config location /re { content_by_lua_block { local ngx_re = require "ngx.re" local subj = "a,b,cd,,," for max = 1, 7 do local res, err = ngx_re.split(subj, ",", nil, nil, max) if err then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say(#res, " ", table.concat(res, "|")) end } } --- request GET /re --- response_body 1 a,b,cd,,, 2 a|b,cd,,, 3 a|b|cd,,, 4 a|b|cd|,, 5 a|b|cd||, 6 a|b|cd||| 6 a|b|cd||| --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 40: cannot load ngx.re module when lacking PCRE support --- config location /re { content_by_lua_block { package.loaded["ngx.re"] = nil local core_regex = require "resty.core.regex" core_regex.no_pcre = true local pok, perr = pcall(require, "ngx.re") if not pok then ngx.say(perr) end } } --- request GET /re --- response_body no support for 'ngx.re' module: OpenResty was compiled without PCRE support --- no_error_log [error] [crit] lua-resty-core-0.1.31/t/re-sub.t000066400000000000000000000162011474236722600163110ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(1014); #master_process_enabled(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 4 + 9); #no_diff(); no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: sub, no submatch, no jit compile, regex cache --- config location = /re { access_log off; content_by_lua_block { local m, err local sub = ngx.re.sub for i = 1, 300 do s, n, err = sub("abcbd", "b", "B", "jo") end if not s then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say("s: ", s) ngx.say("n: ", n) } } --- request GET /re --- response_body s: aBcbd n: 1 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] bad argument type NYI === TEST 2: sub, no submatch, no jit compile, no regex cache --- config location = /re { access_log off; content_by_lua_block { local m, err local sub = ngx.re.sub for i = 1, 300 do s, n, err = sub("abcbd", "b", "B") end if not s then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say("s: ", s) ngx.say("n: ", n) } } --- request GET /re --- response_body s: aBcbd n: 1 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] bad argument type === TEST 3: func + submatches --- config location = /re { access_log off; content_by_lua_block { local m, err local function f(m) return "[" .. m[0] .. "(" .. m[1] .. ")]" end local sub = ngx.re.sub for i = 1, 300 do s, n, err = sub("abcbd", "b(c)", f, "jo") end if not s then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say("s: ", s) ngx.say("n: ", n) } } --- request GET /re --- response_body s: a[bc(c)]bd n: 1 --- no_error_log eval [ "[error]", "bad argument type", qr/NYI (?!bytecode 51 at)/, ] === TEST 4: replace template + submatches --- config location = /re { access_log off; content_by_lua_block { local m, err local sub = ngx.re.sub for i = 1, 300 do s, n, err = sub("abcbd", "b(c)", "[$0($1)]", "jo") end if not s then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say("s: ", s) ngx.say("n: ", n) } } --- request GET /re --- response_body s: a[bc(c)]bd n: 1 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] bad argument type NYI === TEST 5: replace template + submatches (exceeding buffers) --- config location = /re { access_log off; content_by_lua_block { local m, err local gsub = ngx.re.gsub local subj = string.rep("bcbd", 2048) for i = 1, 10 do s, n, err = gsub(subj, "b(c)", "[$0($1)]", "jo") end if not s then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say("s: ", s) ngx.say("n: ", n) } } --- request GET /re --- response_body eval "s: " . ("[bc(c)]bd" x 2048) . "\nn: 2048\n" --- no_error_log [error] bad argument type === TEST 6: ngx.re.gsub: use of ngx.req.get_headers in the user callback --- config location = /t { content_by_lua_block { local data = [[ INNER INNER ]] -- ngx.say(data) local res = ngx.re.gsub(data, "INNER", function(inner_matches) local header = ngx.req.get_headers()["Host"] -- local header = ngx.var["http_HEADER"] return "INNER_REPLACED" end, "s") ngx.print(res) } } --- request GET /t --- response_body INNER_REPLACED INNER_REPLACED --- no_error_log [error] bad argument type NYI === TEST 7: ngx.re.gsub: use of ngx.var in the user callback --- config location = /t { content_by_lua_block { local data = [[ INNER INNER ]] -- ngx.say(data) local res = ngx.re.gsub(data, "INNER", function(inner_matches) -- local header = ngx.req.get_headers()["Host"] local header = ngx.var["http_HEADER"] return "INNER_REPLACED" end, "s") ngx.print(res) } } --- request GET /t --- response_body INNER_REPLACED INNER_REPLACED --- no_error_log [error] bad argument type NYI === TEST 8: ngx.re.gsub: recursive calling (github openresty/lua-nginx-module#445) --- config location = /t { content_by_lua_block { function test() local data = [[ OUTER {FIRST} ]] local p1 = "(OUTER)(.+)" local p2 = "{([A-Z]+)}" ngx.print(data) local res = ngx.re.gsub(data, p1, function(m) -- ngx.say("pre: m[1]: [", m[1], "]") -- ngx.say("pre: m[2]: [", m[2], "]") local res = ngx.re.gsub(m[2], p2, function(_) return "REPLACED" end, "") -- ngx.say("post: m[1]: [", m[1], "]") -- ngx.say("post m[2]: [", m[2], "]") return m[1] .. res end, "") ngx.print(res) end test() } } --- request GET /t --- response_body OUTER {FIRST} OUTER REPLACED --- no_error_log [error] bad argument type NYI === TEST 9: string replace subj is not a string type --- config location /re { content_by_lua_block { local newstr, n, err = ngx.re.sub(1234, "([0-9])[0-9]", 5, "jo") ngx.say(newstr) } } --- request GET /re --- response_body 534 --- no_error_log [error] attempt to get length of local 'subj' (a number value) === TEST 10: func replace return is not a string type (ngx.re.sub) --- config location /re { content_by_lua_block { local lookup = function(m) -- note we are returning a number type here return 5 end local newstr, n, err = ngx.re.sub("hello, 1234", "([0-9])[0-9]", lookup, "jo") ngx.say(newstr) } } --- request GET /re --- response_body hello, 534 --- no_error_log [error] attempt to get length of local 'bit' (a number value) === TEST 11: func replace return is not a string type (ngx.re.gsub) --- config location /re { content_by_lua_block { local lookup = function(m) -- note we are returning a number type here return 5 end local newstr, n, err = ngx.re.gsub("hello, 1234", "([0-9])[0-9]", lookup, "jo") ngx.say(newstr) } } --- request GET /re --- response_body hello, 55 --- no_error_log [error] attempt to get length of local 'bit' (a number value) lua-resty-core-0.1.31/t/request.t000066400000000000000000000340661474236722600166150ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(1014); #master_process_enabled(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 4 + 19); #no_diff(); #no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: ngx.req.get_headers --- config location = /t { set $foo hello; content_by_lua_block { local ffi = require "ffi" local headers for i = 1, 500 do headers = ngx.req.get_headers() end local keys = {} for k, _ in pairs(headers) do keys[#keys + 1] = k end table.sort(keys) for _, k in ipairs(keys) do ngx.say(k, ": ", headers[k]) end } } --- request GET /t --- response_body bar: bar baz: baz connection: close foo: foo host: localhost --- more_headers Foo: foo Bar: bar Baz: baz --- wait: 0.2 --- error_log eval qr/\[TRACE\s+\d+ .*? -> \d+\]/ --- no_error_log eval [ "[error]", qr/ -- NYI: (?!return to lower frame)/, ] === TEST 2: ngx.req.get_headers (raw) --- config location = /t { set $foo hello; content_by_lua_block { local ffi = require "ffi" local headers for i = 1, 500 do headers = ngx.req.get_headers(100, true) end local keys = {} for k, _ in pairs(headers) do keys[#keys + 1] = k end table.sort(keys) for _, k in ipairs(keys) do ngx.say(k, ": ", headers[k]) end } } --- request GET /t --- response_body Bar: bar Baz: baz Connection: close Foo: foo Host: localhost --- more_headers Foo: foo Bar: bar Baz: baz --- wait: 0.2 --- error_log eval qr/\[TRACE\s+\d+ .*? -> \d+\]/ --- no_error_log [error] -- NYI: === TEST 3: ngx.req.get_headers (count is 2) --- config location = /t { set $foo hello; content_by_lua_block { local ffi = require "ffi" local headers for i = 1, 500 do headers = ngx.req.get_headers(2, true) end local keys = {} for k, _ in pairs(headers) do keys[#keys + 1] = k end table.sort(keys) for _, k in ipairs(keys) do ngx.say(k, ": ", headers[k]) end } } --- request GET /t --- response_body Connection: close Host: localhost --- more_headers Foo: foo Bar: bar Baz: baz --- wait: 0.2 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] -- NYI: === TEST 4: ngx.req.get_headers (metatable) --- http_config eval " $::HttpConfig underscores_in_headers on; " --- config location = /t { set $foo hello; content_by_lua_block { local ffi = require "ffi" local headers, header for i = 1, 500 do headers = ngx.req.get_headers() header = headers["foo_BAR"] end ngx.say("foo_BAR: ", header) local keys = {} for k, _ in pairs(headers) do keys[#keys + 1] = k end table.sort(keys) for _, k in ipairs(keys) do ngx.say(k, ": ", headers[k]) end ngx.say("X_Bar_Header: ", headers["X_Bar_Header"]) ngx.say("x_Bar_Header: ", headers["x_Bar_Header"]) ngx.say("x_bar_header: ", headers["x_bar_header"]) } } --- request GET /t --- response_body foo_BAR: foo baz: baz connection: close foo-bar: foo host: localhost x_bar_header: bar X_Bar_Header: bar x_Bar_Header: bar x_bar_header: bar --- more_headers Foo-Bar: foo Baz: baz X_Bar_Header: bar --- wait: 0.2 --- error_log eval qr/\[TRACE\s+\d+ .*? -> \d+\]/ --- no_error_log eval ["[error]", qr/ -- NYI: (?!return to lower frame at)(?!C function 0x[0-9a-f]+ at content_by_lua\(nginx.conf:\d+\):15)/, ] === TEST 5: ngx.req.get_uri_args --- config location = /t { set $foo hello; content_by_lua_block { local ffi = require "ffi" local args for i = 1, 500 do args = ngx.req.get_uri_args() end if type(args) ~= "table" then ngx.say("bad args type found: ", args) return end local keys = {} for k, _ in pairs(args) do keys[#keys + 1] = k end table.sort(keys) for _, k in ipairs(keys) do local v = args[k] if type(v) == "table" then ngx.say(k, ": ", table.concat(v, ", ")) else ngx.say(k, ": ", v) end end } } --- request GET /t?a=3%200&foo%20bar=&a=hello&blah --- response_body a: 3 0, hello blah: true foo bar: --- error_log eval qr/\[TRACE\s+\d+ .*? -> \d+\]/ --- no_error_log [error] -- NYI: --- wait: 0.2 === TEST 6: ngx.req.get_uri_args (empty) --- config location = /t { set $foo hello; content_by_lua_block { local ffi = require "ffi" local args for i = 1, 500 do args = ngx.req.get_uri_args() end if type(args) ~= "table" then ngx.say("bad args type found: ", args) return end local keys = {} for k, _ in pairs(args) do keys[#keys + 1] = k end table.sort(keys) for _, k in ipairs(keys) do local v = args[k] if type(v) == "table" then ngx.say(k, ": ", table.concat(v, ", ")) else ngx.say(k, ": ", v) end end } } --- request GET /t? --- response_body --- wait: 0.2 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] -- NYI: === TEST 7: ngx.req.start_time() --- config location = /t { access_log off; content_by_lua_block { local t for i = 1, 500 do t = ngx.req.start_time() end ngx.sleep(0.10) local elapsed = ngx.now() - t ngx.say(t > 1399867351) ngx.say(">= 0.099: ", elapsed >= 0.099) ngx.say("< 0.11: ", elapsed < 0.11) -- ngx.say(t, " ", elapsed) } } --- request GET /t --- response_body true >= 0.099: true < 0.11: true --- wait: 0.2 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] bad argument type stitch === TEST 8: ngx.req.get_method (GET) --- config location = /t { access_log off; content_by_lua_block { local t for i = 1, 500 do t = ngx.req.get_method() end ngx.say("method: ", t) } } --- request GET /t --- response_body method: GET --- wait: 0.2 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] bad argument type stitch === TEST 9: ngx.req.get_method (OPTIONS) --- config location = /t { access_log off; content_by_lua_block { local t for i = 1, 500 do t = ngx.req.get_method() end ngx.say("method: ", t) } } --- request OPTIONS /t --- response_body method: OPTIONS --- wait: 0.2 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] bad argument type stitch === TEST 10: ngx.req.get_method (POST) --- config location = /t { access_log off; content_by_lua_block { local t for i = 1, 500 do t = ngx.req.get_method() end ngx.say("method: ", t) ngx.req.discard_body() } } --- request POST /t hello --- response_body method: POST --- wait: 0.2 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] bad argument type stitch === TEST 11: ngx.req.get_method (unknown method) --- config location = /t { access_log off; content_by_lua_block { local t for i = 1, 500 do t = ngx.req.get_method() end ngx.say("method: ", t) ngx.req.discard_body() } } --- request BLAH /t hello --- response_body method: BLAH --- wait: 0.2 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] bad argument type stitch === TEST 12: ngx.req.get_method (CONNECT) --- config location = /t { access_log off; content_by_lua_block { local t for i = 1, 500 do t = ngx.req.get_method() end ngx.say("method: ", t) ngx.req.discard_body() } } --- request CONNECT /t hello --- response_body method: CONNECT --- wait: 0.2 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] bad argument type stitch --- skip_nginx 6: >= 1.21.1 === TEST 13: ngx.req.set_method (GET -> PUT) --- config location = /t { access_log off; content_by_lua_block { local t for i = 1, 500 do ngx.req.set_method(ngx.HTTP_PUT) end ngx.say("method: ", ngx.req.get_method()) } } --- request GET /t --- response_body method: PUT --- wait: 0.2 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] bad argument type stitch === TEST 14: ngx.req.set_header (single number value) --- config location = /t { access_log off; content_by_lua_block { local t for i = 1, 500 do ngx.req.set_header("foo", i) end ngx.say("header foo: ", ngx.var.http_foo) } } --- request GET /t --- response_body header foo: 500 --- wait: 0.2 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] bad argument type stitch === TEST 15: ngx.req.set_header (nil value) --- config location = /t { access_log off; content_by_lua_block { local t for i = 1, 500 do ngx.req.set_header("foo", nil) end ngx.say("header foo: ", type(ngx.var.http_foo)) } } --- request GET /t --- response_body header foo: nil --- wait: 0.2 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] bad argument type stitch === TEST 16: ngx.req.clear_header --- config location = /t { access_log off; content_by_lua_block { ngx.req.set_header("foo", "hello") local t for i = 1, 500 do t = ngx.req.clear_header("foo") end ngx.say("header foo: ", type(ngx.var.http_foo)) } } --- request GET /t --- response_body header foo: nil --- wait: 0.2 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] bad argument type stitch === TEST 17: ngx.req.set_header (multiple values) --- config location = /t { content_by_lua_block { ngx.req.set_header("Foo", { "baz", 123 }) ngx.say("Foo: ", table.concat(ngx.req.get_headers()["Foo"], ", ")) } } --- request GET /t --- more_headers Foo: bar --- response_body Foo: baz, 123 --- no_error_log [error] === TEST 18: ngx.req.get_header (metatable is nil) --- config location = /t { content_by_lua_block { local headers = ngx.req.get_headers() ngx.say(string.format("%s,%s",type(headers), type(getmetatable(headers)))) } } --- raw_request eval "GET /t \r\n" --- http09 --- response_body table,table === TEST 19: CONNECT method is considered invalid since nginx 1.21.1 --- config location = /t { access_log off; content_by_lua_block { local t for i = 1, 500 do t = ngx.req.get_method() end ngx.say("method: ", t) ngx.req.discard_body() } } --- request CONNECT /t hello --- error_code: 405 --- no_error_log [error] --- skip_nginx 2: < 1.21.1 === TEST 20: get_uri_args allows to reuse table --- config location = /t { set $foo hello; content_by_lua_block { local base = require "resty.core.base" local args = base.new_tab(0, 3) local id = tostring(args) for i = 1, 5 do base.clear_tab(args) args = ngx.req.get_uri_args(-1, args) assert(tostring(args) == id) end local keys = {} for k, _ in pairs(args) do keys[#keys + 1] = k end table.sort(keys) for _, k in ipairs(keys) do local v = args[k] if type(v) == "table" then ngx.say(k, ": ", table.concat(v, ", ")) else ngx.say(k, ": ", v) end end } } --- request GET /t?a=3%200&foo%20bar=&a=hello&blah --- response_body a: 3 0, hello blah: true foo bar: --- no_error_log [error] === TEST 21: get_uri_args allows to reuse table (empty) --- config location = /t { set $foo hello; content_by_lua_block { local base = require "resty.core.base" local args = base.new_tab(0, 3) local id = tostring(args) for i = 1, 5 do args = ngx.req.get_uri_args(-1, args) assert(tostring(args) == id) end local n_key = 0 for k, _ in pairs(args) do n_key = n_key + 1 end ngx.say(n_key) } } --- request GET /t --- response_body 0 --- no_error_log [error] lua-resty-core-0.1.31/t/require.t000066400000000000000000000032231474236722600165700ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; plan tests => repeat_each() * blocks() * 3; add_block_preprocessor(sub { my $block = shift; my $http_config = $block->http_config || ''; my $init_by_lua_block = $block->init_by_lua_block || ''; $http_config .= <<_EOC_; lua_package_path '\$prefix/html/?.lua;$t::TestCore::lua_package_path'; init_by_lua_block { $t::TestCore::init_by_lua_block $init_by_lua_block } _EOC_ $block->set_value("http_config", $http_config); }); no_diff(); no_long_string(); run_tests(); __DATA__ === TEST 1: utils.str_replace_char() sanity (replaces a single character) --- config location /t { content_by_lua_block { local has_foo, foo has_foo, foo= pcall(require, "foo") if not has_foo then ngx.say("failed to load foo: ", foo) end has_foo, foo = pcall(require, "foo") if not has_foo then ngx.say("failed to load foo again: ", foo) else ngx.say("type(a)=", type(a), " foo=", foo) end } } --- user_files >>> foo.lua local ffi = require("ffi") local _M = {} ffi.cdef[[ int xxxx(); ]] local function get_caches_array() return tonumber(ffi.C.xxxx()) end local a = get_caches_array() _M.a = a _M.get_caches_array = get_caches_array return _M --- request GET /t --- response_body eval qr|failed to load foo: .*/html/foo.lua:10: .*/lib/libluajit-5.1.so.2: undefined symbol: xxxx failed to load foo again: ./lib/resty/core/base.lua:\d+: loop or previous error loading module 'foo'|ms --- no_error_log [error] lua-resty-core-0.1.31/t/response.t000066400000000000000000000101001474236722600167420ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(1014); #master_process_enabled(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 5 + 5); #no_diff(); #no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: write to ngx.header.HEADER (single value) --- config location = /t { set $foo hello; content_by_lua_block { for i = 1, 100 do ngx.header["Foo"] = i end ngx.say("Foo: ", ngx.header["Foo"]) } } --- request GET /t --- response_body Foo: 100 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):2 loop\]/ --- no_error_log [error] -- NYI: === TEST 2: write to ngx.header.HEADER (nil) --- config location = /t { set $foo hello; content_by_lua_block { for i = 1, 200 do ngx.header["Foo"] = i ngx.header["Foo"] = nil end ngx.say("Foo: ", ngx.header["Foo"]) } } --- request GET /t --- response_body Foo: nil --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):2 loop\]/ --- wait: 0.2 --- no_error_log [error] -- NYI: === TEST 3: write to ngx.header.HEADER (multi-value) --- config location = /t { set $foo hello; content_by_lua_block { for i = 1, 200 do ngx.header["Foo"] = {i, i + 1} end local v = ngx.header["Foo"] if type(v) == "table" then ngx.say("Foo: ", table.concat(v, ", ")) else ngx.say("Foo: ", v) end } } --- request GET /t --- response_body Foo: 200, 201 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):2 loop\]/ --- no_error_log [error] -- NYI: === TEST 4: read from ngx.header.HEADER (single value) --- config location = /t { set $foo hello; content_by_lua_block { local v for i = 1, 100 do ngx.header["Foo"] = i v = ngx.header["Foo"] end ngx.say("Foo: ", v) } } --- request GET /t --- response_body Foo: 100 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log eval [ "[error]", qr/ -- NYI: (?!return to lower frame)/, "stitch", ] === TEST 5: read from ngx.header.HEADER (not found) --- config location = /t { set $foo hello; content_by_lua_block { local v for i = 1, 100 do v = ngx.header["Foo"] end ngx.say("Foo: ", v) } } --- request GET /t --- response_body Foo: nil --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] -- NYI: stitch === TEST 6: read from ngx.header.HEADER (multi-value) --- config location = /t { set $foo hello; content_by_lua_block { ngx.header["Foo"] = {"foo", "bar"} local v for i = 1, 100 do v = ngx.header["Foo"] end ngx.say("Foo: ", table.concat(v, ", ")) } } --- request GET /t --- response_body Foo: foo, bar --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] -- NYI: stitch === TEST 7: set multi values to cache-control and override it with multiple values --- config location /lua { content_by_lua_block { ngx.header.cache_control = { "private", "no-store" } ngx.header.cache_control = { "no-cache", "blah", "foo" } local v for i = 1, 400 do v = ngx.header.cache_control end ngx.say("Cache-Control: ", table.concat(v, ", ")) } } --- request GET /lua --- response_headers Cache-Control: no-cache, blah, foo --- response_body_like chop ^Cache-Control: no-cache[;,] blah[;,] foo$ --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):5 (?:loop|-> \d+)\]/ --- no_error_log [error] -- NYI: stitch lua-resty-core-0.1.31/t/semaphore.t000066400000000000000000001226531474236722600171100ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(10140); #workers(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 3 + 3); no_long_string(); #no_diff(); $ENV{TEST_NGINX_LUA_PACKAGE_PATH} = "$t::TestCore::lua_package_path"; our $HttpConfig = <<_EOC_; lua_package_path "$t::TestCore::lua_package_path"; _EOC_ run_tests(); __DATA__ === TEST 1: basic semaphore in uthread --- http_config eval: $::HttpConfig --- config location /test { content_by_lua_block { local semaphore = require "ngx.semaphore" local sem = semaphore.new() local function sem_wait() ngx.say("enter waiting") local ok, err = sem:wait(1) if not ok then ngx.say("err: ", err) else ngx.say("wait success") end end local co = ngx.thread.spawn(sem_wait) ngx.say("back in main thread") sem:post() ngx.say("still in main thread") ngx.sleep(0.01) ngx.say("main thread end") } } --- request GET /test --- response_body enter waiting back in main thread still in main thread wait success main thread end --- no_error_log [error] === TEST 2: semaphore wait order --- http_config eval: $::HttpConfig --- config location /test { content_by_lua_block { local semaphore = require "ngx.semaphore" local sem = semaphore.new() local function sem_wait(id) ngx.say("enter waiting, id: ", id) local ok, err = sem:wait(1) if not ok then ngx.say("err: ", err) else ngx.say("wait success, id: ", id) end end local co1 = ngx.thread.spawn(sem_wait, 1) local co2 = ngx.thread.spawn(sem_wait, 2) ngx.say("back in main thread") sem:post(2) local ok, err = sem:wait(0) if ok then ngx.say("wait success in main thread") else ngx.say("wait failed in main thread: ", err) -- busy end ngx.say("still in main thread") local ok, err = sem:wait(0.01) if ok then ngx.say("wait success in main thread") else ngx.say("wait failed in main thread: ", err) end ngx.sleep(0.01) ngx.say("main thread end") } } --- request GET /test --- response_body enter waiting, id: 1 enter waiting, id: 2 back in main thread wait failed in main thread: timeout still in main thread wait success, id: 1 wait success, id: 2 wait failed in main thread: timeout main thread end --- no_error_log [error] === TEST 3: semaphore wait time=0 --- http_config eval: $::HttpConfig --- config location /test { content_by_lua_block { local semaphore = require "ngx.semaphore" local sem = semaphore.new(1) local function wait_1s() ngx.say("enter 1s wait") local ok, err = sem:wait(1) if not ok then ngx.say("err in wait 1s: ", err) else ngx.say("wait success in 1s wait") end end local function wait_0() local ok, err = sem:wait(0) if not ok then ngx.say("err: ", err) else ngx.say("wait success") end end wait_0() wait_0() local co = ngx.thread.spawn(wait_1s) ngx.say("back in main thread") wait_0() sem:post(2) wait_0() ngx.say("still in main thread") ngx.sleep(0.01) wait_0() ngx.say("main thread end") } } --- request GET /test --- response_body wait success err: timeout enter 1s wait back in main thread err: timeout err: timeout still in main thread wait success in 1s wait wait success main thread end --- no_error_log [error] === TEST 4: basic semaphore in subrequest --- http_config eval: $::HttpConfig --- config location = /test { content_by_lua_block { local res1, res2 = ngx.location.capture_multi{ { "/sem_wait"}, { "/sem_post"}, } ngx.say(res1.status) ngx.say(res1.body) ngx.say(res2.status) ngx.say(res2.body) } } location /sem_wait { content_by_lua_block { local semaphore = require "ngx.semaphore" local g = package.loaded["semaphore_test"] or {} package.loaded["semaphore_test"] = g if not g.test then local sem, err = semaphore.new(0) if not sem then ngx.say(err) return end g.test = sem end local sem = g.test local ok, err = sem:wait(1) if ok then ngx.print("wait") end } } location /sem_post { content_by_lua_block { local semaphore = require "ngx.semaphore" local g = package.loaded["semaphore_test"] or {} package.loaded["semaphore_test"] = g if not g.test then local sem, err = semaphore.new(0) if not sem then ngx.say(err) ngx.exit(500) end g.test = sem end local sem = g.test ngx.sleep(0.001) collectgarbage("collect") sem:post() ngx.print("post") } } --- request GET /test --- response_body 200 wait 200 post --- no_error_log [error] [crit] === TEST 5: semaphore.new in init_by_lua* (w/o shdict) --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { local semaphore = require "ngx.semaphore" local sem, err = semaphore.new(0) if not sem then ngx.log(ngx.ERR, err) else ngx.log(ngx.WARN, "sema created: ", tostring(sem)) end sem:post(2) package.loaded.my_sema = sem } --- config location /test { content_by_lua_block { local sem = package.loaded.my_sema ngx.say("sem count: ", sem:count()) -- sem:post(1) local ok, err = sem:wait(0) if not ok then ngx.say("failed to wait: ", err) return end ngx.say("waited successfully.") } } --- request GET /test --- response_body_like sem count: [12] waited successfully. --- grep_error_log eval qr/\[lua\] init_by_lua\(nginx.conf:\d+\):\d+: sema created: table: 0x[a-f0-9]+/ --- grep_error_log_out eval [ qr/\[lua\] init_by_lua\(nginx.conf:\d+\):\d+: sema created: table: 0x[a-f0-9]+/, "", ] === TEST 6: semaphore.new in init_by_lua* (with shdict) --- http_config lua_shared_dict dogs 1m; lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { local semaphore = require "ngx.semaphore" local sem, err = semaphore.new(0) if not sem then ngx.log(ngx.ERR, err) else ngx.log(ngx.WARN, "sema created: ", tostring(sem)) end sem:post(2) package.loaded.my_sema = sem } --- config location /test { content_by_lua_block { local sem = package.loaded.my_sema ngx.say("sem count: ", sem:count()) -- sem:post(1) local ok, err = sem:wait(0) if not ok then ngx.say("failed to wait: ", err) return end ngx.say("waited successfully.") } } --- request GET /test --- response_body_like sem count: [12] waited successfully. --- grep_error_log eval qr/\[lua\] init_by_lua\(nginx.conf:\d+\):\d+: sema created: table: 0x[a-f0-9]+/ --- grep_error_log_out eval [ qr/\[lua\] init_by_lua\(nginx.conf:\d+\):\d+: sema created: table: 0x[a-f0-9]+/, "", ] === TEST 7: semaphore in init_worker_by_lua (wait is not allowed) --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_worker_by_lua_block { local semaphore = require "ngx.semaphore" local sem, err = semaphore.new(0) if not sem then ngx.log(ngx.ERR, "sem new: ", err) end sem:post(1) local count = sem:count() ngx.log(ngx.ERR, "sem count: ", count) local ok, err = sem:wait(0.1) if not ok then ngx.log(ngx.ERR, "sem wait: ", err) end } --- config location /t { echo "ok"; } --- request GET /t --- response_body ok --- grep_error_log eval: qr/sem \w+: .*?,/ --- grep_error_log_out eval [ "sem count: 1, sem wait: API disabled in the context of init_worker_by_lua*, ", "", ] === TEST 8: semaphore in init_worker_by_lua (new and post) --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_worker_by_lua_block { local semaphore = require "ngx.semaphore" local sem, err = semaphore.new(0) if not sem then ngx.log(ngx.ERR, "sem new: ", err) end sem:post(2) local count = sem:count() ngx.log(ngx.WARN, "sem count: ", count) package.loaded.my_sema = sem } --- config location /t { content_by_lua_block { local sem = package.loaded.my_sema local ok, err = sem:wait(0.1) if not ok then ngx.say("failed to wait: ", err) return end ngx.say("sem wait successfully.") } } --- request GET /t --- response_body sem wait successfully. --- grep_error_log eval: qr/sem \w+: .*?,/ --- grep_error_log_out eval [ "sem count: 2, ", "" ] --- no_error_log [error] === TEST 9: semaphore in set_by_lua (wait is not allowed) --- http_config eval: $::HttpConfig --- config location /t { set_by_lua_block $res { local semaphore = require "ngx.semaphore" local sem, err = semaphore.new(0) if not sem then ngx.log(ngx.ERR, "sem: ", err) end sem:post(1) local count = sem:count() ngx.log(ngx.ERR, "sem: ", count) local ok, err = sem:wait(0.1) if not ok then ngx.log(ngx.ERR, "sem: ", err) end } echo "ok"; } --- request GET /t --- response_body ok --- grep_error_log eval: qr/sem: .*?,/ --- grep_error_log_out eval [ "sem: 1, sem: API disabled in the context of set_by_lua*, ", "sem: 1, sem: API disabled in the context of set_by_lua*, ", ] === TEST 10: semaphore in rewrite_by_lua (all allowed) --- http_config eval: $::HttpConfig --- config location /t { rewrite_by_lua_block { local semaphore = require "ngx.semaphore" local sem, err = semaphore.new(0) if not sem then ngx.log(ngx.ERR, "sem: ", err) end local ok, err = sem:wait(0.01) if not ok then ngx.log(ngx.ERR, "sem: ", err) end sem:post(1) local count = sem:count() ngx.log(ngx.ERR, "sem: ", count) local ok, err = sem:wait(0.1) if not ok then ngx.log(ngx.ERR, "sem: ", err) end } echo "ok"; } --- request GET /t --- response_body ok --- grep_error_log eval: qr/sem: .*?,/ --- grep_error_log_out eval [ "sem: timeout, sem: 1, ", "sem: timeout, sem: 1, ", ] === TEST 11: semaphore in access_by_lua (all allowed) --- http_config eval: $::HttpConfig --- config location /t { access_by_lua_block { local semaphore = require "ngx.semaphore" local sem, err = semaphore.new(0) if not sem then ngx.log(ngx.ERR, "sem: ", err) end local ok, err = sem:wait(0.01) if not ok then ngx.log(ngx.ERR, "sem: ", err) end sem:post(1) local count = sem:count() ngx.log(ngx.ERR, "sem: ", count) local ok, err = sem:wait(0.1) if not ok then ngx.log(ngx.ERR, "sem: ", err) end } echo "ok"; } --- request GET /t --- response_body ok --- grep_error_log eval: qr/sem: .*?,/ --- grep_error_log_out eval [ "sem: timeout, sem: 1, ", "sem: timeout, sem: 1, ", ] === TEST 12: semaphore in content_by_lua (all allowed) --- http_config eval: $::HttpConfig --- config location /t { content_by_lua_block { local semaphore = require "ngx.semaphore" local sem, err = semaphore.new(0) if not sem then ngx.log(ngx.ERR, "sem: ", err) end local ok, err = sem:wait(0.01) if not ok then ngx.log(ngx.ERR, "sem: ", err) end sem:post(1) local count = sem:count() ngx.log(ngx.ERR, "sem: ", count) local ok, err = sem:wait(0.1) if not ok then ngx.log(ngx.ERR, "sem: ", err) else ngx.say("ok") end } } --- request GET /t --- response_body ok --- grep_error_log eval: qr/sem: .*?,/ --- grep_error_log_out eval [ "sem: timeout, sem: 1, ", "sem: timeout, sem: 1, ", ] === TEST 13: semaphore in log_by_lua (wait not allowed) --- http_config eval: $::HttpConfig --- config location /t { echo "ok"; log_by_lua_block { local semaphore = require "ngx.semaphore" local sem, err = semaphore.new(0) if not sem then ngx.log(ngx.ERR, "sem: ", err) end sem:post(1) local count = sem:count() ngx.log(ngx.ERR, "sem: ", count) local ok, err = sem:wait(0.1) if not ok then ngx.log(ngx.ERR, "sem: ", err) end } } --- request GET /t --- response_body ok --- grep_error_log eval: qr/sem: .*?,/ --- grep_error_log_out eval [ "sem: 1 while logging request, sem: API disabled in the context of log_by_lua* while logging request, ", "sem: 1 while logging request, sem: API disabled in the context of log_by_lua* while logging request, ", ] --- wait: 0.2 === TEST 14: semaphore in header_filter_by_lua (wait not allowed) --- http_config eval: $::HttpConfig --- config location /t { echo "ok"; header_filter_by_lua_block { local semaphore = require "ngx.semaphore" local sem, err = semaphore.new(0) if not sem then ngx.log(ngx.ERR, "sem: ", err) end sem:post(1) local count = sem:count() ngx.log(ngx.ERR, "sem: ", count) local ok, err = sem:wait(0.1) if not ok then ngx.log(ngx.ERR, "sem: ", err) end } } --- request GET /t --- response_body ok --- grep_error_log eval: qr/sem: .*?,/ --- grep_error_log_out eval [ "sem: 1, sem: API disabled in the context of header_filter_by_lua*, ", "sem: 1, sem: API disabled in the context of header_filter_by_lua*, ", ] === TEST 15: semaphore in body_filter_by_lua (wait not allowed) --- http_config eval: $::HttpConfig --- config location /t { echo "ok"; body_filter_by_lua_block { local semaphore = require "ngx.semaphore" local sem, err = semaphore.new(0) if not sem then ngx.log(ngx.ERR, "sem: ", err) end sem:post(1) local count = sem:count() ngx.log(ngx.ERR, "sem: ", count) local ok, err = sem:wait(0.1) if not ok then ngx.log(ngx.ERR, "sem: ", err) end } } --- request GET /t --- response_body ok --- grep_error_log eval: qr/sem: .*?,/ --- grep_error_log_out eval [ "sem: 1, sem: API disabled in the context of body_filter_by_lua*, sem: 1, sem: API disabled in the context of body_filter_by_lua*, ", "sem: 1, sem: API disabled in the context of body_filter_by_lua*, sem: 1, sem: API disabled in the context of body_filter_by_lua*, ", ] === TEST 16: semaphore in ngx.timer (all allowed) --- http_config eval: $::HttpConfig --- config location /t { content_by_lua_block { local function func_sem() local semaphore = require "ngx.semaphore" local sem, err = semaphore.new(0) if not sem then ngx.log(ngx.ERR, "sem: ", err) end local ok, err = sem:wait(0.01) if not ok then ngx.log(ngx.ERR, "sem: ", err) end sem:post(1) local count = sem:count() ngx.log(ngx.ERR, "sem: ", count) local ok, err = sem:wait(0.1) if not ok then ngx.log(ngx.ERR, "sem: ", err) end end local ok, err = ngx.timer.at(0, func_sem) if ok then ngx.sleep(0.01) ngx.say("ok") end } } --- request GET /t --- response_body ok --- grep_error_log eval: qr/sem: .*?,/ --- grep_error_log_out eval [ "sem: timeout, sem: 1, ", "sem: timeout, sem: 1, ", ] --- wait: 0.2 === TEST 17: semaphore post in all phase (in a request) --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_worker_by_lua_block { local semaphore = require "ngx.semaphore" local sem, err = semaphore.new(0) if not sem then ngx.log(ngx.ERR, err) end package.loaded.sem = sem local function wait() local i = 0 while true do local ok, err = sem:wait(1) if not ok then ngx.log(ngx.ERR, "sem: ", err) end i = i + 1 if i % 6 == 0 then ngx.log(ngx.ERR, "sem: 6 times") end end end local ok, err = ngx.timer.at(0, wait) if not ok then ngx.log(ngx.ERR, "sem: ", err) end } --- config location /test { set_by_lua_block $res { local sem = package.loaded.sem sem:post() } rewrite_by_lua_block { local sem = package.loaded.sem sem:post() } access_by_lua_block { local sem = package.loaded.sem sem:post() } content_by_lua_block { local sem = package.loaded.sem sem:post() ngx.say("ok") } header_filter_by_lua_block { local sem = package.loaded.sem sem:post() } body_filter_by_lua_block { local sem = package.loaded.sem sem:post() } } --- request GET /test --- response_body ok --- grep_error_log eval: qr/sem: .*?,/ --- grep_error_log_out eval [ "sem: 6 times, ", "sem: 6 times, ", ] --- wait: 0.2 === TEST 18: semaphore wait post in access_by_lua --- http_config eval: $::HttpConfig --- config location /test { access_by_lua_block { local semaphore = require "ngx.semaphore" local sem = semaphore.new(0) local func_wait = function () ngx.say("enter wait") local ok, err = sem:wait(1) if ok then ngx.say("wait success") end end local func_post = function () ngx.say("enter post") sem:post() ngx.say("post success") end local co1 = ngx.thread.spawn(func_wait) local co2 = ngx.thread.spawn(func_post) ngx.thread.wait(co1) ngx.thread.wait(co2) } } --- request GET /test --- response_body enter wait enter post post success wait success --- no_error_log [error] === TEST 19: semaphore wait post in rewrite_by_lua --- http_config eval: $::HttpConfig --- config location /t { rewrite_by_lua_block { local semaphore = require "ngx.semaphore" local sem = semaphore.new(0) local func_wait = function () ngx.say("enter wait") local ok, err = sem:wait(1) if ok then ngx.say("wait success") end end local func_post = function () ngx.say("enter post") sem:post() ngx.say("post success") end local co1 = ngx.thread.spawn(func_wait) local co2 = ngx.thread.spawn(func_post) ngx.thread.wait(co1) ngx.thread.wait(co2) } } --- request GET /test --- response_body enter wait enter post post success wait success --- no_error_log [error] === TEST 20: semaphore wait in timer.at --- http_config eval: $::HttpConfig --- config location /test { content_by_lua_block { local semaphore = require "ngx.semaphore" local sem = semaphore.new() local function func_wait(premature) local ok, err = sem:wait(1) if not ok then ngx.log(ngx.ERR, err) else ngx.log(ngx.ERR, "wait success") end end ngx.timer.at(0, func_wait) sem:post() ngx.sleep(0.01) ngx.say("ok") } } --- request GET /test --- response_body ok --- error_log wait success === TEST 21: semaphore post in header_filter_by_lua (subrequest) --- http_config eval: $::HttpConfig --- config location /test { content_by_lua_block { local res1, res2 = ngx.location.capture_multi{ {"/sem_wait"}, {"/sem_post"}, } ngx.say(res1.status) ngx.say(res1.body) ngx.say(res2.status) ngx.say(res2.body) } } location /sem_wait { content_by_lua_block { local semaphore = require "ngx.semaphore" if not package.loaded.sem then local sem, err = semaphore.new(0) if not sem then ngx.say(err) ngx.exit(500) end package.loaded.sem = sem end local sem = package.loaded.sem local ok, err = sem:wait(1) if ok then ngx.print("wait") ngx.exit(200) else ngx.exit(500) end } } location /sem_post { header_filter_by_lua_block { local semaphore = require "ngx.semaphore" if not package.loaded.sem then local sem, err = semaphore.new(0) if not sem then ngx.log(ngx.ERR, err) end package.loaded.sem = sem end local sem = package.loaded.sem sem:post() } content_by_lua_block { ngx.print("post") ngx.exit(200) } } --- request GET /test --- response_body 200 wait 200 post --- no_error_log [error] === TEST 22: semaphore post in body_filter_by_lua (subrequest) --- http_config eval: $::HttpConfig --- config location /test { content_by_lua_block { local res1, res2 = ngx.location.capture_multi{ {"/sem_wait"}, {"/sem_post"}, } ngx.say(res1.status) ngx.say(res1.body) ngx.say(res2.status) ngx.say(res2.body) } } location /sem_wait { content_by_lua_block { local semaphore = require "ngx.semaphore" if not package.loaded.sem then local sem, err = semaphore.new(0) if not sem then ngx.say(err) ngx.exit(500) end package.loaded.sem = sem end local sem = package.loaded.sem local ok, err = sem:wait(10) if ok then ngx.print("wait") ngx.exit(200) else ngx.exit(500) end } } location /sem_post { body_filter_by_lua_block { local semaphore = require "ngx.semaphore" if not package.loaded.sem then local sem, err = semaphore.new(0) if not sem then ngx.log(ngx.ERR, err) end package.loaded.sem = sem end local sem = package.loaded.sem sem:post() } content_by_lua_block { ngx.print("post") ngx.exit(200) } } --- request GET /test --- response_body 200 wait 200 post --- log_level: debug --- no_error_log [error] === TEST 23: semaphore post in set_by_lua --- http_config eval: $::HttpConfig --- config location /test { content_by_lua_block { local res1, res2 = ngx.location.capture_multi{ {"/sem_wait"}, {"/sem_post"}, } ngx.say(res1.status) ngx.say(res1.body) ngx.say(res2.status) ngx.say(res2.body) } } location /sem_wait { content_by_lua_block { local semaphore = require "ngx.semaphore" if not package.loaded.sem then local sem, err = semaphore.new(0) if not sem then ngx.say(err) ngx.exit(500) end package.loaded.sem = sem end local sem = package.loaded.sem local ok, err = sem:wait(10) if ok then ngx.print("wait") ngx.exit(200) else ngx.exit(500) end } } location /sem_post { set_by_lua_block $res { local semaphore = require "ngx.semaphore" if not package.loaded.sem then local sem, err = semaphore.new(0) if not sem then ngx.log(ngx.ERR, err) end package.loaded.sem = sem end local sem = package.loaded.sem sem:post() } content_by_lua_block { ngx.print("post") ngx.exit(200) } } --- request GET /test --- response_body 200 wait 200 post --- log_level: debug --- no_error_log [error] === TEST 24: semaphore post in timer.at --- http_config eval: $::HttpConfig --- config location /test { content_by_lua_block { local semaphore = require "ngx.semaphore" package.loaded.sem = semaphore.new(0) local res1, res2 = ngx.location.capture_multi{ {"/sem_wait"}, {"/sem_post"}, } ngx.say(res1.status) ngx.say(res1.body) ngx.say(res2.status) ngx.say(res2.body) } } location /sem_wait { content_by_lua_block { local sem = package.loaded.sem local ok, err = sem:wait(2) if ok then ngx.print("wait") ngx.exit(200) else ngx.status = 500 ngx.say(err) end } } location /sem_post { content_by_lua_block { local function func(premature) local sem = package.loaded.sem sem:post() end ngx.timer.at(0, func, g) ngx.sleep(0) ngx.print("post") ngx.exit(200) } } --- request GET /test --- response_body 200 wait 200 post --- log_level: debug --- no_error_log [error] === TEST 25: two thread wait for each other --- http_config eval: $::HttpConfig --- config location /test { content_by_lua_block { local semaphore = require "ngx.semaphore" local sem_A = semaphore.new(0) local sem_B = semaphore.new(0) if not sem_A or not sem_B then error("create failed") end local function th_A() for i = 1, 11 do local ok, err = sem_A:wait(1) if not ok then ngx.log(ngx.ERR, err) end sem_B:post(1) end ngx.say("count in A: ", sem_A:count()) end local function th_B() for i = 1, 10 do local ok, err = sem_B:wait(1) if not ok then ngx.log(ngx.ERR, err) end sem_A:post(1) end ngx.say("count in B: ", sem_B:count()) end local co_A = ngx.thread.spawn(th_A) local co_B = ngx.thread.spawn(th_B) sem_A:post(1) } } --- log_level: debug --- request GET /test --- response_body count in B: 0 count in A: 0 --- no_error_log [error] === TEST 26: kill a light thread that is waiting on a semaphore (no resource) --- http_config eval: $::HttpConfig --- config location /test { content_by_lua_block { local semaphore = require "ngx.semaphore" local sem = semaphore.new(0) if not sem then error("create failed") end local function func_wait() sem:wait(1) end local co = ngx.thread.spawn(func_wait) local ok, err = ngx.thread.kill(co) if ok then ngx.say("ok") else ngx.say(err) end } } --- log_level: debug --- request GET /test --- response_body ok --- no_error_log [error] === TEST 27: kill a light thread that is waiting on a semaphore (after post) --- http_config eval: $::HttpConfig --- config location /test { content_by_lua_block { local semaphore = require "ngx.semaphore" local sem = semaphore.new(0) if not sem then error("create failed") end local function func_wait() sem:wait(1) end local co = ngx.thread.spawn(func_wait) sem:post() local ok, err = ngx.thread.kill(co) if ok then ngx.say("ok") else ngx.say(err) end ngx.sleep(0.01) local count = sem:count() ngx.say("count: ", count) } } --- log_level: debug --- request GET /test --- response_body ok count: 1 --- no_error_log [error] === TEST 28: kill a thread that is waiting on another thread that is waiting on semaphore --- http_config eval: $::HttpConfig --- config location /test { content_by_lua_block { local semaphore = require "ngx.semaphore" local sem = semaphore.new(0) if not sem then error("create failed") end local function sem_wait() ngx.say("sem waiting start") local ok, err = sem:wait(0.1) if not ok then ngx.say("sem wait err: ", err) end ngx.say("sem waiting done") end local function thread_wait() local co = ngx.thread.spawn(sem_wait) ngx.say("thread waiting start") local ok, err = ngx.thread.wait(co) if not ok then ngx.say("thread wait err: ", err) end ngx.say("thread waiting done") end local co2 = ngx.thread.spawn(thread_wait) ngx.sleep(0.01) local ok, err = ngx.thread.kill(co2) if ok then ngx.say("thread kill success") else ngx.say("kill err: ", err) end } } --- log_level: debug --- request GET /test --- response_body sem waiting start thread waiting start thread kill success sem wait err: timeout sem waiting done --- no_error_log [error] === TEST 29: a light thread that is going to exit is waiting on a semaphore --- http_config eval: $::HttpConfig --- config location /test { content_by_lua_block { local semaphore = require "ngx.semaphore" local sem = semaphore.new(0) if not sem then error("create failed") end local function func(sem) ngx.say("sem waiting") local ok, err = sem:wait(0.1) if ok then ngx.say("wait success") else ngx.say("err: ", err) end end local co = ngx.thread.spawn(func, sem) ngx.say("ok") ngx.exit(200) } } --- log_level: debug --- request GET /test --- response_body sem waiting ok --- error_log http lua semaphore cleanup === TEST 30: main thread wait a light thread that is waiting on a semaphore --- http_config eval: $::HttpConfig --- config location /test { content_by_lua_block { local semaphore = require "ngx.semaphore" local sem = semaphore.new(0) if not sem then error("create failed") end local function func(sem) local ok, err = sem:wait(0.001) if ok then ngx.say("wait success") else ngx.say("err: ", err) end end local co = ngx.thread.spawn(func, sem) ngx.thread.wait(co) } } --- log_level: debug --- request GET /test --- response_body err: timeout --- no_error_log [error] === TEST 31: multi wait and mult post with one semaphore --- http_config eval: $::HttpConfig --- config location = /test { content_by_lua_block { local semaphore = require "ngx.semaphore" local sem, err = semaphore.new(0) if not sem then ngx.log(ngx.ERR, err) ngx.exit(500) end local function func(op, id) ngx.say(op, ": ", id) if op == "wait" then local ok, err = sem:wait(1) if ok then ngx.say("wait success: ", id) end else sem:post() end end local tco = {} for i = 1, 3 do tco[#tco + 1] = ngx.thread.spawn(func, "wait", i) end for i = 1, 3 do tco[#tco + 1] = ngx.thread.spawn(func, "post", i) end for i = 1, #tco do ngx.thread.wait(tco[i]) end } } --- request GET /test --- response_body wait: 1 wait: 2 wait: 3 post: 1 post: 2 post: 3 wait success: 1 wait success: 2 wait success: 3 --- no_error_log [error] === TEST 32: semaphore wait time is zero --- http_config eval: $::HttpConfig --- config location /test { content_by_lua_block { local semaphore = require "ngx.semaphore" local sem = semaphore.new(0) local ok, err = sem:wait(0) if not ok then ngx.say(err) end } } --- request GET /test --- response_body timeout --- no_error_log [error] === TEST 33: test semaphore gc --- http_config eval: $::HttpConfig --- config location /test { content_by_lua_block { local semaphore = require "ngx.semaphore" local sem, err = semaphore.new(0) if sem then ngx.say("success") end sem = nil collectgarbage("collect") } } --- request GET /test --- response_body success --- log_level: debug --- error_log in lua gc, semaphore === TEST 34: basic semaphore_mm alloc --- http_config eval: $::HttpConfig --- config location /test { content_by_lua_block { local semaphore = require "ngx.semaphore" local sem = semaphore.new(0) if sem then ngx.say("ok") end } } --- log_level: debug --- request GET /test --- response_body ok --- grep_error_log eval: qr/(new block, alloc semaphore|from head of free queue, alloc semaphore)/ --- grep_error_log_out eval [ "new block, alloc semaphore ", "from head of free queue, alloc semaphore ", ] === TEST 35: basic semaphore_mm free insert tail --- http_config eval: $::HttpConfig --- config location /t { content_by_lua_block { local semaphore = require "ngx.semaphore" local sems = package.loaded.sems or {} package.loaded.sems = sems local num_per_block = 4095 if not sems[num_per_block] then for i = 1, num_per_block * 3 do sems[i] = semaphore.new(0) end end for i = 1, 2 do if sems[i] then sems[i] = nil ngx.say("ok") break end end collectgarbage("collect") } } --- log_level: debug --- request GET /t --- response_body ok --- error_log add to free queue tail === TEST 36: basic semaphore_mm free insert head --- http_config eval: $::HttpConfig --- config location /test { content_by_lua_block { local semaphore = require "ngx.semaphore" local sems = package.loaded.sems or {} package.loaded.sems = sems local num_per_block = 4095 if not sems[num_per_block] then for i = 1, num_per_block * 3 do sems[i] = semaphore.new(0) end end if sems[#sems] then sems[#sems] = nil ngx.say("ok") end collectgarbage("collect") } } --- log_level: debug --- request GET /test --- response_body ok --- error_log add to free queue head === TEST 37: semaphore_mm free block (load <= 50% & the on the older side) --- http_config eval: $::HttpConfig --- config location /test { content_by_lua_block { local semaphore = require "ngx.semaphore" local sems = package.loaded.sems or {} package.loaded.sems = sems local num_per_block = 4095 if not sems[num_per_block * 3] then for i = 1, num_per_block * 3 do sems[i] = semaphore.new(0) end for i = num_per_block + 1, num_per_block * 2 do sems[i] = nil end else for i = 1, num_per_block do sems[i] = nil end end collectgarbage("collect") ngx.say("ok") } } --- log_level: debug --- request GET /test --- response_body ok --- grep_error_log eval: qr/free semaphore block/ --- grep_error_log_out eval [ "", "free semaphore block ", ] --- timeout: 10 === TEST 38: basic semaphore count --- http_config eval: $::HttpConfig --- config location /test { content_by_lua_block { local semaphore = require "ngx.semaphore" local sem = semaphore.new(10) local count = sem:count() ngx.say(count) sem:wait(0) local count = sem:count() ngx.say(count) sem:post(3) local count = sem:count() ngx.say(count) } } --- request GET /test --- response_body 10 9 12 --- no_error_log [error] === TEST 39: basic semaphore count (negative number) --- http_config eval: $::HttpConfig --- config location /test { content_by_lua_block { local semaphore = require "ngx.semaphore" local sem = semaphore.new() local count = sem:count() ngx.say(count) local function wait() sem:wait(0.01) end local co = ngx.thread.spawn(wait) local count = sem:count() ngx.say(count) } } --- request GET /test --- response_body 0 -1 --- no_error_log [error] === TEST 40: bugfix: semaphore instance can't be garbage collected when someone is waiting on it --- http_config eval: $::HttpConfig --- config location /test { content_by_lua_block { local semaphore = require "ngx.semaphore" local my_sema = {} local key = "my key" local function my_clean() print("cleaning up") my_sema[key]:post() my_sema[key] = nil collectgarbage() end local ok, err = ngx.timer.at(0.001, my_clean) if not ok then ngx.log(ngx.ERR, "failed to create timer: ", err) ngx.exit(500) end my_sema[key] = semaphore:new(0) local ok, err = my_sema[key]:wait(2) ngx.say(ok, ", ", err) } } --- request GET /test --- response_body true, nil --- no_error_log [error] [crit] lua-resty-core-0.1.31/t/sha1-bin.t000066400000000000000000000036231474236722600165220ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(1014); #master_process_enabled(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 4); #no_diff(); #no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: set sha1_bin (string) --- config location = /sha1_bin { content_by_lua_block { local s for i = 1, 30 do s = ngx.sha1_bin("hello") end ngx.say(string.len(s)) } } --- request GET /sha1_bin --- response_body 20 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] === TEST 2: set sha1_bin (nil) --- config location = /sha1_bin { content_by_lua_block { local s for i = 1, 30 do s = ngx.sha1_bin(nil) end ngx.say(string.len(s)) } } --- request GET /sha1_bin --- response_body 20 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] === TEST 3: set sha1_bin (number) --- config location = /sha1_bin { content_by_lua_block { local s for i = 1, 30 do s = ngx.sha1_bin(3.14) end ngx.say(string.len(s)) } } --- request GET /sha1_bin --- response_body 20 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] === TEST 4: set sha1_bin (boolean) --- config location = /sha1_bin { content_by_lua_block { local s for i = 1, 30 do s = ngx.sha1_bin(true) end ngx.say(string.len(s)) } } --- request GET /sha1_bin --- response_body 20 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] lua-resty-core-0.1.31/t/shared.t000066400000000000000000000215321474236722600163650ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; repeat_each(2); plan tests => repeat_each() * blocks() * 4; our $HttpConfig = <<_EOC_; lua_shared_dict dogs 1m; $t::TestCore::HttpConfig _EOC_ no_diff(); no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: shared.ttl errors on nil key --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua_block { local ttl, err = ngx.shared.dogs:ttl() if not ttl then ngx.say("failed to get ttl: ", err) end } } --- request GET /t --- response_body failed to get ttl: nil key --- no_error_log [error] [alert] === TEST 2: shared.ttl errors on empty key --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua_block { local ttl, err = ngx.shared.dogs:ttl("") if not ttl then ngx.say("failed to get ttl: ", err) end } } --- request GET /t --- response_body failed to get ttl: empty key --- no_error_log [error] [alert] === TEST 3: shared.ttl returns error on not found key --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua_block { local ttl, err = ngx.shared.dogs:ttl("key") if not ttl then ngx.say("failed to get ttl: ", err) end } } --- request GET /t --- response_body failed to get ttl: not found --- no_error_log [error] [alert] === TEST 4: shared.ttl returns key ttl for non-default (positive) ttl --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua_block { local ok, err = ngx.shared.dogs:set("key", true, 0.2) local ttl, err = ngx.shared.dogs:ttl("key") if not ttl then ngx.log(ngx.ERR, "failed to get ttl: ", err) end ngx.say(ttl) ngx.say("sleep for 0.1s...") ngx.sleep(0.1) ttl, err = ngx.shared.dogs:ttl("key") if not ttl then ngx.log(ngx.ERR, "failed to get ttl: ", err) end ngx.say(ttl) } } --- request GET /t --- response_body_like chomp \A0.2 sleep for 0.1s... 0.\d* \z --- no_error_log [error] [alert] === TEST 5: shared.ttl returns key ttl for non-default (negative) ttl --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua_block { local ok, err = ngx.shared.dogs:set("key", true, 0.1) local ttl, err = ngx.shared.dogs:ttl("key") if not ttl then ngx.log(ngx.ERR, "failed to get ttl: ", err) end ngx.say(ttl) ngx.say("sleep for 0.2s...") ngx.sleep(0.2) ttl, err = ngx.shared.dogs:ttl("key") if not ttl then ngx.log(ngx.ERR, "failed to get ttl: ", err) end ngx.say(ttl) } } --- request GET /t --- response_body_like chomp \A0.1 sleep for 0.2s... -0.\d* \z --- no_error_log [error] [alert] === TEST 6: shared.ttl returns key ttl for default ttl (0) --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua_block { local ok, err = ngx.shared.dogs:set("key", true) local ttl, err = ngx.shared.dogs:ttl("key") if not ttl then ngx.log(ngx.ERR, "failed to get ttl: ", err) end ngx.say(ttl) ngx.say("sleep for 0.1s...") ngx.sleep(0.11) ttl, err = ngx.shared.dogs:ttl("key") if not ttl then ngx.log(ngx.ERR, "failed to get ttl: ", err) end ngx.say(ttl) } } --- request GET /t --- response_body 0 sleep for 0.1s... 0 --- no_error_log [error] [alert] === TEST 7: shared.ttl JIT compiles --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua_block { local ok, err = ngx.shared.dogs:set("key", true) for i = 1, 30 do local ttl, err = ngx.shared.dogs:ttl("key") if not ttl then ngx.log(ngx.ERR, "failed to get ttl: ", err) end end } } --- request GET /t --- response_body --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] === TEST 8: shared.expire errors on invalid exptime --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua_block { local dogs = ngx.shared.dogs local ok, err = pcall(dogs.expire, dogs) if not ok then ngx.say(err) end } } --- request GET /t --- response_body bad "exptime" argument --- no_error_log [error] [alert] === TEST 9: shared.expire returns error on nil key --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua_block { local dogs = ngx.shared.dogs local ok, err = dogs:expire(nil, 1) if not ok then ngx.say("failed to set ttl: ", err) end } } --- request GET /t --- response_body failed to set ttl: nil key --- no_error_log [error] [alert] === TEST 10: shared.expire returns error on empty key --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua_block { local dogs = ngx.shared.dogs local ok, err = dogs:expire("", 1) if not ok then ngx.say("failed to set ttl: ", err) end } } --- request GET /t --- response_body failed to set ttl: empty key --- no_error_log [error] [alert] === TEST 11: shared.expire returns error on not found key --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua_block { local dogs = ngx.shared.dogs local ok, err = dogs:expire("key", 1) if not ok then ngx.say("failed to set ttl: ", err) end } } --- request GET /t --- response_body failed to set ttl: not found --- no_error_log [error] [alert] === TEST 12: shared.expire updates ttl of key with non-default ttl --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua_block { local dogs = ngx.shared.dogs local ok, err = dogs:set("key", true, 0.1) if not ok then ngx.log(ngx.ERR, "failed to set: ", err) end ok, err = dogs:expire("key", 0.3) if not ok then ngx.say("failed to set ttl: ", err) end ngx.sleep(0.2) local val, err = dogs:get("key") if err then ngx.log(ngx.ERR, "failed to get: ", err) end ngx.say("after 0.2s: ", val) ngx.sleep(0.2) val, err = dogs:get("key") if err then ngx.log(ngx.ERR, "failed to get: ", err) end ngx.say("after 0.4s: ", val) } } --- request GET /t --- response_body after 0.2s: true after 0.4s: nil --- no_error_log [error] [alert] === TEST 13: shared.expire updates ttl of key with default ttl (0) --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua_block { local dogs = ngx.shared.dogs local ok, err = dogs:set("key", true) if not ok then ngx.log(ngx.ERR, "failed to set: ", err) end local val, err = dogs:get("key") if err then ngx.log(ngx.ERR, "failed to get: ", err) end ngx.say("after set: ", val) ok, err = dogs:expire("key", 0.3) if not ok then ngx.say("failed to set ttl: ", err) end ngx.sleep(0.4) val, err = dogs:get("key") if err then ngx.log(ngx.ERR, "failed to get: ", err) end ngx.say("after 0.4s: ", val) } } --- request GET /t --- response_body after set: true after 0.4s: nil --- no_error_log [error] [alert] === TEST 14: shared.expire JIT compiles --- http_config eval: $::HttpConfig --- config location = /t { content_by_lua_block { local dogs = ngx.shared.dogs local ok, err = dogs:set("key", true, 0.1) if not ok then ngx.log(ngx.ERR, "failed to set: ", err) end for i = 1, 30 do local ok, err = dogs:expire("key", 0.3) if not ok then ngx.say("failed to set ttl: ", err) end end } } --- request GET /t --- response_body --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):9 loop\]/ --- no_error_log [error] lua-resty-core-0.1.31/t/shdict.t000066400000000000000000001137521474236722600164030ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(1014); #master_process_enabled(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 5 + 2); add_block_preprocessor(sub { my $block = shift; my $http_config = $block->http_config || ''; $http_config .= <<_EOC_; lua_shared_dict dogs 1m; lua_shared_dict cats 16k; lua_shared_dict birds 100k; $t::TestCore::HttpConfig _EOC_ $block->set_value("http_config", $http_config); }); #no_diff(); no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: get a string value --- config location = /t { content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) local ok, err, forcible = dogs:set("foo", "bar", 0, 72) if not ok then ngx.say("failed to set: ", err) return end for i = 1, 100 do val, flags = dogs:get("foo") end ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } } --- request GET /t --- response_body value type: string value: bar flags: 72 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):11 loop\]/ --- no_error_log [error] -- NYI: === TEST 2: get an nonexistent key --- config location = /t { content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) -- dogs:set("foo", "bar") for i = 1, 100 do val, flags = dogs:get("nonexistent") end ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } } --- request GET /t --- response_body value type: nil value: nil flags: nil --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):7 loop\]/ --- no_error_log [error] -- NYI: === TEST 3: get a boolean value (true) --- config location = /t { content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) dogs:set("foo", true, 0, 5678) for i = 1, 100 do val, flags = dogs:get("foo") end ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } } --- request GET /t --- response_body value type: boolean value: true flags: 5678 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):7 loop\]/ --- no_error_log [error] -- NYI: === TEST 4: get a boolean value (false) --- config location = /t { content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) dogs:set("foo", false, 0, 777) for i = 1, 100 do val, flags = dogs:get("foo") end ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } } --- request GET /t --- response_body value type: boolean value: false flags: 777 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):7 loop\]/ --- no_error_log [error] -- NYI: === TEST 5: get a number value (int) --- config location = /t { content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) dogs:set("foo", 51203) for i = 1, 100 do val, flags = dogs:get("foo") end ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } } --- request GET /t --- response_body value type: number value: 51203 flags: nil --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):7 loop\]/ --- no_error_log [error] -- NYI: === TEST 6: get a number value (double) --- config location = /t { content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) dogs:set("foo", 3.1415926, 0, 78) for i = 1, 100 do val, flags = dogs:get("foo") end ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } } --- request GET /t --- response_body value type: number value: 3.1415926 flags: 78 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):7 loop\]/ --- no_error_log [error] -- NYI: === TEST 7: get a large string value --- config location = /t { content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) dogs:flush_all() dogs:flush_expired() dogs:set("foo", string.rep("bbbb", 1024) .. "a", 0, 912) for i = 1, 100 do val, flags = dogs:get("foo") end ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } } --- request GET /t --- response_body eval "value type: string value: " . ("bbbb" x 1024) . "a flags: 912 " --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):9 loop\]/ --- no_error_log [error] -- NYI: === TEST 8: get_stale (false) --- config location = /t { content_by_lua_block { local ffi = require "ffi" local val, flags, stale local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) dogs:set("foo", "bar", 0, 72) for i = 1, 100 do val, flags, stale = dogs:get_stale("foo") end ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) ngx.say("stale: ", stale) } } --- request GET /t --- response_body value type: string value: bar flags: 72 stale: false --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):7 loop\]/ --- no_error_log [error] -- NYI: === TEST 9: get_stale (true) --- config location = /t { content_by_lua_block { local ffi = require "ffi" local val, flags, stale local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) local ok, err, forcible = dogs:set("foo", "bar", 0.01, 72) if not ok then ngx.say("failed to set: ", err) return end ngx.update_time() ngx.sleep(0.02) for i = 1, 30 do val, flags, stale = dogs:get_stale("foo") end ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) ngx.say("stale: ", stale) } } --- request GET /t --- response_body value type: string value: bar flags: 72 stale: true --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):13 loop\]/ --- no_error_log [error] -- NYI: === TEST 10: incr int --- config location = /t { content_by_lua_block { local ffi = require "ffi" local val local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) local ok, err, forcible = dogs:set("foo", 56) if not ok then ngx.say("failed to set: ", err) return end for i = 1, 100 do val, err = dogs:incr("foo", 2) end ngx.say("value: ", val) ngx.say("err: ", err) } } --- request GET /t --- response_body value: 256 err: nil --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):11 loop\]/ --- no_error_log [error] -- NYI: === TEST 11: incr double --- config location = /t { content_by_lua_block { local ffi = require "ffi" local val, err local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) dogs:set("foo", 56) for i = 1, 150 do val, err = dogs:incr("foo", 2.1) end ngx.say("value: ", val) ngx.say("err: ", err) } } --- request GET /t --- response_body value: 371 err: nil --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):7 loop\]/ --- no_error_log [error] -- NYI: === TEST 12: set a string value --- config location = /t { content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) local ok, err, forcible for i = 1, 100 do ok, err, forcible = dogs:set("foo", "bar", 0, 72) end if not ok then ngx.say("failed to set: ", err) return end val, flags = dogs:get("foo") ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } } --- request GET /t --- response_body value type: string value: bar flags: 72 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):7 loop\]/ --- no_error_log [error] -- NYI: === TEST 13: set a boolean value (true) --- config location = /t { content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) local ok, err, forcible for i = 1, 100 do ok, err, forcible = dogs:set("foo", true, 0, 5678) end if not ok then ngx.say("failed to set: ", err) return end val, flags = dogs:get("foo") ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } } --- request GET /t --- response_body value type: boolean value: true flags: 5678 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):7 loop\]/ --- no_error_log [error] -- NYI: === TEST 14: set a boolean value (false) --- config location = /t { content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) for i = 1, 100 do dogs:set("foo", false, 0, 777) end val, flags = dogs:get("foo") ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } } --- request GET /t --- response_body value type: boolean value: false flags: 777 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):6 loop\]/ --- no_error_log [error] -- NYI: === TEST 15: set a number value (int) --- config location = /t { content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) for i = 1, 100 do dogs:set("foo", 51203) end val, flags = dogs:get("foo") ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } } --- request GET /t --- response_body value type: number value: 51203 flags: nil --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):6 loop\]/ --- no_error_log [error] -- NYI: === TEST 16: set a number value (double) --- config location = /t { content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) for i = 1, 100 do dogs:set("foo", 3.1415926, 0, 78) end val, flags = dogs:get("foo") ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } } --- request GET /t --- response_body value type: number value: 3.1415926 flags: 78 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):6 loop\]/ --- no_error_log [error] -- NYI: === TEST 17: set a number value and a nil --- config location = /t { content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) for i = 1, 150 do dogs:set("foo", 3.1415926, 0, 78) dogs:set("foo", nil) end val, flags = dogs:get("foo") ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } } --- request GET /t --- response_body value type: nil value: nil flags: nil --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):6 loop\]/ --- no_error_log [error] -- NYI: === TEST 18: safe set a number value --- config location = /t { content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) dogs:flush_all() dogs:flush_expired() for i = 1, 100 do dogs:safe_set("foo", 3.1415926, 0, 78) end val, flags = dogs:get("foo") ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } } --- request GET /t --- response_body value type: number value: 3.1415926 flags: 78 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):8 loop\]/ --- no_error_log [error] -- NYI: === TEST 19: add a string value --- config location = /t { content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) dogs:flush_all() local ok, err, forcible for i = 1, 100 do ok, err, forcible = dogs:add("foo" .. i, "bar", 0, 72) end if not ok then ngx.say("failed to set: ", err) return end val, flags = dogs:get("foo100") ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } } --- request GET /t --- response_body value type: string value: bar flags: 72 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):8 loop\]/ --- no_error_log [error] -- NYI: === TEST 20: safe add a string value --- config location = /t { content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) dogs:flush_all() dogs:flush_expired() local ok, err, forcible for i = 1, 100 do ok, err, forcible = dogs:safe_add("foo" .. i, "bar", 0, 72) end if not ok then ngx.say("failed to set: ", err) return end val, flags = dogs:get("foo100") ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } } --- request GET /t --- response_body value type: string value: bar flags: 72 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):9 loop\]/ --- no_error_log [error] -- NYI: === TEST 21: replace a string value --- config location = /t { content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) dogs:set("foo", "hello") local ok, err, forcible for i = 1, 100 do ok, err, forcible = dogs:replace("foo", "bar" .. i, 0, 72) end if not ok then ngx.say("failed to set: ", err) return end val, flags = dogs:get("foo") ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } } --- request GET /t --- response_body value type: string value: bar100 flags: 72 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):8 loop\]/ --- no_error_log [error] -- NYI: === TEST 22: set a number value and delete --- config location = /t { content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) for i = 1, 150 do dogs:set("foo", 3.1415926, 0, 78) dogs:delete("foo") end val, flags = dogs:get("foo") ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } } --- request GET /t --- response_body value type: nil value: nil flags: nil --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):6 loop\]/ --- no_error_log [error] -- NYI: stitch === TEST 23: set nil key --- config location = /t { content_by_lua_block { local val, flags local dogs = ngx.shared.dogs local ok, err = dogs:set(nil, "bar") if not ok then ngx.say("failed to set: ", err) end } } --- request GET /t --- response_body failed to set: nil key --- no_error_log [error] [alert] [crit] === TEST 24: get nil key --- config location = /t { content_by_lua_block { local val, flags local dogs = ngx.shared.dogs local value, err = dogs:get(nil, "bar") if not ok then ngx.say("failed to get: ", err) end } } --- request GET /t --- response_body failed to get: nil key --- no_error_log [error] [alert] [crit] === TEST 25: get stale key --- config location = /t { content_by_lua_block { local val, flags local dogs = ngx.shared.dogs local value, err = dogs:get_stale(nil, "bar") if not ok then ngx.say("failed to get stale: ", err) end } } --- request GET /t --- response_body failed to get stale: nil key --- no_error_log [error] [alert] [crit] === TEST 26: incr key --- config location = /t { content_by_lua_block { local val, flags local dogs = ngx.shared.dogs local value, err = dogs:incr(nil, 32) if not value then ngx.say("failed to incr: ", err) end } } --- request GET /t --- response_body failed to incr: nil key --- no_error_log [error] [alert] [crit] === TEST 27: flush_all --- config location = /t { content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs dogs:set("foo", "bah") -- local cd = ffi.cast("void *", dogs) for i = 1, 150 do dogs:flush_all() end val, flags = dogs:get("foo") ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } } --- request GET /t --- response_body value type: nil value: nil flags: nil --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):7 loop\]/ --- no_error_log [error] -- NYI: stitch === TEST 28: incr, value is not number --- config location = /t { content_by_lua_block { local val, flags local dogs = ngx.shared.dogs local value, err = dogs:incr("foo", "bar") if not value then ngx.say("failed to incr: ", err) end } } --- request GET /t --- error_code: 500 --- response_body_like: 500 --- error_log cannot convert 'nil' to 'double' --- no_error_log [alert] [crit] === TEST 29: incr with init --- config location = /t { content_by_lua_block { local val, flags local dogs = ngx.shared.dogs dogs:flush_all() local value, err = dogs:incr("foo", 10) if not value then ngx.say("failed to incr: ", err) end local value, err, forcible = dogs:incr("foo", 10, 10) if not value then ngx.say("failed to incr: ", err) return end ngx.say("incr ok, value: ", value, ", forcible: ", forcible) } } --- request GET /t --- response_body failed to incr: not found incr ok, value: 20, forcible: false --- no_error_log [error] [alert] [crit] === TEST 30: incr, init is not number --- config location = /t { content_by_lua_block { local val, flags local dogs = ngx.shared.dogs local value, err = dogs:incr("foo", 10, "bar") if not ok then ngx.say("failed to incr: ", err) end } } --- request GET /t --- error_code: 500 --- response_body_like: 500 --- error_log number expected, got string --- no_error_log [alert] [crit] === TEST 31: capacity --- config location = /t { content_by_lua_block { local cats = ngx.shared.cats local capacity = cats:capacity() ngx.say("capacity type: ", type(capacity)) ngx.say("capacity: ", capacity) } } --- request GET /t --- response_body capacity type: number capacity: 16384 --- no_error_log [error] [alert] [crit] === TEST 32: free_space, empty (16k zone) --- skip_nginx: 5: < 1.11.7 --- config location = /t { content_by_lua_block { local cats = ngx.shared.cats cats:flush_all() cats:flush_expired() local free_page_bytes = cats:free_space() ngx.say("free_page_bytes type: ", type(free_page_bytes)) ngx.say("free_page_bytes: ", free_page_bytes) } } --- request GET /t --- response_body free_page_bytes type: number free_page_bytes: 4096 --- no_error_log [error] [alert] [crit] === TEST 33: free_space, empty (100k zone) --- skip_nginx: 5: < 1.11.7 --- config location = /t { content_by_lua_block { local birds = ngx.shared.birds birds:flush_all() birds:flush_expired() local free_page_bytes = birds:free_space() ngx.say("free_page_bytes type: ", type(free_page_bytes)) ngx.say("free_page_bytes: ", free_page_bytes) } } --- request GET /t --- response_body_like chomp \Afree_page_bytes type: number free_page_bytes: (?:90112|94208) \z --- no_error_log [error] [alert] [crit] === TEST 34: free_space, about half full, one page left --- skip_nginx: 5: < 1.11.7 --- config location = /t { content_by_lua_block { local cats = ngx.shared.cats cats:flush_all() cats:flush_expired() for i = 1, 31 do local key = string.format("key%05d", i) local val = string.format("val%05d", i) local success, err, forcible = cats:set(key, val) if err ~= nil then ngx.say(string.format("got error, i=%d, err=%s", i, err)) end if forcible then ngx.say(string.format("got forcible, i=%d", i)) end if not success then ngx.say(string.format("got not success, i=%d", i)) end end local free_page_bytes = cats:free_space() ngx.say("free_page_bytes type: ", type(free_page_bytes)) ngx.say("free_page_bytes: ", free_page_bytes) } } --- request GET /t --- response_body free_page_bytes type: number free_page_bytes: 4096 --- no_error_log [error] [alert] [crit] === TEST 35: free_space, about half full, no page left --- skip_nginx: 5: < 1.11.7 --- config location = /t { content_by_lua_block { local cats = ngx.shared.cats cats:flush_all() cats:flush_expired() for i = 1, 32 do local key = string.format("key%05d", i) local val = string.format("val%05d", i) local success, err, forcible = cats:set(key, val) if err ~= nil then ngx.say(string.format("got error, i=%d, err=%s", i, err)) end if forcible then ngx.say(string.format("got forcible, i=%d", i)) end if not success then ngx.say(string.format("got not success, i=%d", i)) end end local free_page_bytes = cats:free_space() ngx.say("free_page_bytes type: ", type(free_page_bytes)) ngx.say("free_page_bytes: ", free_page_bytes) } } --- request GET /t --- response_body_like chomp \Afree_page_bytes type: number free_page_bytes: (?:0|4096) \z --- no_error_log [error] [alert] [crit] === TEST 36: free_space, full --- skip_nginx: 5: < 1.11.7 --- config location = /t { content_by_lua_block { local cats = ngx.shared.cats cats:flush_all() cats:flush_expired() for i = 1, 63 do local key = string.format("key%05d", i) local val = string.format("val%05d", i) local success, err, forcible = cats:set(key, val) if err ~= nil then ngx.say(string.format("got error, i=%d, err=%s", i, err)) end if forcible then ngx.say(string.format("got forcible, i=%d", i)) end if not success then ngx.say(string.format("got not success, i=%d", i)) end end local free_page_bytes = cats:free_space() ngx.say("free_page_bytes type: ", type(free_page_bytes)) ngx.say("free_page_bytes: ", free_page_bytes) } } --- request GET /t --- response_body free_page_bytes type: number free_page_bytes: 0 --- no_error_log [error] [alert] [crit] === TEST 37: free_space, got forcible --- skip_nginx: 5: < 1.11.7 --- config location = /t { content_by_lua_block { local cats = ngx.shared.cats cats:flush_all() cats:flush_expired() for i = 1, 64 do local key = string.format("key%05d", i) local val = string.format("val%05d", i) local success, err, forcible = cats:set(key, val) if err ~= nil then ngx.say(string.format("got error, i=%d, err=%s", i, err)) end if forcible then ngx.say(string.format("got forcible, i=%d", i)) end if not success then ngx.say(string.format("got not success, i=%d", i)) end end local free_page_bytes = cats:free_space() ngx.say("free_page_bytes type: ", type(free_page_bytes)) ngx.say("free_page_bytes: ", free_page_bytes) } } --- request GET /t --- response_body_like chomp \A(?:got forcible, i=64 )?free_page_bytes type: number free_page_bytes: 0 \z --- no_error_log [error] [alert] [crit] === TEST 38: free_space, full (100k) --- skip_nginx: 5: < 1.11.7 --- config location = /t { content_by_lua_block { local birds = ngx.shared.birds birds:flush_all() birds:flush_expired() for i = 1, 1000 do local key = string.format("key%05d", i) local val = string.format("val%05d", i) local ok, err, forcible = birds:set(key, val) if err ~= nil then ngx.say(string.format("got error, i=%d, err=%s", i, err)) end if forcible then ngx.say(string.format("got forcible, i=%d", i)) break end if not ok then ngx.say(string.format("got not ok, i=%d", i)) break end end local free_page_bytes = birds:free_space() ngx.say("free_page_bytes type: ", type(free_page_bytes)) ngx.say("free_page_bytes: ", free_page_bytes) } } --- request GET /t --- response_body_like chomp \A(?:got forcible, i=736 )?free_page_bytes type: number free_page_bytes: (?:0|32768) \z --- no_error_log [error] [alert] [crit] === TEST 39: incr bad init_ttl argument --- config location = /t { content_by_lua_block { local dogs = ngx.shared.dogs local pok, err = pcall(dogs.incr, dogs, "foo", 1, 0, -1) if not pok then ngx.say("not ok: ", err) return end ngx.say("ok") } } --- request GET /t --- response_body not ok: bad "init_ttl" argument --- no_error_log [error] [alert] [crit] === TEST 40: incr init_ttl argument is not a number --- config location = /t { content_by_lua_block { local dogs = ngx.shared.dogs local pok, err = pcall(dogs.incr, dogs, "foo", 1, 0, "bar") if not pok then ngx.say("not ok: ", err) return end ngx.say("ok") } } --- request GET /t --- response_body not ok: bad init_ttl arg: number expected, got string --- no_error_log [error] [alert] [crit] === TEST 41: incr init_ttl argument without init --- config location = /t { content_by_lua_block { local dogs = ngx.shared.dogs local pok, err = pcall(dogs.incr, dogs, "foo", 1, nil, 0.01) if not pok then ngx.say("not ok: ", err) return end ngx.say("ok") } } --- request GET /t --- response_body not ok: must provide "init" when providing "init_ttl" --- no_error_log [error] [alert] [crit] === TEST 42: incr key with init_ttl (key exists) --- config location = /t { content_by_lua_block { local dogs = ngx.shared.dogs dogs:set("foo", 32) local res, err = dogs:incr("foo", 10502, 0, 0.01) ngx.say("incr: ", res, " ", err) ngx.say("foo = ", dogs:get("foo")) ngx.update_time() ngx.sleep(0.02) ngx.say("foo after incr init_ttl = ", dogs:get("foo")) } } --- request GET /t --- response_body incr: 10534 nil foo = 10534 foo after incr init_ttl = 10534 --- no_error_log [error] [alert] [crit] === TEST 43: incr key with init and init_ttl (key not exists) --- config location = /t { content_by_lua_block { local dogs = ngx.shared.dogs dogs:flush_all() local res, err = dogs:incr("foo", 10502, 1, 0.01) ngx.say("incr: ", res, " ", err) ngx.say("foo = ", dogs:get("foo")) ngx.update_time() ngx.sleep(0.02) ngx.say("foo after init_ttl = ", dogs:get("foo")) } } --- request GET /t --- response_body incr: 10503 nil foo = 10503 foo after init_ttl = nil --- no_error_log [error] [alert] [crit] === TEST 44: incr key with init and init_ttl as string (key not exists) --- config location = /t { content_by_lua_block { local dogs = ngx.shared.dogs dogs:flush_all() local res, err = dogs:incr("foo", 10502, 1, "0.01") ngx.say("incr: ", res, " ", err) ngx.say("foo = ", dogs:get("foo")) ngx.update_time() ngx.sleep(0.02) ngx.say("foo after init_ttl = ", dogs:get("foo")) } } --- request GET /t --- response_body incr: 10503 nil foo = 10503 foo after init_ttl = nil --- no_error_log [error] [alert] [crit] === TEST 45: incr key with init and init_ttl (key expired and size matched) --- config location = /t { content_by_lua_block { local dogs = ngx.shared.dogs for i = 1, 20 do dogs:set("bar" .. i, i, 0.02) end dogs:set("foo", 32, 0.02) ngx.update_time() ngx.sleep(0.03) local res, err = dogs:incr("foo", 10502, 0, 0.01) ngx.say("incr: ", res, " ", err) ngx.say("foo = ", dogs:get("foo")) ngx.update_time() ngx.sleep(0.02) ngx.say("foo after init_ttl = ", dogs:get("foo")) } } --- request GET /t --- response_body incr: 10502 nil foo = 10502 foo after init_ttl = nil --- no_error_log [error] [alert] [crit] === TEST 46: incr key with init and init_ttl (forcibly override other valid entries) --- config location = /t { content_by_lua_block { local dogs = ngx.shared.dogs dogs:flush_all() local long_prefix = string.rep("1234567890", 100) for i = 1, 1000 do local success, err, forcible = dogs:set(long_prefix .. i, i) if forcible then dogs:delete(long_prefix .. i) break end end local res, err, forcible = dogs:incr(long_prefix .. "bar", 10502, 0) ngx.say("incr: ", res, " ", err, " ", forcible) local res, err, forcible = dogs:incr(long_prefix .. "foo", 10502, 0, 0.01) ngx.say("incr: ", res, " ", err, " ", forcible) ngx.say("foo = ", dogs:get(long_prefix .. "foo")) ngx.update_time() ngx.sleep(0.02) ngx.say("foo after init_ttl = ", dogs:get("foo")) } } --- request GET /t --- response_body incr: 10502 nil false incr: 10502 nil true foo = 10502 foo after init_ttl = nil --- no_error_log [error] [alert] [crit] === TEST 47: exptime uses long type to avoid overflow in set() + ttl() --- config location = /t { content_by_lua_block { local dogs = ngx.shared.dogs dogs:flush_all() local ok, err = dogs:set("huge_ttl", true, 2 ^ 31) if not ok then ngx.say("err setting: ", err) return end local ttl, err = dogs:ttl("huge_ttl") if not ttl then ngx.say("err retrieving ttl: ", err) return end ngx.say("ttl: ", ttl) } } --- request GET /t --- response_body ttl: 2147483648 --- no_error_log [error] [alert] [crit] === TEST 48: exptime uses long type to avoid overflow in expire() + ttl() --- config location = /t { content_by_lua_block { local dogs = ngx.shared.dogs dogs:flush_all() local ok, err = dogs:set("updated_huge_ttl", true) if not ok then ngx.say("err setting: ", err) return end local ok, err = dogs:expire("updated_huge_ttl", 2 ^ 31) if not ok then ngx.say("err expire: ", err) return end local ttl, err = dogs:ttl("updated_huge_ttl") if not ttl then ngx.say("err retrieving ttl: ", err) return end ngx.say("ttl: ", ttl) } } --- request GET /t --- response_body ttl: 2147483648 --- no_error_log [error] [alert] [crit] === TEST 49: init_ttl uses long type to avoid overflow in incr() + ttl() --- config location = /t { content_by_lua_block { local dogs = ngx.shared.dogs dogs:flush_all() local ok, err = dogs:incr("incr_huge_ttl", 1, 0, 2 ^ 31) if not ok then ngx.say("err incr: ", err) return end local ttl, err = dogs:ttl("incr_huge_ttl") if not ttl then ngx.say("err retrieving ttl: ", err) return end ngx.say("ttl: ", ttl) } } --- request GET /t --- response_body ttl: 2147483648 --- no_error_log [error] [alert] [crit] === TEST 50: check zone argument --- config location = /t { content_by_lua_block { local function check_in_pcall(f, ...) local ok, err = pcall(f, ...) if not ok then ngx.say(err) else ngx.say("ok") end end local dogs = ngx.shared.dogs check_in_pcall(dogs.set, dogs, 'k', 1) check_in_pcall(dogs.set, 'k', 1) check_in_pcall(dogs.set, {1}, 'k', 1) check_in_pcall(dogs.set, {ngx.null}, 'k', 1) } } --- request GET /t --- response_body ok bad "zone" argument bad "zone" argument bad "zone" argument --- no_error_log [error] [alert] [crit] === TEST 51: free_space, not supported in NGINX < 1.11.7 --- skip_nginx: 5: >= 1.11.7 --- config location = /t { content_by_lua_block { local birds = ngx.shared.birds local pok, perr = pcall(function () birds:free_space() end) if not pok then ngx.say(perr) end } } --- request GET /t --- response_body_like content_by_lua\(nginx\.conf:\d+\):\d+: 'shm:free_space\(\)' not supported in NGINX < 1.11.7 --- no_error_log [error] [alert] [crit] lua-resty-core-0.1.31/t/socket-tcp-getoption.t000066400000000000000000000140701474236722600212000ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; repeat_each(2); plan tests => repeat_each() * (blocks() * 2 + 7); #worker_connections(1024); #no_diff(); no_long_string(); run_tests(); __DATA__ === TEST 1: no parameters. --- config set $port $TEST_NGINX_SERVER_PORT; location /t { content_by_lua_block { require "resty.core.socket" local port = ngx.var.port local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", port) if not ok then ngx.say("failed to connect: ", err) return end ok, err = sock:getoption() if not ok then ngx.say("getoption failed: ", err) return end sock:close() } } --- request GET /t --- response_body getoption failed: missing the "option" argument --- no_error_log [error] === TEST 2: unsuppotrted option name. --- config set $port $TEST_NGINX_SERVER_PORT; location /t { content_by_lua_block { require "resty.core.socket" local port = ngx.var.port local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", port) if not ok then ngx.say("failed to connect: ", err) return end local sndbuf, err = sock:getoption("abc") if not sndbuf then ngx.say("getoption abc failed: ", err) return end sock:close() } } --- request GET /t --- response_body getoption abc failed: unsupported option abc --- no_error_log [error] === TEST 3: getoption before calling connect. --- config set $port $TEST_NGINX_SERVER_PORT; location /t { content_by_lua_block { require "resty.core.socket" local sock = ngx.socket.tcp() local sndbuf, err = sock:getoption("sndbuf") if not sndbuf then ngx.say("getoption sndbuf failed: ", err) return end sock:close() } } --- request GET /t --- error_code: 500 --- error_log socket is never created nor connected === TEST 4: get keepalive. --- config set $port $TEST_NGINX_SERVER_PORT; location /t { content_by_lua_block { require "resty.core.socket" local port = ngx.var.port local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", port) if not ok then ngx.say("failed to connect: ", err) return end local val, err = sock:getoption("keepalive") if not val then ngx.say("getoption keepalive failed: ", err) return end ngx.say("keepalive: ", val) sock:close() } } --- request GET /t --- response_body_like eval qr/keepalive: \d+/ --- no_error_log [error] === TEST 5: get reuseaddr. --- config set $port $TEST_NGINX_SERVER_PORT; location /t { content_by_lua_block { require "resty.core.socket" local port = ngx.var.port local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", port) if not ok then ngx.say("failed to connect: ", err) return end local val, err = sock:getoption("reuseaddr") if not val then ngx.say("getoption reuseaddr failed: ", err) return end ngx.say("reuseaddr: ", val) sock:close() } } --- request GET /t --- response_body_like eval qr/reuseaddr: \d+/ --- no_error_log [error] === TEST 6: get tcp-nodelay. --- config set $port $TEST_NGINX_SERVER_PORT; location /t { content_by_lua_block { require "resty.core.socket" local port = ngx.var.port local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", port) if not ok then ngx.say("failed to connect: ", err) return end local val, err = sock:getoption("tcp-nodelay") if not val then ngx.say("getoption tcp-nodelay failed: ", err) return end ngx.say("tcp-nodelay: ", val) sock:close() } } --- request GET /t --- response_body_like eval qr/tcp-nodelay: \d+/ --- no_error_log [error] === TEST 7: get sndbuf. --- config set $port $TEST_NGINX_SERVER_PORT; location /t { content_by_lua_block { require "resty.core.socket" local port = ngx.var.port local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", port) if not ok then ngx.say("failed to connect: ", err) return end local val, err = sock:getoption("sndbuf") if not val then ngx.say("getoption sndbuf failed: ", err) return end ngx.say("sndbuf: ", val) sock:close() } } --- request GET /t --- response_body_like eval qr/sndbuf: \d+/ --- no_error_log [error] === TEST 8: get rcvbuf. --- config set $port $TEST_NGINX_SERVER_PORT; location /t { content_by_lua_block { require "resty.core.socket" local port = ngx.var.port local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", port) if not ok then ngx.say("failed to connect: ", err) return end local val, err = sock:getoption("rcvbuf") if not val then ngx.say("getoption rcvbuf failed: ", err) return end ngx.say("rcvbuf: ", val) sock:close() } } --- request GET /t --- response_body_like eval qr/rcvbuf: \d+/ --- no_error_log [error] lua-resty-core-0.1.31/t/socket-tcp-setoption.t000066400000000000000000000521441474236722600212200ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; repeat_each(2); plan tests => repeat_each() * (blocks() * 3 - 1); #worker_connections(1024); #no_diff(); no_long_string(); run_tests(); __DATA__ === TEST 1: no parameters. --- config set $port $TEST_NGINX_SERVER_PORT; location /t { content_by_lua_block { require "resty.core.socket" local port = ngx.var.port local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", port) if not ok then ngx.say("failed to connect: ", err) return end ok, err = sock:setoption() if not ok then ngx.say("setoption failed: ", err) end ok, err = sock:setoption("sndbuf") if not ok then ngx.say("setoption failed: ", err) end sock:close() } } --- request GET /t --- response_body setoption failed: missing the "option" argument setoption failed: missing the "value" argument --- no_error_log [error] === TEST 2: unsuppotrted option name. --- config set $port $TEST_NGINX_SERVER_PORT; location /t { content_by_lua_block { require "resty.core.socket" local port = ngx.var.port local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", port) if not ok then ngx.say("failed to connect: ", err) return end local ok, err = sock:setoption("abc", 123) if not ok then ngx.say("setoption abc failed: ", err) return end sock:close() } } --- request GET /t --- response_body setoption abc failed: unsupported option abc --- no_error_log [error] === TEST 3: getoption before calling connect. --- config set $port $TEST_NGINX_SERVER_PORT; location /t { content_by_lua_block { require "resty.core.socket" local sock = ngx.socket.tcp() local sndbuf, err = sock:setoption("sndbuf", 4000) if not sndbuf then ngx.say("getoption sndbuf failed: ", err) return end sock:close() } } --- request GET /t --- error_code: 500 --- error_log socket is never created nor connected === TEST 4: keepalive set by 1/0. --- config set $port $TEST_NGINX_SERVER_PORT; location /t { content_by_lua_block { require "resty.core.socket" local port = ngx.var.port local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", port) if not ok then ngx.say("failed to connect: ", err) return end local v1, err = sock:getoption("keepalive") if not v1 then ngx.say("get default keepalive failed: ", err) return end ok, err = sock:setoption("keepalive", 1) if not ok then ngx.say("enabling keepalive failed: ", err) return end local v2, err = sock:getoption("keepalive") if not v2 then ngx.say("get enabled keepalive failed: ", err) return end ngx.say("keepalive changes from ", v1, " to ", v2) ok, err = sock:setoption("keepalive", 0) if not ok then ngx.say("disable keepalive failed: ", err) return end local v3, err = sock:getoption("keepalive") if not v3 then ngx.say("get disabled keepalive failed: ", err) return end ngx.say("keepalive changes from ", v2, " to ", v3) sock:close() } } --- request GET /t --- response_body keepalive changes from 0 to 1 keepalive changes from 1 to 0 --- no_error_log [error] === TEST 5: keepalive set by true/false. --- config set $port $TEST_NGINX_SERVER_PORT; location /t { content_by_lua_block { require "resty.core.socket" local port = ngx.var.port local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", port) if not ok then ngx.say("failed to connect: ", err) return end local v1, err = sock:getoption("keepalive") if not v1 then ngx.say("get default keepalive failed: ", err) return end ok, err = sock:setoption("keepalive", true) if not ok then ngx.say("enabling keepalive failed: ", err) return end local v2, err = sock:getoption("keepalive") if not v2 then ngx.say("get enabled keepalive failed: ", err) return end ngx.say("keepalive changes from ", v1, " to ", v2) ok, err = sock:setoption("keepalive", false) if not ok then ngx.say("disable keepalive failed: ", err) return end local v3, err = sock:getoption("keepalive") if not v3 then ngx.say("get disabled keepalive failed: ", err) return end ngx.say("keepalive changes from ", v2, " to ", v3) sock:close() } } --- request GET /t --- response_body keepalive changes from 0 to 1 keepalive changes from 1 to 0 --- no_error_log [error] === TEST 6: keepalive set by ~0/0. --- config set $port $TEST_NGINX_SERVER_PORT; location /t { content_by_lua_block { require "resty.core.socket" local port = ngx.var.port local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", port) if not ok then ngx.say("failed to connect: ", err) return end local v1, err = sock:getoption("keepalive") if not v1 then ngx.say("get default keepalive failed: ", err) return end ok, err = sock:setoption("keepalive", 10) if not ok then ngx.say("enabling keepalive failed: ", err) return end local v2, err = sock:getoption("keepalive") if not v2 then ngx.say("get enabled keepalive failed: ", err) return end ngx.say("keepalive changes from ", v1, " to ", v2) ok, err = sock:setoption("keepalive", 0) if not ok then ngx.say("disable keepalive failed: ", err) return end local v3, err = sock:getoption("keepalive") if not v3 then ngx.say("get disabled keepalive failed: ", err) return end ngx.say("keepalive changes from ", v2, " to ", v3) sock:close() } } --- request GET /t --- response_body keepalive changes from 0 to 1 keepalive changes from 1 to 0 --- no_error_log [error] === TEST 7: reuseaddr set by 1/0. --- config set $port $TEST_NGINX_SERVER_PORT; location /t { content_by_lua_block { require "resty.core.socket" local port = ngx.var.port local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", port) if not ok then ngx.say("failed to connect: ", err) return end local v1, err = sock:getoption("reuseaddr") if not v1 then ngx.say("get default reuseaddr failed: ", err) return end ok, err = sock:setoption("reuseaddr", 1) if not ok then ngx.say("enabling reuseaddr failed: ", err) return end local v2, err = sock:getoption("reuseaddr") if not v2 then ngx.say("get enabled reuseaddr failed: ", err) return end ngx.say("reuseaddr changes from ", v1, " to ", v2) ok, err = sock:setoption("reuseaddr", 0) if not ok then ngx.say("disable reuseaddr failed: ", err) return end local v3, err = sock:getoption("reuseaddr") if not v3 then ngx.say("get disabled reuseaddr failed: ", err) return end ngx.say("reuseaddr changes from ", v2, " to ", v3) sock:close() } } --- request GET /t --- response_body reuseaddr changes from 0 to 1 reuseaddr changes from 1 to 0 --- no_error_log [error] === TEST 8: reuseaddr set by true/false. --- config set $port $TEST_NGINX_SERVER_PORT; location /t { content_by_lua_block { require "resty.core.socket" local port = ngx.var.port local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", port) if not ok then ngx.say("failed to connect: ", err) return end local v1, err = sock:getoption("reuseaddr") if not v1 then ngx.say("get default reuseaddr failed: ", err) return end ok, err = sock:setoption("reuseaddr", true) if not ok then ngx.say("enabling reuseaddr failed: ", err) return end local v2, err = sock:getoption("reuseaddr") if not v2 then ngx.say("get enabled reuseaddr failed: ", err) return end ngx.say("reuseaddr changes from ", v1, " to ", v2) ok, err = sock:setoption("reuseaddr", false) if not ok then ngx.say("disable reuseaddr failed: ", err) return end local v3, err = sock:getoption("reuseaddr") if not v3 then ngx.say("get disabled reuseaddr failed: ", err) return end ngx.say("reuseaddr changes from ", v2, " to ", v3) sock:close() } } --- request GET /t --- response_body reuseaddr changes from 0 to 1 reuseaddr changes from 1 to 0 --- no_error_log [error] === TEST 9: reuseaddr set by ~0/0. --- config set $port $TEST_NGINX_SERVER_PORT; location /t { content_by_lua_block { require "resty.core.socket" local port = ngx.var.port local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", port) if not ok then ngx.say("failed to connect: ", err) return end local v1, err = sock:getoption("reuseaddr") if not v1 then ngx.say("get default reuseaddr failed: ", err) return end ok, err = sock:setoption("reuseaddr", 10) if not ok then ngx.say("enabling reuseaddr failed: ", err) return end local v2, err = sock:getoption("reuseaddr") if not v2 then ngx.say("get enabled reuseaddr failed: ", err) return end ngx.say("reuseaddr changes from ", v1, " to ", v2) ok, err = sock:setoption("reuseaddr", 0) if not ok then ngx.say("disable reuseaddr failed: ", err) return end local v3, err = sock:getoption("reuseaddr") if not v3 then ngx.say("get disabled reuseaddr failed: ", err) return end ngx.say("reuseaddr changes from ", v2, " to ", v3) sock:close() } } --- request GET /t --- response_body reuseaddr changes from 0 to 1 reuseaddr changes from 1 to 0 --- no_error_log [error] === TEST 10: tcp-nodelay set by 1/0. --- config set $port $TEST_NGINX_SERVER_PORT; location /t { content_by_lua_block { require "resty.core.socket" local port = ngx.var.port local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", port) if not ok then ngx.say("failed to connect: ", err) return end local v1, err = sock:getoption("tcp-nodelay") if not v1 then ngx.say("get default tcp-nodelay failed: ", err) return end ok, err = sock:setoption("tcp-nodelay", 1) if not ok then ngx.say("enabling tcp-nodelay failed: ", err) return end local v2, err = sock:getoption("tcp-nodelay") if not v2 then ngx.say("get enabled tcp-nodelay failed: ", err) return end ngx.say("tcp-nodelay changes from ", v1, " to ", v2) ok, err = sock:setoption("tcp-nodelay", 0) if not ok then ngx.say("disable tcp-nodelay failed: ", err) return end local v3, err = sock:getoption("tcp-nodelay") if not v3 then ngx.say("get disabled tcp-nodelay failed: ", err) return end ngx.say("tcp-nodelay changes from ", v2, " to ", v3) sock:close() } } --- request GET /t --- response_body tcp-nodelay changes from 0 to 1 tcp-nodelay changes from 1 to 0 --- no_error_log [error] === TEST 11: tcp-nodelay set by true/false. --- config set $port $TEST_NGINX_SERVER_PORT; location /t { content_by_lua_block { require "resty.core.socket" local port = ngx.var.port local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", port) if not ok then ngx.say("failed to connect: ", err) return end local v1, err = sock:getoption("tcp-nodelay") if not v1 then ngx.say("get default tcp-nodelay failed: ", err) return end ok, err = sock:setoption("tcp-nodelay", true) if not ok then ngx.say("enabling tcp-nodelay failed: ", err) return end local v2, err = sock:getoption("tcp-nodelay") if not v2 then ngx.say("get enabled tcp-nodelay failed: ", err) return end ngx.say("tcp-nodelay changes from ", v1, " to ", v2) ok, err = sock:setoption("tcp-nodelay", false) if not ok then ngx.say("disable tcp-nodelay failed: ", err) return end local v3, err = sock:getoption("tcp-nodelay") if not v3 then ngx.say("get disabled tcp-nodelay failed: ", err) return end ngx.say("tcp-nodelay changes from ", v2, " to ", v3) sock:close() } } --- request GET /t --- response_body tcp-nodelay changes from 0 to 1 tcp-nodelay changes from 1 to 0 --- no_error_log [error] === TEST 12: tcp-nodelay set by ~0/0. --- config set $port $TEST_NGINX_SERVER_PORT; location /t { content_by_lua_block { require "resty.core.socket" local port = ngx.var.port local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", port) if not ok then ngx.say("failed to connect: ", err) return end local v1, err = sock:getoption("tcp-nodelay") if not v1 then ngx.say("get default tcp-nodelay failed: ", err) return end ok, err = sock:setoption("tcp-nodelay", 10) if not ok then ngx.say("enabling tcp-nodelay failed: ", err) return end local v2, err = sock:getoption("tcp-nodelay") if not v2 then ngx.say("get enabled tcp-nodelay failed: ", err) return end ngx.say("tcp-nodelay changes from ", v1, " to ", v2) ok, err = sock:setoption("tcp-nodelay", 0) if not ok then ngx.say("disable tcp-nodelay failed: ", err) return end local v3, err = sock:getoption("tcp-nodelay") if not v3 then ngx.say("get disabled tcp-nodelay failed: ", err) return end ngx.say("tcp-nodelay changes from ", v2, " to ", v3) sock:close() } } --- request GET /t --- response_body tcp-nodelay changes from 0 to 1 tcp-nodelay changes from 1 to 0 --- no_error_log [error] === TEST 13: sndbuf. --- config set $port $TEST_NGINX_SERVER_PORT; location /t { content_by_lua_block { require "resty.core.socket" local port = ngx.var.port local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", port) if not ok then ngx.say("failed to connect: ", err) return end local v1, err = sock:getoption("sndbuf") if not v1 then ngx.say("get default sndbuf failed: ", err) return end ok, err = sock:setoption("sndbuf", 4096) if not ok then ngx.say("enabling sndbuf failed: ", err) return end local v2, err = sock:getoption("sndbuf") if not v2 then ngx.say("get enabled sndbuf failed: ", err) return end ngx.say("sndbuf changes from ", v1, " to ", v2) sock:close() } } --- request GET /t --- response_body_like eval qr/\Asndbuf changes from \d+ to \d+\n\z/ --- no_error_log [error] === TEST 14: rcvbuf. --- config set $port $TEST_NGINX_SERVER_PORT; location /t { content_by_lua_block { require "resty.core.socket" local port = ngx.var.port local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", port) if not ok then ngx.say("failed to connect: ", err) return end local v1, err = sock:getoption("rcvbuf") if not v1 then ngx.say("get default rcvbuf failed: ", err) return end ok, err = sock:setoption("rcvbuf", 4096) if not ok then ngx.say("enabling rcvbuf failed: ", err) return end local v2, err = sock:getoption("rcvbuf") if not v2 then ngx.say("get enabled rcvbuf failed: ", err) return end ngx.say("rcvbuf changes from ", v1, " to ", v2) sock:close() } } --- request GET /t --- response_body_like eval qr/\Arcvbuf changes from \d+ to \d+\n\z/ --- no_error_log [error] === TEST 15: strerr. --- config set $port $TEST_NGINX_SERVER_PORT; location /t { content_by_lua_block { require "resty.core.socket" local ffi = require "ffi" local base = require "resty.core.base" ffi.cdef[[ typedef struct ngx_http_lua_socket_tcp_upstream_s ngx_http_lua_socket_tcp_upstream_t; int ngx_http_lua_ffi_socket_tcp_hack_fd( ngx_http_lua_socket_tcp_upstream_t *u, int fd, unsigned char *errstr, size_t *errlen); ]] local port = ngx.var.port local sock = ngx.socket.tcp() local ok, err = sock:connect("127.0.0.1", port) if not ok then ngx.say("failed to connect: ", err) return end local errstr = base.get_string_buf(4096) local errlen = base.get_size_ptr() errlen[0] = 4096 local SOCKET_CTX_INDEX = 1 local tcpsock = sock[SOCKET_CTX_INDEX] -- hack the fd of the socket local bad_fd = 12345 local realfd = ffi.C.ngx_http_lua_ffi_socket_tcp_hack_fd(tcpsock, bad_fd, errstr, errlen) if realfd == -1 then ngx.say("hack fd failed: ", ffi.string(err, errlen[0])) return end ok, err = sock:setoption("rcvbuf", 4096) if not ok then ngx.say("enabling rcvbuf failed: ", err) -- restore the fd of the socket ffi.C.ngx_http_lua_ffi_socket_tcp_hack_fd(tcpsock, realfd, errstr, errlen) return end } } --- request GET /t --- response_body_like eval qr/\Aenabling rcvbuf failed: [\/\s\w]+\n\z/ --- no_error_log [error] lua-resty-core-0.1.31/t/ssl-client-hello.t000066400000000000000000000661161474236722600203040ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(10140); #workers(1); #log_level('warn'); repeat_each(2); # All these tests need to have new openssl my $NginxBinary = $ENV{'TEST_NGINX_BINARY'} || 'nginx'; my $openssl_version = eval { `$NginxBinary -V 2>&1` }; if ($openssl_version =~ m/built with OpenSSL (0\S*|1\.0\S*|1\.1\.0\S*)/) { plan(skip_all => "too old OpenSSL, need 1.1.1, was $1"); } else { plan tests => repeat_each() * (blocks() * 6 - 2) - 4; } no_long_string(); #no_diff(); env_to_nginx("PATH=" . $ENV{'PATH'}); $ENV{TEST_NGINX_LUA_PACKAGE_PATH} = "$t::TestCore::lua_package_path"; $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); run_tests(); __DATA__ === TEST 1: read SNI name via ssl.clienthello.get_client_hello_server_name() --- skip_nginx: 6: < 1.19.9 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_client_hello_by_lua_block { local ssl_clt = require "ngx.ssl.clienthello" print("read SNI name from Lua: ", ssl_clt.get_client_hello_server_name()) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx received: Content-Type: text/plain received: Content-Length: 4 received: Connection: close received: received: foo close: 1 nil --- error_log lua ssl server name: "test.com" read SNI name from Lua: test.com --- no_error_log [error] [alert] === TEST 2: read SNI name via ssl.clienthello.get_client_hello_server_name() when no SNI name specified --- skip_nginx: 6: < 1.19.9 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen 127.0.0.2:$TEST_NGINX_RAND_PORT_1 ssl; server_name test.com; ssl_client_hello_by_lua_block { local ssl_clt = require "ngx.ssl.clienthello" local name = ssl_clt.get_client_hello_server_name() print("read SNI name from Lua: ", name, ", type: ", type(name)) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("127.0.0.2", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, nil, true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx received: Content-Type: text/plain received: Content-Length: 4 received: Connection: close received: received: foo close: 1 nil --- error_log read SNI name from Lua: nil, type: nil --- no_error_log [error] [alert] [emerg] === TEST 3: read SNI name via ssl.clienthello.get_client_hello_ext() --- skip_nginx: 6: < 1.19.9 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_client_hello_by_lua_block { local ssl_clt = require "ngx.ssl.clienthello" local byte = string.byte local ext = ssl_clt.get_client_hello_ext(0) if not ext then print("failed to get_client_hello_ext(0)") ngx.exit(ngx.ERROR) end local total_len = string.len(ext) if total_len <= 2 then print("bad SSL Client Hello Extension") ngx.exit(ngx.ERROR) end local len = byte(ext, 1) * 256 + byte(ext, 2) if len + 2 ~= total_len then print("bad SSL Client Hello Extension") ngx.exit(ngx.ERROR) end if byte(ext, 3) ~= 0 then print("bad SSL Client Hello Extension") ngx.exit(ngx.ERROR) end if total_len <= 5 then print("bad SSL Client Hello Extension") ngx.exit(ngx.ERROR) end len = byte(ext, 4) * 256 + byte(ext, 5) if len + 5 > total_len then print("bad SSL Client Hello Extension") ngx.exit(ngx.ERROR) end local name = string.sub(ext, 6, 6 + len -1) print("read SNI name from Lua: ", name) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx received: Content-Type: text/plain received: Content-Length: 4 received: Connection: close received: received: foo close: 1 nil --- error_log lua ssl server name: "test.com" read SNI name from Lua: test.com --- no_error_log [error] [alert] === TEST 4: read SNI name via ssl.clienthello.get_client_hello_ext() when no SNI name specified --- skip_nginx: 6: < 1.19.9 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen 127.0.0.2:$TEST_NGINX_RAND_PORT_1 ssl; server_name test.com; ssl_client_hello_by_lua_block { local ssl_clt = require "ngx.ssl.clienthello" local ext = ssl_clt.get_client_hello_ext(0) print("read SNI name from Lua: ", ext, ", type: ", type(ext)) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("127.0.0.2", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, nil, true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx received: Content-Type: text/plain received: Content-Length: 4 received: Connection: close received: received: foo close: 1 nil --- error_log read SNI name from Lua: nil, type: nil --- no_error_log [error] [alert] [emerg] === TEST 5: dynamically set ssl protocol - allow TLSv1.2 --- skip_nginx: 6: < 1.19.9 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_client_hello_by_lua_block { local ssl_clt = require "ngx.ssl.clienthello" local ok = ssl_clt.set_protocols({"TLSv1.2", "TLSv1.3"}) if not ok then print("failed to set_protocols") ngx.exit(ngx.ERROR) end } ssl_protocols TLSv1 TLSv1.1; ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_protocols TLSv1.2; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, nil, true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx received: Content-Type: text/plain received: Content-Length: 4 received: Connection: close received: received: foo close: 1 nil --- error_log eval [qr/SSL: TLSv1.2, cipher:/] --- no_error_log [error] [alert] [emerg] === TEST 6: dynamically set ssl protocol - allow TLSv1.3 --- skip_nginx: 6: < 1.19.9 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_client_hello_by_lua_block { local ssl_clt = require "ngx.ssl.clienthello" local ok = ssl_clt.set_protocols({"TLSv1.2", "TLSv1.3"}) if not ok then print("failed to set_protocols") ngx.exit(ngx.ERROR) end } ssl_protocols TLSv1 TLSv1.1; ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_protocols TLSv1.3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, nil, true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx received: Content-Type: text/plain received: Content-Length: 4 received: Connection: close received: received: foo close: 1 nil --- error_log eval [qr/SSL: TLSv1.3, cipher:/] --- no_error_log [error] [alert] [emerg] === TEST 7: dynamically set ssl protocol - deny TLSv1.1 --- skip_nginx: 5: < 1.19.9 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_client_hello_by_lua_block { local ssl_clt = require "ngx.ssl.clienthello" local ok = ssl_clt.set_protocols({"TLSv1.2", "TLSv1.3"}) if not ok then print("failed to set_protocols") ngx.exit(ngx.ERROR) end } ssl_protocols TLSv1 TLSv1.1; ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_protocols TLSv1.1; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, nil, true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 failed to do SSL handshake: handshake failed --- error_log eval [qr/SSL_do_handshake\(\) failed .*?tls_early_post_process_client_hello:unsupported protocol/] --- no_error_log [alert] [emerg] === TEST 8: dynamically set ssl protocol - deny TLSv1 --- skip_nginx: 5: < 1.19.9 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_client_hello_by_lua_block { local ssl_clt = require "ngx.ssl.clienthello" local ok = ssl_clt.set_protocols({"TLSv1.2", "TLSv1.3"}) if not ok then print("failed to set_protocols") ngx.exit(ngx.ERROR) end } ssl_protocols TLSv1 TLSv1.1; ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_protocols TLSv1; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, nil, true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 failed to do SSL handshake: handshake failed --- error_log eval [qr/SSL_do_handshake\(\) failed .*?tls_early_post_process_client_hello:unsupported protocol/] --- no_error_log [alert] [emerg] === TEST 9: get client hello supported versions - allow TLSv1.2 --- skip_nginx: 4: < 1.19.9 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen 127.0.0.2:$TEST_NGINX_RAND_PORT_1 ssl; server_name test.com; ssl_client_hello_by_lua_block { local ssl_clt = require "ngx.ssl.clienthello" local types, err = ssl_clt.get_supported_versions() if not err and types then for _, ssl_type in pairs(types) do if ssl_type == "TLSv1.2" then ngx.exit(ngx.OK) end end end ngx.log(ngx.ERR, "failed to get_supported_versions") ngx.exit(ngx.ERROR) } ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_protocols TLSv1 TLSv1.1 ; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("127.0.0.2", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, nil, true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 failed to do SSL handshake: handshake failed --- error_log failed to get_supported_versions --- no_error_log [alert] lua-resty-core-0.1.31/t/ssl-session-fetch.t000066400000000000000000000406601474236722600204730ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; use Cwd qw(abs_path realpath); use File::Basename; #worker_connections(10140); #workers(1); #log_level('warn'); #master_on(); repeat_each(2); plan tests => repeat_each() * (blocks() * 6); no_long_string(); #no_diff(); env_to_nginx("PATH=" . $ENV{'PATH'}); $ENV{TEST_NGINX_LUA_PACKAGE_PATH} = "$t::TestCore::lua_package_path"; $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; $ENV{TEST_NGINX_CERT_DIR} ||= dirname(realpath(abs_path(__FILE__))); run_tests(); __DATA__ === TEST 1: get resume session id serialized --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; ssl_session_fetch_by_lua_block { local ssl = require "ngx.ssl.session" local sid = ssl.get_session_id() print("session id: ", sid) } server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_session_tickets off; ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; server_tokens off; } --- config server_tokens off; resolver $TEST_NGINX_RESOLVER; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; lua_ssl_protocols TLSv1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(5000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) package.loaded.session = sess local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata close: 1 nil --- grep_error_log eval qr/ssl_session_fetch_by_lua\(nginx.conf:\d+\):\d+: session id: [a-fA-f\d]+/s --- grep_error_log_out eval [ "", qr/ssl_session_fetch_by_lua\(nginx.conf:\d+\):4: session id: [a-fA-f\d]+/s, qr/ssl_session_fetch_by_lua\(nginx.conf:\d+\):4: session id: [a-fA-f\d]+/s, ] --- no_error_log [alert] [emerg] [error] === TEST 2: attempt to fetch new session in lua_ctx during resumption. --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; ssl_session_fetch_by_lua_block { local ssl = require "ngx.ssl.session" local sess, err = ssl.get_serialized_session() if sess then print("session size: ", #sess) end if err then print("get session error: ", err) end } server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_session_tickets off; ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; server_tokens off; } --- config server_tokens off; resolver $TEST_NGINX_RESOLVER; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; lua_ssl_protocols TLSv1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(5000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) package.loaded.session = sess local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata close: 1 nil --- grep_error_log eval qr/ssl_session_fetch_by_lua:\d: session size: [a-fA-f\d]+|get session error: bad session in lua context/s --- grep_error_log_out eval [ "", 'get session error: bad session in lua context ', 'get session error: bad session in lua context ', ] --- no_error_log [alert] [emerg] [error] === TEST 3: store new session, and resume it Use a tmp file to store and resume session. This is for testing only. In practice, never store session in plaintext on persistent storage. --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; ssl_session_store_by_lua_block { local ssl = require "ngx.ssl.session" local sid = ssl.get_session_id() print("session id: ", sid) local sess = ssl.get_serialized_session() print("session size: ", #sess) local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/session.tmp", "w")) f:write(sess) f:close() } ssl_session_fetch_by_lua_block { local ssl = require "ngx.ssl.session" local sid = ssl.get_session_id() print("session id: ", sid) local f = io.open("$TEST_NGINX_SERVER_ROOT/html/session.tmp") if f == nil then return end local sess = f:read("*a") f:close() ssl.set_serialized_session(sess) } server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_session_tickets off; ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; server_tokens off; } --- config server_tokens off; resolver $TEST_NGINX_RESOLVER; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; lua_ssl_protocols TLSv1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(5000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) package.loaded.session = sess local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata close: 1 nil --- grep_error_log eval qr/ssl_session_(fetch|store)_by_lua\(nginx.conf:\d+\):\d+: session id: [a-fA-F\d]+/s --- grep_error_log_out eval [ qr/ssl_session_store_by_lua\(nginx.conf:\d+\):5: session id: [a-fA-F\d]+/s, qr/ssl_session_fetch_by_lua\(nginx.conf:\d+\):4: session id: [a-fA-F\d]+/s, qr/ssl_session_fetch_by_lua\(nginx.conf:\d+\):4: session id: [a-fA-F\d]+/s, ] --- no_error_log [alert] [emerg] [error] === TEST 4: attempt to resume a corrupted session Session resumption should fail, but the handshake should be able to carry on and negotiate a new session. --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; ssl_session_store_by_lua_block { local ssl = require "ngx.ssl.session" local sid = ssl.get_session_id() print("session id: ", sid) } ssl_session_fetch_by_lua_block { local ssl = require "ngx.ssl.session" local sid = ssl.get_session_id() print("session id: ", sid) local sess = "==garbage data==" local ok, err = ssl.set_serialized_session(sess) if not ok or err then print("failed to resume session: ", err) end } server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_session_tickets off; ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; server_tokens off; } --- config server_tokens off; resolver $TEST_NGINX_RESOLVER; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; lua_ssl_protocols TLSv1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(5000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) package.loaded.session = sess local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata close: 1 nil --- grep_error_log eval qr/failed to resume session: failed to de-serialize session|ssl_session_(fetch|store)_by_lua\(nginx.conf:\d+\):\d+: session id: [a-fA-F\d]+/s --- grep_error_log_out eval [ qr/^ssl_session_store_by_lua\(nginx.conf:\d+\):5: session id: [a-fA-F\d]+$/s, qr/^ssl_session_fetch_by_lua\(nginx.conf:\d+\):4: session id: [a-fA-F\d]+ failed to resume session: failed to de-serialize session ssl_session_store_by_lua\(nginx.conf:\d+\):5: session id: [a-fA-F\d]+ $/s, qr/ssl_session_fetch_by_lua:4: session id: [a-fA-F\d]+ failed to resume session: failed to de-serialize session ssl_session_store_by_lua\(nginx.conf:\d+\):5: session id: [a-fA-F\d]+ $/s, ] --- no_error_log [alert] [emerg] [error] === TEST 5: yield during doing handshake with client which uses low version OpenSSL --- no_check_leak --- http_config lua_shared_dict done 16k; lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH/?.lua;;"; ssl_session_store_by_lua_block { local ssl = require "ngx.ssl.session" local sid = ssl.get_session_id() print("session id: ", sid) } ssl_session_fetch_by_lua_block { local ssl = require "ngx.ssl.session" ngx.sleep(0.01) -- yield local sid = ssl.get_session_id() print("session id: ", sid) local sess = "==garbage data==" local ok, err = ssl.set_serialized_session(sess) if not ok or err then print("failed to resume session: ", err) end } server { listen $TEST_NGINX_RAND_PORT_1 ssl; server_name test.com; ssl_session_tickets off; ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; ssl_protocols TLSv1.2; location / { content_by_lua_block { ngx.shared.done:set("handshake", true) } } } --- config lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; location /t { set $sess_file $TEST_NGINX_HTML_DIR/sess; set $addr 127.0.0.1:$TEST_NGINX_RAND_PORT_1; content_by_lua_block { ngx.shared.done:delete("handshake") local addr = ngx.var.addr; local sess = ngx.var.sess_file local req = "'GET / HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n'" local f, err if not package.loaded.session then f, err = io.popen("echo -n " .. req .. " | timeout 3s openssl s_client -connect " .. addr .. " -sess_out " .. sess) package.loaded.session = true else f, err = io.popen("echo -n " .. req .. " | timeout 3s openssl s_client -connect " .. addr .. " -sess_in " .. sess) end if not f then ngx.say(err) return end local step = 0.001 while step < 2 do ngx.sleep(step) step = step * 2 if ngx.shared.done:get("handshake") then local out = f:read('*a') ngx.log(ngx.INFO, out) ngx.say("ok") f:close() return end end ngx.log(ngx.ERR, "openssl client handshake timeout") } } --- request GET /t --- response_body ok --- error_log eval qr/content_by_lua\(nginx\.conf:\d+\):\d+: CONNECTED/ --- grep_error_log eval qr/failed to resume session: failed to de-serialize session|ssl_session_(fetch|store)_by_lua\(nginx.conf:\d+\):\d+: session id: [a-fA-F\d]+/s --- grep_error_log_out eval [ qr/^ssl_session_fetch_by_lua\(nginx.conf:\d+\):\d+: session id: [a-fA-F\d]+ failed to resume session: failed to de-serialize session ssl_session_store_by_lua\(nginx.conf:\d+\):\d+: session id: [a-fA-F\d]+ $/s, qr/^ssl_session_fetch_by_lua\(nginx.conf:\d+\):\d+: session id: [a-fA-F\d]+ failed to resume session: failed to de-serialize session ssl_session_store_by_lua\(nginx.conf:\d+\):\d+: session id: [a-fA-F\d]+ $/s, qr/^ssl_session_fetch_by_lua\(nginx.conf:\d+\):\d+: session id: [a-fA-F\d]+ failed to resume session: failed to de-serialize session ssl_session_store_by_lua\(nginx.conf:\d+\):\d+: session id: [a-fA-F\d]+ $/s, ] --- no_error_log [alert] [emerg] [error] --- timeout: 5 === TEST 6: store new session, and resume it, avoid memory leak when calling repeatly --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; ssl_session_store_by_lua_block { local ssl = require "ngx.ssl.session" local sess = ssl.get_serialized_session() local f = assert(io.open("$TEST_NGINX_SERVER_ROOT/html/session.tmp", "w")) f:write(sess) f:close() } ssl_session_fetch_by_lua_block { local ssl = require "ngx.ssl.session" local f = io.open("$TEST_NGINX_SERVER_ROOT/html/session.tmp") if f == nil then return end local sess = f:read("*a") f:close() ssl.set_serialized_session(sess) ssl.set_serialized_session(sess) } server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_session_tickets off; ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; server_tokens off; } --- config lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; lua_ssl_protocols TLSv1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(5000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(package.loaded.session, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) package.loaded.session = sess local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata close: 1 nil --- no_error_log [alert] [emerg] [error] lua-resty-core-0.1.31/t/ssl-session-store.t000066400000000000000000000164471474236722600205440ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; use Cwd qw(abs_path realpath); use File::Basename; #worker_connections(10140); #workers(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 6 + 2); no_long_string(); #no_diff(); $ENV{TEST_NGINX_LUA_PACKAGE_PATH} = "$t::TestCore::lua_package_path"; $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; $ENV{TEST_NGINX_CERT_DIR} ||= dirname(realpath(abs_path(__FILE__))); run_tests(); __DATA__ === TEST 1: get new session serialized --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; ssl_session_store_by_lua_block { local ssl = require "ngx.ssl.session" local sess = ssl.get_serialized_session() print("session size: ", #sess) } server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_session_tickets off; ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; server_tokens off; } --- config server_tokens off; resolver $TEST_NGINX_RESOLVER; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; lua_ssl_protocols TLSv1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(5000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata close: 1 nil --- error_log eval qr/ssl_session_store_by_lua\(nginx.conf:\d+\):4: session size: \d+/s --- no_error_log [alert] [emerg] [error] === TEST 2: get new session id serialized --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; ssl_session_store_by_lua_block { local ssl = require "ngx.ssl.session" local sid = ssl.get_session_id() print("session id: ", sid) } server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_session_tickets off; ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; server_tokens off; } --- config server_tokens off; resolver $TEST_NGINX_RESOLVER; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; lua_ssl_protocols TLSv1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(5000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata close: 1 nil --- error_log eval qr/ssl_session_store_by_lua\(nginx.conf:\d+\):4: session id: [a-fA-f\d]+/s --- no_error_log [alert] [emerg] [error] === TEST 3: store the session via timer to memcached --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; ssl_session_store_by_lua_block { local ssl = require "ngx.ssl.session" local function f(premature, key, value) local sock = ngx.socket.tcp() sock:settimeout(5000) local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_MEMCACHED_PORT) if not ok then ngx.log(ngx.ERR, "failed to connect to memc: ", err) return end local bytes, err = sock:send("set " .. key .. " 0 0 " .. tostring(#value) .. " \r\n" .. value .. "\r\n") if not bytes then ngx.log(ngx.ERR, "failed to send set command: ", err) return end local res, err = sock:receive() if not res then ngx.log(ngx.ERR, "failed to receive memc reply: ", err) return end print("received memc reply: ", res) end local sid = ssl.get_session_id() print("session id: ", sid) local sess = ssl.get_serialized_session() print("session size: ", #sess) local ok, err = ngx.timer.at(0, f, sid, sess) if not ok then ngx.log(ngx.ERR, "failed to create timer: ", err) return end } server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_session_tickets off; ssl_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; ssl_certificate_key $TEST_NGINX_CERT_DIR/cert/test.key; server_tokens off; } --- config server_tokens off; resolver $TEST_NGINX_RESOLVER; lua_ssl_trusted_certificate $TEST_NGINX_CERT_DIR/cert/test.crt; lua_ssl_verify_depth 3; lua_ssl_protocols TLSv1.2; location /t { set $port $TEST_NGINX_MEMCACHED_PORT; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(5000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata close: 1 nil --- error_log eval [ qr/ssl_session_store_by_lua\(nginx.conf:\d+\):32: session id: [a-fA-f\d]+/s, qr/ssl_session_store_by_lua\(nginx.conf:\d+\):34: session size: \d+/s, qr/received memc reply: STORED/s, ] --- no_error_log [alert] [emerg] [error] --- wait: 0.2 lua-resty-core-0.1.31/t/ssl.t000066400000000000000000002713511474236722600157260ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(10140); #workers(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 6 - 1); no_long_string(); #no_diff(); env_to_nginx("PATH=" . $ENV{'PATH'}); $ENV{TEST_NGINX_LUA_PACKAGE_PATH} = "$t::TestCore::lua_package_path"; $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); run_tests(); __DATA__ === TEST 1: clear certs --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" ssl.clear_certs() } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 failed to do SSL handshake: handshake failed --- error_log lua ssl server name: "test.com" sslv3 alert handshake failure --- no_error_log [alert] [emerg] === TEST 2: set DER cert and private key --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" ssl.clear_certs() local f = assert(io.open("t/cert/test.crt.der")) local cert_data = f:read("*a") f:close() local ok, err = ssl.set_der_cert(cert_data) if not ok then ngx.log(ngx.ERR, "failed to set DER cert: ", err) return end local f = assert(io.open("t/cert/test.key.der")) local pkey_data = f:read("*a") f:close() local ok, err = ssl.set_der_priv_key(pkey_data) if not ok then ngx.log(ngx.ERR, "failed to set DER cert: ", err) return end } ssl_certificate ../../cert/test2.crt; ssl_certificate_key ../../cert/test2.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx received: Content-Type: text/plain received: Content-Length: 4 received: Connection: close received: received: foo close: 1 nil --- error_log lua ssl server name: "test.com" --- no_error_log [error] [alert] [emerg] === TEST 3: read SNI name via ssl.server_name() --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" print("read SNI name from Lua: ", ssl.server_name()) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx received: Content-Type: text/plain received: Content-Length: 4 received: Connection: close received: received: foo close: 1 nil --- error_log lua ssl server name: "test.com" read SNI name from Lua: test.com --- no_error_log [error] [alert] === TEST 4: read SNI name via ssl.server_name() when no SNI name specified --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local name = ssl.server_name(), print("read SNI name from Lua: ", name, ", type: ", type(name)) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, nil, true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx received: Content-Type: text/plain received: Content-Length: 4 received: Connection: close received: received: foo close: 1 nil --- error_log read SNI name from Lua: nil, type: nil --- no_error_log [error] [alert] [emerg] === TEST 5: read raw server addr via ssl.raw_server_addr() (unix domain socket) --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local addr, addrtyp, err = ssl.raw_server_addr() if not addr then ngx.log(ngx.ERR, "failed to fetch raw server addr: ", err) return end if addrtyp == "inet" then -- IPv4 ip = string.format("%d.%d.%d.%d", byte(addr, 1), byte(addr, 2), byte(addr, 3), byte(addr, 4)) print("Using IPv4 address: ", ip) elseif addrtyp == "inet6" then -- IPv6 ip = string.format("%d.%d.%d.%d", byte(addr, 13), byte(addr, 14), byte(addr, 15), byte(addr, 16)) print("Using IPv6 address: ", ip) else -- unix print("Using unix socket file ", addr) end } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx received: Content-Type: text/plain received: Content-Length: 4 received: Connection: close received: received: foo close: 1 nil --- error_log eval [ 'lua ssl server name: "test.com"', qr/Using unix socket file .*?nginx\.sock/ ] --- no_error_log [error] [alert] --- no_check_leak === TEST 6: read raw server addr via ssl.raw_server_addr() (IPv4) --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen 127.0.0.1:$TEST_NGINX_RAND_PORT_1 ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local byte = string.byte local addr, addrtyp, err = ssl.raw_server_addr() if not addr then ngx.log(ngx.ERR, "failed to fetch raw server addr: ", err) return end if addrtyp == "inet" then -- IPv4 ip = string.format("%d.%d.%d.%d", byte(addr, 1), byte(addr, 2), byte(addr, 3), byte(addr, 4)) print("Using IPv4 address: ", ip) elseif addrtyp == "inet6" then -- IPv6 ip = string.format("%d.%d.%d.%d", byte(addr, 13), byte(addr, 14), byte(addr, 15), byte(addr, 16)) print("Using IPv6 address: ", ip) else -- unix print("Using unix socket file ", addr) end } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx received: Content-Type: text/plain received: Content-Length: 4 received: Connection: close received: received: foo close: 1 nil --- error_log lua ssl server name: "test.com" Using IPv4 address: 127.0.0.1 --- no_error_log [error] [alert] --- no_check_leak === TEST 7: read raw server addr via ssl.raw_server_addr() (IPv6) --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen [::1]:$TEST_NGINX_RAND_PORT_1 ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local byte = string.byte local addr, addrtyp, err = ssl.raw_server_addr() if not addr then ngx.log(ngx.ERR, "failed to fetch raw server addr: ", err) return end if addrtyp == "inet" then -- IPv4 ip = string.format("%d.%d.%d.%d", byte(addr, 1), byte(addr, 2), byte(addr, 3), byte(addr, 4)) print("Using IPv4 address: ", ip) elseif addrtyp == "inet6" then -- IPv6 ip = string.format("%d.%d.%d.%d", byte(addr, 13), byte(addr, 14), byte(addr, 15), byte(addr, 16)) print("Using IPv6 address: ", ip) else -- unix print("Using unix socket file ", addr) end } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("[::1]", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx received: Content-Type: text/plain received: Content-Length: 4 received: Connection: close received: received: foo close: 1 nil --- error_log lua ssl server name: "test.com" Using IPv6 address: 0.0.0.1 --- no_error_log [error] [alert] --- skip_eval: 6: system("ping6 -c 1 ::1 >/dev/null 2>&1") ne 0 --- no_check_leak === TEST 8: set DER cert chain --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" ssl.clear_certs() local f = assert(io.open("t/cert/chain/chain.der")) local cert_data = f:read("*a") f:close() local ok, err = ssl.set_der_cert(cert_data) if not ok then ngx.log(ngx.ERR, "failed to set DER cert: ", err) return end local f = assert(io.open("t/cert/chain/test-com.key.der")) local pkey_data = f:read("*a") f:close() local ok, err = ssl.set_der_priv_key(pkey_data) if not ok then ngx.log(ngx.ERR, "failed to set DER cert: ", err) return end } ssl_certificate ../../cert/test2.crt; ssl_certificate_key ../../cert/test2.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/chain/root-ca.crt; lua_ssl_verify_depth 3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx received: Content-Type: text/plain received: Content-Length: 4 received: Connection: close received: received: foo close: 1 nil --- error_log lua ssl server name: "test.com" --- no_error_log [error] [alert] [emerg] === TEST 9: read PEM cert chain but set DER cert chain --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" ssl.clear_certs() local f = assert(io.open("t/cert/chain/chain.pem")) local cert_data = f:read("*a") f:close() local cert, err = ssl.cert_pem_to_der(cert_data) if not cert then ngx.log(ngx.ERR, "failed to convert pem cert to der cert: ", err) return end local ok, err = ssl.set_der_cert(cert) if not ok then ngx.log(ngx.ERR, "failed to set DER cert: ", err) return end local f = assert(io.open("t/cert/chain/test-com.key.der")) local pkey_data = f:read("*a") f:close() local ok, err = ssl.set_der_priv_key(pkey_data) if not ok then ngx.log(ngx.ERR, "failed to set DER private key: ", err) return end } ssl_certificate ../../cert/test2.crt; ssl_certificate_key ../../cert/test2.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/chain/root-ca.crt; lua_ssl_verify_depth 3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx received: Content-Type: text/plain received: Content-Length: 4 received: Connection: close received: received: foo close: 1 nil --- error_log lua ssl server name: "test.com" --- no_error_log [error] [alert] [emerg] === TEST 10: tls version - SSLv3 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen 127.0.0.2:$TEST_NGINX_RAND_PORT_1 ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ver, err = ssl.get_tls1_version_str(resp) if not ver then ngx.log(ngx.ERR, "failed to get TLS1 version: ", err) return end ngx.log(ngx.WARN, "got TLS1 version: ", ver) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; ssl_protocols SSLv3; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_verify_depth 3; lua_ssl_protocols SSLv3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("127.0.0.2", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(false, nil, true, false) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) end -- do } } --- request GET /t --- response_body connected: 1 ssl handshake: boolean --- error_log got TLS1 version: SSLv3, --- no_error_log [error] [alert] [emerg] === TEST 11: tls version - TLSv1 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen 127.0.0.2:$TEST_NGINX_RAND_PORT_1 ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ver, err = ssl.get_tls1_version_str(resp) if not ver then ngx.log(ngx.ERR, "failed to get TLS1 version: ", err) return end ngx.log(ngx.WARN, "got TLS1 version: ", ver) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; ssl_protocols TLSv1; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_verify_depth 3; lua_ssl_protocols TLSv1; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("127.0.0.2", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(false, nil, true, false) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) end -- do } } --- request GET /t --- response_body connected: 1 ssl handshake: boolean --- error_log got TLS1 version: TLSv1, --- no_error_log [error] [alert] [emerg] === TEST 12: tls version - TLSv1.1 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen 127.0.0.2:$TEST_NGINX_RAND_PORT_1 ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ver, err = ssl.get_tls1_version_str(resp) if not ver then ngx.log(ngx.ERR, "failed to get TLS1 version: ", err) return end ngx.log(ngx.WARN, "got TLS1 version: ", ver) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; ssl_protocols TLSv1.1; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_verify_depth 3; lua_ssl_protocols TLSv1.1; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("127.0.0.2", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(false, nil, true, false) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) end -- do } } --- request GET /t --- response_body connected: 1 ssl handshake: boolean --- error_log got TLS1 version: TLSv1.1, --- no_error_log [error] [alert] [emerg] === TEST 13: tls version - TLSv1.2 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen 127.0.0.2:$TEST_NGINX_RAND_PORT_1 ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ver, err = ssl.get_tls1_version_str(resp) if not ver then ngx.log(ngx.ERR, "failed to get TLS1 version: ", err) return end ngx.log(ngx.WARN, "got TLS1 version: ", ver) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; ssl_protocols TLSv1.2; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_verify_depth 3; lua_ssl_protocols TLSv1.2; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("127.0.0.2", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(false, nil, true, false) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) end -- do } } --- request GET /t --- response_body connected: 1 ssl handshake: boolean --- error_log got TLS1 version: TLSv1.2, --- no_error_log [error] [alert] [emerg] === TEST 14: ngx.semaphore in ssl_certificate_by_lua* --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen 127.0.0.2:$TEST_NGINX_RAND_PORT_1 ssl; server_name test.com; ssl_certificate_by_lua_block { local semaphore = require "ngx.semaphore" local sema = assert(semaphore.new()) local function f() assert(sema:wait(1)) end local t = assert(ngx.thread.spawn(f)) ngx.sleep(0.25) assert(sema:post()) assert(ngx.thread.wait(t)) print("ssl cert by lua done") } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; ssl_protocols TLSv1.2; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_verify_depth 3; lua_ssl_protocols TLSv1.2; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("127.0.0.2", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(false, nil, true, false) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) end -- do } } --- request GET /t --- response_body connected: 1 ssl handshake: boolean --- grep_error_log eval: qr/http lua semaphore (?:wait yielding|\w[^:,]*)/ --- grep_error_log_out http lua semaphore new http lua semaphore wait http lua semaphore wait yielding http lua semaphore post --- error_log ssl cert by lua done --- no_error_log [error] [alert] [emerg] === TEST 15: read PEM key chain but set DER key chain --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" ssl.clear_certs() local f = assert(io.open("t/cert/chain/chain.pem")) local cert_data = f:read("*a") f:close() local cert, err = ssl.cert_pem_to_der(cert_data) if not cert then ngx.log(ngx.ERR, "failed to convert pem cert to der cert: ", err) return end local ok, err = ssl.set_der_cert(cert) if not ok then ngx.log(ngx.ERR, "failed to set DER cert: ", err) return end local f = assert(io.open("t/cert/chain/test-com.key.pem")) local pkey_data = f:read("*a") f:close() pkey_data, err = ssl.priv_key_pem_to_der(pkey_data) if not pkey_data then ngx.log(ngx.ERR, "failed to convert pem key to der key: ", err) return end local ok, err = ssl.set_der_priv_key(pkey_data) if not ok then ngx.log(ngx.ERR, "failed to set private key: ", err) return end } ssl_certificate ../../cert/test2.crt; ssl_certificate_key ../../cert/test2.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block { ngx.status = 201 ngx.say("foo") ngx.exit(201) } more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/chain/root-ca.crt; lua_ssl_verify_depth 3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx received: Content-Type: text/plain received: Content-Length: 4 received: Connection: close received: received: foo close: 1 nil --- error_log lua ssl server name: "test.com" --- no_error_log [error] [alert] [emerg] === TEST 16: parse PEM cert and key to cdata --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" ssl.clear_certs() local f = assert(io.open("t/cert/chain/chain.pem")) local cert_data = f:read("*a") f:close() local cert, err = ssl.parse_pem_cert(cert_data) if not cert then ngx.log(ngx.ERR, "failed to parse pem cert: ", err) return end local ok, err = ssl.set_cert(cert) if not ok then ngx.log(ngx.ERR, "failed to set cert: ", err) return end local f = assert(io.open("t/cert/chain/test-com.key.pem")) local pkey_data = f:read("*a") f:close() local pkey, err = ssl.parse_pem_priv_key(pkey_data) if not pkey then ngx.log(ngx.ERR, "failed to parse pem key: ", err) return end local ok, err = ssl.set_priv_key(pkey) if not ok then ngx.log(ngx.ERR, "failed to set private key: ", err) return end } ssl_certificate ../../cert/test2.crt; ssl_certificate_key ../../cert/test2.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block { ngx.status = 201 ngx.say("foo") ngx.exit(201) } more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/chain/root-ca.crt; lua_ssl_verify_depth 3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx received: Content-Type: text/plain received: Content-Length: 4 received: Connection: close received: received: foo close: 1 nil --- error_log lua ssl server name: "test.com" --- no_error_log [error] [alert] [emerg] === TEST 17: parse PEM cert and key to cdata (bad cert 0 in the chain) --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" ssl.clear_certs() local f = assert(io.open("t/cert/chain/chain-bad0.pem")) local cert_data = f:read("*a") f:close() local cert, err = ssl.parse_pem_cert(cert_data) if not cert then ngx.log(ngx.ERR, "failed to parse pem cert: ", err) return end local ok, err = ssl.set_cert(cert) if not ok then ngx.log(ngx.ERR, "failed to set cert: ", err) return end local f = assert(io.open("t/cert/chain/test-com.key.pem")) local pkey_data = f:read("*a") f:close() local pkey, err = ssl.parse_pem_priv_key(pkey_data) if not pkey then ngx.log(ngx.ERR, "failed to parse pem key: ", err) return end local ok, err = ssl.set_priv_key(pkey) if not ok then ngx.log(ngx.ERR, "failed to set private key: ", err) return end } ssl_certificate ../../cert/test2.crt; ssl_certificate_key ../../cert/test2.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block { ngx.status = 201 ngx.say("foo") ngx.exit(201) } more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/chain/root-ca.crt; lua_ssl_verify_depth 3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 failed to do SSL handshake: handshake failed --- error_log eval qr/\[error\] .*? failed to parse pem cert: PEM_read_bio_X509_AUX\(\) failed/ --- no_error_log [alert] [emerg] [crit] === TEST 18: parse PEM cert and key to cdata (bad cert 2 in the chain) --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" ssl.clear_certs() local f = assert(io.open("t/cert/chain/chain-bad2.pem")) local cert_data = f:read("*a") f:close() local cert, err = ssl.parse_pem_cert(cert_data) if not cert then ngx.log(ngx.ERR, "failed to parse pem cert: ", err) return end local ok, err = ssl.set_cert(cert) if not ok then ngx.log(ngx.ERR, "failed to set cert: ", err) return end local f = assert(io.open("t/cert/chain/test-com.key.pem")) local pkey_data = f:read("*a") f:close() local pkey, err = ssl.parse_pem_priv_key(pkey_data) if not pkey then ngx.log(ngx.ERR, "failed to parse pem key: ", err) return end local ok, err = ssl.set_priv_key(pkey) if not ok then ngx.log(ngx.ERR, "failed to set private key: ", err) return end } ssl_certificate ../../cert/test2.crt; ssl_certificate_key ../../cert/test2.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block { ngx.status = 201 ngx.say("foo") ngx.exit(201) } more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/chain/root-ca.crt; lua_ssl_verify_depth 3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 failed to do SSL handshake: handshake failed --- error_log eval qr/\[error\] .*? failed to parse pem cert: PEM_read_bio_X509\(\) failed/ --- no_error_log [alert] [emerg] [crit] === TEST 19: parse PEM cert and key to cdata (bad priv key) --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" ssl.clear_certs() local f = assert(io.open("t/cert/chain/chain.pem")) local cert_data = f:read("*a") f:close() local cert, err = ssl.parse_pem_cert(cert_data) if not cert then ngx.log(ngx.ERR, "failed to parse pem cert: ", err) return end local ok, err = ssl.set_cert(cert) if not ok then ngx.log(ngx.ERR, "failed to set cert: ", err) return end local f = assert(io.open("t/cert/chain/test-com-bad.key.pem")) local pkey_data = f:read("*a") f:close() local pkey, err = ssl.parse_pem_priv_key(pkey_data) if not pkey then ngx.log(ngx.ERR, "failed to parse pem key: ", err) return end local ok, err = ssl.set_priv_key(pkey) if not ok then ngx.log(ngx.ERR, "failed to set private key: ", err) return end } ssl_certificate ../../cert/test2.crt; ssl_certificate_key ../../cert/test2.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block { ngx.status = 201 ngx.say("foo") ngx.exit(201) } more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/chain/root-ca.crt; lua_ssl_verify_depth 3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 failed to do SSL handshake: handshake failed --- error_log eval qr/\[error\] .*? failed to parse pem key: PEM_read_bio_PrivateKey\(\) failed/ --- no_error_log [alert] [emerg] [crit] === TEST 20: read client addr via ssl.raw_client_addr() --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen 127.0.0.1:$TEST_NGINX_RAND_PORT_1 ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local byte = string.byte local addr, addrtype, err = ssl.raw_client_addr() local ip = string.format("%d.%d.%d.%d", byte(addr, 1), byte(addr, 2), byte(addr, 3), byte(addr, 4)) print("client ip: ", ip) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, nil, true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx received: Content-Type: text/plain received: Content-Length: 4 received: Connection: close received: received: foo close: 1 nil --- error_log client ip: 127.0.0.1 --- no_error_log [error] [alert] [emerg] === TEST 21: yield during doing handshake with client which uses low version OpenSSL --- no_check_leak --- http_config lua_shared_dict done 16k; lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH/?.lua;;"; server { listen $TEST_NGINX_RAND_PORT_1 ssl; server_name test.com; ssl_session_tickets off; ssl_certificate ../../cert/test2.crt; ssl_certificate_key ../../cert/test2.key; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" ssl.clear_certs() local f = assert(io.open("t/cert/test.crt.der")) local cert_data = f:read("*a") f:close() ngx.sleep(0.01) -- yield local ok, err = ssl.set_der_cert(cert_data) if not ok then ngx.log(ngx.ERR, "failed to set DER cert: ", err) return end local f = assert(io.open("t/cert/test.key.der")) local pkey_data = f:read("*a") f:close() local ok, err = ssl.set_der_priv_key(pkey_data) if not ok then ngx.log(ngx.ERR, "failed to set DER cert: ", err) return end } location / { content_by_lua_block { ngx.shared.done:set("handshake", true) } } } --- config lua_ssl_trusted_certificate ../../cert/test.crt; location /t { content_by_lua_block { ngx.shared.done:delete("handshake") local addr = ngx.var.addr; local req = "'GET / HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n'" local f, err = io.popen("echo -n " .. req .. " | timeout 3s openssl s_client -connect 127.0.0.1:$TEST_NGINX_RAND_PORT_1") if not f then ngx.say(err) return end local step = 0.001 while step < 2 do ngx.sleep(step) step = step * 2 if ngx.shared.done:get("handshake") then local out = f:read('*a') ngx.log(ngx.INFO, out) ngx.say("ok") f:close() return end end ngx.log(ngx.ERR, "openssl client handshake timeout") } } --- request GET /t --- response_body ok --- error_log eval [ qr/content_by_lua\(nginx\.conf:\d+\):\d+: CONNECTED/, qr/subject=\/?C(?\s?=\s?)US(?\/|,\s)ST\kCalifornia\kL\kSan Francisco\kO\kOpenResty\kOU\kOpenResty\kCN\ktest\.com\kemailAddress\kagentzh\@gmail\.com/, ] --- no_error_log [error] [alert] --- timeout: 4 === TEST 22: tls version - TLSv1.3 --- skip_openssl: 6: < 1.1.1 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; server_tokens off; ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; ssl_protocols TLSv1.3; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ver, err = ssl.get_tls1_version_str(resp) if not ver then ngx.log(ngx.ERR, "failed to get TLS1 version: ", err) return end ngx.log(ngx.WARN, "got TLS1 version: ", ver) } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_verify_depth 3; lua_ssl_protocols TLSv1.3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(false, nil, true, false) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) end -- do } } --- request GET /t --- response_body connected: 1 ssl handshake: boolean --- error_log got TLS1 version: TLSv1.3, --- no_error_log [error] [alert] [emerg] === TEST 23: verify client with CA certificates --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local f = assert(io.open("t/cert/test.crt")) local cert_data = f:read("*a") f:close() local cert, err = ssl.parse_pem_cert(cert_data) if not cert then ngx.log(ngx.ERR, "failed to parse pem cert: ", err) return end local ok, err = ssl.verify_client(cert, 1, nil) if not ok then ngx.log(ngx.ERR, "failed to verify client: ", err) return end } ssl_certificate ../../cert/test2.crt; ssl_certificate_key ../../cert/test2.key; location / { default_type 'text/plain'; content_by_lua_block { print('client certificate subject: ', ngx.var.ssl_client_s_dn) ngx.say(ngx.var.ssl_client_verify) } more_clear_headers Date; } } --- config location /t { proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock; proxy_ssl_certificate ../../cert/test.crt; proxy_ssl_certificate_key ../../cert/test.key; proxy_ssl_session_reuse off; } --- request GET /t --- response_body SUCCESS --- error_log client certificate subject: emailAddress=agentzh@gmail.com,CN=test.com --- no_error_log [error] [alert] [emerg] === TEST 24: verify client without CA certificates --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ok, err = ssl.verify_client() if not ok then ngx.log(ngx.ERR, "failed to verify client: ", err) return end } ssl_certificate ../../cert/test2.crt; ssl_certificate_key ../../cert/test2.key; location / { default_type 'text/plain'; content_by_lua_block { print('client certificate subject: ', ngx.var.ssl_client_s_dn) ngx.say(ngx.var.ssl_client_verify) } more_clear_headers Date; } } --- config location /t { proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock; proxy_ssl_certificate ../../cert/test.crt; proxy_ssl_certificate_key ../../cert/test.key; proxy_ssl_session_reuse off; } --- request GET /t --- response_body FAILED:self signed certificate --- error_log client certificate subject: emailAddress=agentzh@gmail.com,CN=test.com --- no_error_log [error] [alert] [emerg] === TEST 25: verify client but client provides no certificate --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local f = assert(io.open("t/cert/test.crt")) local cert_data = f:read("*a") f:close() local cert, err = ssl.parse_pem_cert(cert_data) if not cert then ngx.log(ngx.ERR, "failed to parse pem cert: ", err) return end local ok, err = ssl.verify_client(cert, 1, nil) if not ok then ngx.log(ngx.ERR, "failed to verify client: ", err) return end } ssl_certificate ../../cert/test2.crt; ssl_certificate_key ../../cert/test2.key; location / { default_type 'text/plain'; content_by_lua_block { print('client certificate subject: ', ngx.var.ssl_client_s_dn) ngx.say(ngx.var.ssl_client_verify) } more_clear_headers Date; } } --- config location /t { proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock; proxy_ssl_session_reuse off; } --- request GET /t --- response_body NONE --- error_log client certificate subject: nil --- no_error_log [error] [alert] [emerg] === TEST 26: read server port via ssl.server_port() with ipv4 --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen 127.0.0.1:$TEST_NGINX_RAND_PORT_2 ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local port, err = ssl.server_port() print("read server port from Lua: ", port) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_RAND_PORT_2) if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx received: Content-Type: text/plain received: Content-Length: 4 received: Connection: close received: received: foo close: 1 nil --- error_log eval qr/read server port from Lua: \d+/ --- no_error_log [error] [alert] [emerg] === TEST 27: read server port via ssl.server_port() with unix domain socket --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local port, err = ssl.server_port() print("read server port from Lua: ", port, err) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx received: Content-Type: text/plain received: Content-Length: 4 received: Connection: close received: received: foo close: 1 nil --- error_log read server port from Lua: nilunix domain has no port --- no_error_log [error] [alert] [emerg] === TEST 28: PEM key protected by passphrase --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" ssl.clear_certs() local f = assert(io.open("t/cert/test_passphrase.crt")) local cert_data = f:read("*a") f:close() local cert, err = ssl.cert_pem_to_der(cert_data) if not cert then ngx.log(ngx.ERR, "failed to convert pem cert to der cert: ", err) return end local ok, err = ssl.set_der_cert(cert) if not ok then ngx.log(ngx.ERR, "failed to set DER cert: ", err) return end local f = assert(io.open("t/cert/test_passphrase.key")) local pkey_data = f:read("*a") f:close() pkey_data, err = ssl.priv_key_pem_to_der(pkey_data, "123456") if not pkey_data then ngx.log(ngx.ERR, "failed to convert pem key to der key: ", err) return end local ok, err = ssl.set_der_priv_key(pkey_data) if not ok then ngx.log(ngx.ERR, "failed to set private key: ", err) return end } ssl_certificate ../../cert/test2.crt; ssl_certificate_key ../../cert/test2.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block { ngx.status = 201 ngx.say("foo") ngx.exit(201) } more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/chain/root-ca.crt; lua_ssl_verify_depth 3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", false) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx received: Content-Type: text/plain received: Content-Length: 4 received: Connection: close received: received: foo close: 1 nil --- error_log lua ssl server name: "test.com" --- no_error_log [error] [alert] [emerg] === TEST 29: parse PEM cert and key to cdata --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" ssl.clear_certs() local f = assert(io.open("t/cert/chain/chain.der")) local cert_data = f:read("*a") f:close() local cert, err = ssl.parse_der_cert(cert_data) if not cert then ngx.log(ngx.ERR, "failed to parse pem cert: ", err) return end local ok, err = ssl.set_cert(cert) if not ok then ngx.log(ngx.ERR, "failed to set cert: ", err) return end local f = assert(io.open("t/cert/chain/test-com.key.der")) local pkey_data = f:read("*a") f:close() local pkey, err = ssl.parse_der_priv_key(pkey_data) if not pkey then ngx.log(ngx.ERR, "failed to parse pem key: ", err) return end local ok, err = ssl.set_priv_key(pkey) if not ok then ngx.log(ngx.ERR, "failed to set private key: ", err) return end } ssl_certificate ../../cert/test2.crt; ssl_certificate_key ../../cert/test2.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block { ngx.status = 201 ngx.say("foo") ngx.exit(201) } more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/chain/root-ca.crt; lua_ssl_verify_depth 3; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx received: Content-Type: text/plain received: Content-Length: 4 received: Connection: close received: received: foo close: 1 nil --- error_log lua ssl server name: "test.com" --- no_error_log [error] [alert] [emerg] === TEST 30: read client-random via ssl.get_client_random() --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local client_random_len = ssl.get_client_random(0) print("client-random length: ", client_random_len) local init_v = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" local client_random = ssl.get_client_random() if client_random == init_v then print("maybe the client random value is incorrect") end } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx received: Content-Type: text/plain received: Content-Length: 4 received: Connection: close received: received: foo close: 1 nil --- error_log client-random length: 32 --- no_error_log [error] [alert] [emerg] === TEST 31: export_keying_material --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; access_by_lua_block { local ssl = require "ngx.ssl" local key_length = 16 local label = "EXPERIMENTAL my label" local context = "\x00\x01\x02\x03" local key, err = ssl.export_keying_material(key_length, label, context) if not key then ngx.log(ngx.ERR, "failed to derive key ", err) return end ngx.log(ngx.INFO, "output key length: ", #key) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx received: Content-Type: text/plain received: Content-Length: 4 received: Connection: close received: received: foo close: 1 nil --- error_log output key length: 16 --- no_error_log [error] [alert] [emerg] === TEST 32: get SSL pointer --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ssl_pointer, err = ssl.get_req_ssl_pointer() if not ssl_pointer then ngx.log(ngx.ERR, "cann't get SSL pointer") end } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; server_tokens off; location /foo { default_type 'text/plain'; content_by_lua_block {ngx.status = 201 ngx.say("foo") ngx.exit(201)} more_clear_headers Date; } } --- config server_tokens off; lua_ssl_trusted_certificate ../../cert/test.crt; location /t { content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) local req = "GET /foo HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n" local bytes, err = sock:send(req) if not bytes then ngx.say("failed to send http request: ", err) return end ngx.say("sent http request: ", bytes, " bytes.") while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } } --- request GET /t --- response_body connected: 1 ssl handshake: cdata sent http request: 56 bytes. received: HTTP/1.1 201 Created received: Server: nginx received: Content-Type: text/plain received: Content-Length: 4 received: Connection: close received: received: foo close: 1 nil --- error_log lua ssl server name: "test.com" --- no_error_log [error] [emerg] [crit] === TEST 33: verify client, but server not trust root ca --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local f = assert(io.open("t/cert/mtls_server.crt")) local cert_data = f:read("*a") f:close() local cert, err = ssl.parse_pem_cert(cert_data) if not cert then ngx.log(ngx.ERR, "failed to parse pem cert: ", err) return end local ok, err = ssl.verify_client(cert, 1, nil) if not ok then ngx.log(ngx.ERR, "failed to verify client: ", err) return end } ssl_certificate ../../cert/mtls_server.crt; ssl_certificate_key ../../cert/mtls_server.key; location / { default_type 'text/plain'; content_by_lua_block { ngx.say(ngx.var.ssl_client_verify) } more_clear_headers Date; } } --- config location /t { proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock; proxy_ssl_certificate ../../cert/mtls_client.crt; proxy_ssl_certificate_key ../../cert/mtls_client.key; proxy_ssl_session_reuse off; } --- request GET /t --- response_body FAILED:unable to verify the first certificate --- no_error_log [error] [alert] [emerg] === TEST 34: verify client and server trust root ca --- http_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; server_name test.com; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local f = assert(io.open("t/cert/mtls_server.crt")) local cert_data = f:read("*a") f:close() local cert, err = ssl.parse_pem_cert(cert_data) if not cert then ngx.log(ngx.ERR, "failed to parse pem cert: ", err) return end local f = assert(io.open("t/cert/mtls_ca.crt")) local cert_data = f:read("*a") f:close() local trusted_cert, err = ssl.parse_pem_cert(cert_data) if not trusted_cert then ngx.log(ngx.ERR, "failed to parse pem trusted cert: ", err) return end local ok, err = ssl.verify_client(cert, 1, trusted_cert) if not ok then ngx.log(ngx.ERR, "failed to verify client: ", err) return end } ssl_certificate ../../cert/mtls_server.crt; ssl_certificate_key ../../cert/mtls_server.key; location / { default_type 'text/plain'; content_by_lua_block { ngx.say(ngx.var.ssl_client_verify) } more_clear_headers Date; } } --- config location /t { proxy_pass https://unix:$TEST_NGINX_HTML_DIR/nginx.sock; proxy_ssl_certificate ../../cert/mtls_client.crt; proxy_ssl_certificate_key ../../cert/mtls_client.key; proxy_ssl_session_reuse off; } --- request GET /t --- response_body SUCCESS --- no_error_log [error] [alert] [emerg] lua-resty-core-0.1.31/t/status.t000066400000000000000000000023541474236722600164430ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(1014); #master_process_enabled(1); log_level('warn'); #repeat_each(120); repeat_each(2); plan tests => repeat_each() * (blocks() * 7); #no_diff(); #no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: get ngx.status --- config location = /t { return 201; header_filter_by_lua_block { local sum = 0 for i = 1, 30 do sum = sum + ngx.status end ngx.log(ngx.WARN, "sum: ", sum) } } --- request GET /t --- response_body --- error_code: 201 --- no_error_log [error] -- NYI: bad argument --- error_log eval ["sum: 6030,", qr/\[TRACE\s+\d+\s+header_filter_by_lua\(nginx.conf:\d+\):3 loop\]/ ] === TEST 2: set ngx.status --- config location = /t { return 201; header_filter_by_lua_block { for i = 100, 200 do ngx.status = i end ngx.log(ngx.WARN, "status: ", ngx.status) } } --- request GET /t --- response_body --- no_error_log [error] -- NYI: bad argument --- error_log eval ["status: 200,", qr/\[TRACE\s+\d+\s+header_filter_by_lua\(nginx.conf:\d+\):2 loop\]/ ] lua-resty-core-0.1.31/t/stream/000077500000000000000000000000001474236722600162225ustar00rootroot00000000000000lua-resty-core-0.1.31/t/stream/balancer-bind.t000066400000000000000000000047251474236722600211000ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore::Stream; repeat_each(2); plan tests => repeat_each() * (blocks() * 4); $ENV{TEST_NGINX_LUA_PACKAGE_PATH} = "$t::TestCore::Stream::lua_package_path"; $ENV{TEST_NGINX_UPSTREAM_PORT} ||= get_unused_port 12345; no_long_string(); run_tests(); __DATA__ === TEST 1: balancer --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; upstream backend { server 0.0.0.1:1234 down; balancer_by_lua_block { local b = require "ngx.balancer" assert(b.set_current_peer("127.0.0.1", $TEST_NGINX_UPSTREAM_PORT)) } } server { listen 127.0.0.1:$TEST_NGINX_UPSTREAM_PORT; content_by_lua_block { ngx.print(ngx.var.remote_addr, ":", ngx.var.remote_port) } } --- stream_server_config proxy_pass backend; --- request GET /t --- response_body eval [ qr/127.0.0.1/, ] --- error_code: 200 --- no_error_log [error] [warn] === TEST 2: balancer with bind_to_local_addr (addr) --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; upstream backend { server 0.0.0.1:1234 down; balancer_by_lua_block { local b = require "ngx.balancer" assert(b.set_current_peer("127.0.0.1", $TEST_NGINX_UPSTREAM_PORT)) assert(b.bind_to_local_addr("127.0.0.4")) } } server { listen 127.0.0.1:$TEST_NGINX_UPSTREAM_PORT; content_by_lua_block { ngx.print(ngx.var.remote_addr, ":", ngx.var.remote_port) } } --- stream_server_config proxy_pass backend; --- request GET /t --- response_body eval [ qr/127.0.0.4/, ] --- error_code: 200 --- no_error_log [error] [warn] === TEST 3: balancer with bind_to_local_addr (addr and port) --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; upstream backend { server 0.0.0.1:1234 down; balancer_by_lua_block { local b = require "ngx.balancer" assert(b.set_current_peer("127.0.0.1", $TEST_NGINX_UPSTREAM_PORT)) assert(b.bind_to_local_addr("127.0.0.8:23456")) } } server { listen 127.0.0.1:$TEST_NGINX_UPSTREAM_PORT; content_by_lua_block { ngx.print(ngx.var.remote_addr, ":", ngx.var.remote_port) } } --- stream_server_config proxy_pass backend; --- request GET /t --- response_body eval [ qr/127.0.0.8/, ] --- error_code: 200 --- no_error_log [error] [warn] lua-resty-core-0.1.31/t/stream/balancer-keepalive.t000066400000000000000000000023361474236722600221250ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore::Stream; repeat_each(2); plan tests => repeat_each() * (blocks() * 2); no_long_string(); run_tests(); __DATA__ === TEST 1: set_current_peer: NYI 'opts' argument --- stream_config upstream backend { server 127.0.0.1:12345; balancer_by_lua_block { local b = require "ngx.balancer" local pok, perr = pcall(b.set_current_peer, "127.0.0.3", 12345, "abc") if not pok then ngx.log(ngx.ERR, perr) end } } --- stream_server_config proxy_pass backend; --- error_log eval qr/balancer_by_lua:\d+: bad argument #3 to 'set_current_peer' \('host' not yet implemented in stream subsystem\)/ === TEST 2: enable_keepalive: NYI --- stream_config upstream backend { server 127.0.0.1:12345; balancer_by_lua_block { local b = require "ngx.balancer" local pok, perr = pcall(b.enable_keepalive) if not pok then ngx.log(ngx.ERR, perr) end } } --- stream_server_config proxy_pass backend; --- error_log eval qr/balancer_by_lua:\d+: 'enable_keepalive' not yet implemented in stream subsystem/ lua-resty-core-0.1.31/t/stream/balancer-timeout.t000066400000000000000000000203151474236722600216430ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: BEGIN { if (!defined $ENV{LD_PRELOAD}) { $ENV{LD_PRELOAD} = ''; } if ($ENV{LD_PRELOAD} !~ /\bmockeagain\.so\b/) { $ENV{LD_PRELOAD} = "mockeagain.so $ENV{LD_PRELOAD}"; } if (defined $ENV{MOCKEAGAIN} && $ENV{MOCKEAGAIN} eq 'r') { $ENV{MOCKEAGAIN} = 'rw'; } else { $ENV{MOCKEAGAIN} = 'w'; } $ENV{TEST_NGINX_EVENT_TYPE} = 'poll'; $ENV{TEST_NGINX_POSTPONE_OUTPUT} = 1; } use lib '.'; use t::TestCore::Stream; #worker_connections(1014); #master_on(); #workers(2); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 3 + 5); $ENV{TEST_NGINX_LUA_PACKAGE_PATH} = "$t::TestCore::Stream::lua_package_path"; #worker_connections(1024); #no_diff(); no_long_string(); run_tests(); __DATA__ === TEST 1: set_timeouts --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen $TEST_NGINX_RAND_PORT_1; return "fake origin\n"; } upstream backend { server 0.0.0.1:1234; balancer_by_lua_block { local b = require "ngx.balancer" assert(b.set_timeouts(1.234, 5.678, 7.689)) assert(b.set_current_peer("127.0.0.1", tonumber($TEST_NGINX_RAND_PORT_1))) } } --- stream_server_config proxy_pass backend; --- response_body fake origin --- grep_error_log eval: qr/event timer add: \d+: (?:1234|5678|7689):/ --- grep_error_log_out eval qr/\Aevent timer add: \d+: 1234: event timer add: \d+: 7689: \z/ --- no_error_log [warn] === TEST 2: set_timeouts (nil connect timeout) --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; proxy_connect_timeout 1234ms; server { listen $TEST_NGINX_RAND_PORT_1; return "fake origin\n"; } upstream backend { server 0.0.0.1:1234; balancer_by_lua_block { local b = require "ngx.balancer" assert(b.set_timeouts(nil, 5.678, 7.689)) assert(b.set_current_peer("127.0.0.1", tonumber($TEST_NGINX_RAND_PORT_1))) } } --- stream_server_config proxy_pass backend; --- stream_response fake origin --- grep_error_log eval: qr/event timer add: \d+: (?:1234|5678|7689):/ --- grep_error_log_out eval qr/\Aevent timer add: \d+: 1234: event timer add: \d+: 7689: \z/ --- no_error_log [warn] === TEST 3: set_timeouts (nil send timeout) --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; proxy_timeout 5678ms; server { listen $TEST_NGINX_RAND_PORT_1; return "fake origin\n"; } upstream backend { server 0.0.0.1:1234; balancer_by_lua_block { local b = require "ngx.balancer" assert(b.set_timeouts(1.234, nil, 7.689)) assert(b.set_current_peer("127.0.0.1", tonumber($TEST_NGINX_RAND_PORT_1))) } } --- stream_server_config proxy_pass backend; --- stream_response fake origin --- grep_error_log eval: qr/event timer add: \d+: (?:1234|5678|7689):/ --- grep_error_log_out eval qr/\Aevent timer add: \d+: 1234: event timer add: \d+: 7689: \z/ --- no_error_log [warn] === TEST 4: set_timeouts (nil read timeout) --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; proxy_timeout 7689ms; server { listen $TEST_NGINX_RAND_PORT_1; return "fake origin\n"; } upstream backend { server 0.0.0.1:1234; balancer_by_lua_block { local b = require "ngx.balancer" assert(b.set_timeouts(1.234, 5.678, nil)) assert(b.set_current_peer("127.0.0.1", tonumber($TEST_NGINX_RAND_PORT_1))) } } --- stream_server_config proxy_pass backend; --- stream_response fake origin --- grep_error_log eval: qr/event timer add: \d+: (?:1234|5678|7689):/ --- grep_error_log_out eval qr/\Aevent timer add: \d+: 1234: event timer add: \d+: 5678: \z/ --- no_error_log [warn] === TEST 5: set connect timeout to 0 --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; upstream backend { server 0.0.0.1:1234; balancer_by_lua_block { local b = require "ngx.balancer" assert(b.set_timeouts(0, 1.234, 5.678)) assert(b.set_current_peer("127.0.0.1", tonumber($TEST_NGINX_RAND_PORT_1))) } } --- stream_server_config proxy_pass backend; --- error_log eval qr/\[error\] .*? balancer_by_lua:3: bad connect timeout/ --- no_error_log [warn] === TEST 6: set connect timeout to -1 --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; upstream backend { server 0.0.0.1:1234; balancer_by_lua_block { local b = require "ngx.balancer" assert(b.set_timeouts(-1, 1.234, 5.678)) assert(b.set_current_peer("127.0.0.1", tonumber($TEST_NGINX_RAND_PORT_1))) } } --- stream_server_config proxy_pass backend; --- error_log eval qr/\[error\] .*? balancer_by_lua:3: bad connect timeout/ --- no_error_log [warn] === TEST 7: set send timeout to 0 --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; upstream backend { server 0.0.0.1:1234; balancer_by_lua_block { local b = require "ngx.balancer" assert(b.set_timeouts(1.234, 0, 5.678)) assert(b.set_current_peer("127.0.0.1", tonumber($TEST_NGINX_RAND_PORT_1))) } } --- stream_server_config proxy_pass backend; --- error_log eval qr/\[error\] .*? balancer_by_lua:3: bad send timeout/ --- no_error_log [warn] === TEST 8: set send timeout to -1 --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; upstream backend { server 0.0.0.1:1234; balancer_by_lua_block { local b = require "ngx.balancer" assert(b.set_timeouts(1.234, -1, 5.678)) assert(b.set_current_peer("127.0.0.1", tonumber($TEST_NGINX_RAND_PORT_1))) } } --- stream_server_config proxy_pass backend; --- error_log eval qr/\[error\] .*? balancer_by_lua:3: bad send timeout/ --- no_error_log [warn] === TEST 9: set read timeout to 0 --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; upstream backend { server 0.0.0.1:1234; balancer_by_lua_block { local b = require "ngx.balancer" assert(b.set_timeouts(1.234, 4.567, 0)) assert(b.set_current_peer("127.0.0.1", tonumber($TEST_NGINX_RAND_PORT_1))) } } --- stream_server_config proxy_pass backend; --- error_log eval qr/\[error\] .*? balancer_by_lua:3: bad read timeout/ --- no_error_log [warn] === TEST 10 set read timeout to -1 --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; upstream backend { server 0.0.0.1:1234; balancer_by_lua_block { local b = require "ngx.balancer" assert(b.set_timeouts(1.234, 4.567, -1)) assert(b.set_current_peer("127.0.0.1", tonumber($TEST_NGINX_RAND_PORT_1))) } } --- stream_server_config proxy_pass backend; --- error_log eval qr/\[error\] .*? balancer_by_lua:3: bad read timeout/ --- no_error_log [warn] === TEST 11: set_timeouts called in a wrong context --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; --- stream_server_config content_by_lua_block { local balancer = require "ngx.balancer" local ok, err = balancer.set_timeouts(1, 1, 1) if not ok then ngx.say("failed to call: ", err) return end ngx.say("unexpected success!") } --- stream_response failed to call: API disabled in the current context --- no_error_log [error] [alert] === TEST 12: set_timeouts called with a non-numerical parameter --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; upstream backend { server 0.0.0.1:1234; balancer_by_lua_block { local balancer = require "ngx.balancer" local ok, err = balancer.set_timeouts("1.234", 1, 1) if not ok then ngx.log(ngx.ERR, "failed to call: ", err) end } } --- stream_server_config proxy_pass backend; --- error_log eval qr/\[error\] .*? bad connect timeout/ --- no_error_log [alert] lua-resty-core-0.1.31/t/stream/balancer.t000066400000000000000000000136151474236722600201640ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore::Stream; #worker_connections(1014); #master_on(); #workers(2); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 3 + 2); $ENV{TEST_NGINX_LUA_PACKAGE_PATH} = "$t::TestCore::Stream::lua_package_path"; #worker_connections(1024); #no_diff(); no_long_string(); run_tests(); __DATA__ === TEST 1: set current peer (separate addr and port) --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; upstream backend { server 0.0.0.1:1234; balancer_by_lua_block { print("hello from balancer by lua!") local b = require "ngx.balancer" assert(b.set_current_peer("127.0.0.3", 12345)) } } --- stream_server_config proxy_pass backend; --- error_log eval [ '[lua] balancer_by_lua:2: hello from balancer by lua! while connecting to upstream,', qr{connect\(\) failed .*?, upstream: "127\.0\.0\.3:12345"}, ] --- no_error_log [warn] === TEST 2: set current peer & next upstream (3 tries) --- skip_nginx: 4: < 1.7.5 --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; proxy_next_upstream on; proxy_next_upstream_tries 10; upstream backend { server 0.0.0.1:1234; balancer_by_lua_block { print("hello from balancer by lua!") local b = require "ngx.balancer" if not ngx.ctx.tries then ngx.ctx.tries = 0 end if ngx.ctx.tries < 2 then local ok, err = b.set_more_tries(1) if not ok then return error("failed to set more tries: ", err) elseif err then ngx.log(ngx.WARN, "set more tries: ", err) end end ngx.ctx.tries = ngx.ctx.tries + 1 assert(b.set_current_peer("127.0.0.3", 12345)) } } --- stream_server_config proxy_pass backend; --- grep_error_log eval: qr{connect\(\) failed .*, upstream: ".*?"} --- grep_error_log_out eval qr#^(?:connect\(\) failed .*?, upstream: "127.0.0.3:12345"\n){3}$# --- no_error_log [warn] === TEST 3: set current peer & next upstream (no retries) --- skip_nginx: 4: < 1.7.5 --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; proxy_next_upstream on; upstream backend { server 0.0.0.1:1234; balancer_by_lua_block { print("hello from balancer by lua!") local b = require "ngx.balancer" if not ngx.ctx.tries then ngx.ctx.tries = 0 end ngx.ctx.tries = ngx.ctx.tries + 1 assert(b.set_current_peer("127.0.0.3", 12345)) } } --- stream_server_config proxy_pass backend; --- grep_error_log eval: qr{connect\(\) failed .*, upstream: ".*?"} --- grep_error_log_out eval qr#^(?:connect\(\) failed .*?, upstream: "127.0.0.3:12345"\n){1}$# --- no_error_log [warn] === TEST 4: set current peer & next upstream (3 tries exceeding the limit) --- skip_nginx: 4: < 1.7.5 --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; proxy_next_upstream on; proxy_next_upstream_tries 2; upstream backend { server 0.0.0.1:1234; balancer_by_lua_block { local b = require "ngx.balancer" if not ngx.ctx.tries then ngx.ctx.tries = 0 end if ngx.ctx.tries < 2 then local ok, err = b.set_more_tries(1) if not ok then return error("failed to set more tries: ", err) elseif err then ngx.log(ngx.WARN, "set more tries: ", err) end end ngx.ctx.tries = ngx.ctx.tries + 1 assert(b.set_current_peer("127.0.0.3", 12345)) } } --- stream_server_config proxy_pass backend; --- grep_error_log eval: qr{connect\(\) failed .*, upstream: ".*?"} --- grep_error_log_out eval qr#^(?:connect\(\) failed .*?, upstream: "127.0.0.3:12345"\n){2}$# --- error_log set more tries: reduced tries due to limit === TEST 5: get last peer failure status (connect failed) --- skip_nginx: 4: < 1.7.5 --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; proxy_next_upstream on; proxy_next_upstream_tries 10; upstream backend { server 0.0.0.1:1234; balancer_by_lua_block { local b = require "ngx.balancer" local state, status = b.get_last_failure() print("last peer failure: ", state, " ", status) if not ngx.ctx.tries then ngx.ctx.tries = 0 end if ngx.ctx.tries < 2 then local ok, err = b.set_more_tries(1) if not ok then return error("failed to set more tries: ", err) elseif err then ngx.log(ngx.WARN, "set more tries: ", err) end end ngx.ctx.tries = ngx.ctx.tries + 1 assert(b.set_current_peer("127.0.0.3", 12345)) } } --- stream_server_config proxy_pass backend; --- grep_error_log eval: qr{last peer failure: \S+ \S+} --- grep_error_log_out last peer failure: nil nil last peer failure: failed 0 last peer failure: failed 0 --- no_error_log [warn] === TEST 6: set current peer (port embedded in addr) --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; upstream backend { server 0.0.0.1:1234; balancer_by_lua_block { print("hello from balancer by lua!") local b = require "ngx.balancer" assert(b.set_current_peer("127.0.0.3:12345")) } } --- stream_server_config proxy_pass backend; --- error_log eval [ '[lua] balancer_by_lua:2: hello from balancer by lua! while connecting to upstream,', qr{connect\(\) failed .*?, upstream: "127\.0\.0\.3:12345"}, ] --- no_error_log [warn] lua-resty-core-0.1.31/t/stream/ctx.t000066400000000000000000000157241474236722600172160ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore::Stream; repeat_each(2); plan tests => repeat_each() * (blocks() * 3 + 4); $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: ngx.ctx in ssl_certificate_by_lua --- stream_config server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; ssl_certificate_by_lua_block { ngx.ctx.answer = 42 ngx.log(ngx.WARN, "ngx.ctx.answer = ", ngx.ctx.answer) ngx.ctx.count = 0 } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; content_by_lua_block { ngx.say(ngx.ctx.answer) ngx.ctx.count = ngx.ctx.count + 1 ngx.say(ngx.ctx.count) } } --- stream_server_config lua_ssl_trusted_certificate ../../cert/test.crt; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local function run() local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end while true do local line, err = sock:receive() if not line then break end ngx.say("received: ", line) end sock:close() end run() end -- do -- collectgarbage() } --- stream_response received: 42 received: 1 --- error_log ngx.ctx.answer = 42 --- grep_error_log eval qr/lua release ngx.ctx at ref \d+/ --- grep_error_log_out eval ["lua release ngx.ctx at ref 2 lua release ngx.ctx at ref 1 ", "lua release ngx.ctx at ref 2 lua release ngx.ctx at ref 1 lua release ngx.ctx at ref 2 lua release ngx.ctx at ref 1 "] --- no_error_log [error] === TEST 2: ngx.ctx in ssl_certificate_by_lua (share objects) --- stream_config server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; ssl_certificate_by_lua_block { ngx.ctx.req = { count = 0 } } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; content_by_lua_block { ngx.ctx.req.count = ngx.ctx.req.count + 1 ngx.say(ngx.ctx.req.count) } } --- stream_server_config lua_ssl_trusted_certificate ../../cert/test.crt; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local function run() local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end while true do local line, err = sock:receive() if not line then break end ngx.say("received: ", line) end sock:close() end run() end -- do -- collectgarbage() } --- stream_response received: 1 --- no_error_log [error] === TEST 3: ngx.ctx in ssl_certificate_by_lua (release ctx when client aborted) --- stream_config server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" ssl.clear_certs() ngx.ctx.answer = 42 } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; return "ok"; } --- stream_server_config lua_ssl_trusted_certificate ../../cert/test.crt; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) end sock:close() end -- do -- collectgarbage() } --- stream_response failed to do SSL handshake: handshake failed --- grep_error_log eval qr/lua release ngx.ctx at ref \d+/ --- grep_error_log_out eval ["lua release ngx.ctx at ref 1 ", "lua release ngx.ctx at ref 1 lua release ngx.ctx at ref 1 "] === TEST 4: ngx.ctx in ssl_client_hello_by_lua --- stream_config server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; ssl_client_hello_by_lua_block { ngx.ctx.answer = 42 ngx.log(ngx.WARN, "ngx.ctx.answer = ", ngx.ctx.answer) ngx.ctx.count = 0 } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; content_by_lua_block { ngx.say(ngx.ctx.answer) ngx.ctx.count = ngx.ctx.count + 1 ngx.say(ngx.ctx.count) } } --- stream_server_config lua_ssl_trusted_certificate ../../cert/test.crt; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local function run() local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end while true do local line, err = sock:receive() if not line then break end ngx.say("received: ", line) end sock:close() end run() end -- do -- collectgarbage() } --- stream_response received: 42 received: 1 --- error_log ngx.ctx.answer = 42 --- grep_error_log eval qr/lua release ngx.ctx at ref \d+/ --- grep_error_log_out eval ["lua release ngx.ctx at ref 2 lua release ngx.ctx at ref 1 ", "lua release ngx.ctx at ref 2 lua release ngx.ctx at ref 1 lua release ngx.ctx at ref 2 lua release ngx.ctx at ref 1 "] --- no_error_log [error] lua-resty-core-0.1.31/t/stream/errlog-raw-log.t000066400000000000000000000106551474236722600212560ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore::Stream; log_level('error'); repeat_each(1); plan tests => repeat_each() * (blocks() * 2 + 5); add_block_preprocessor(sub { my $block = shift; my $stream_config = $block->stream_config || ''; my $init_by_lua_block = $block->init_by_lua_block || ''; $stream_config .= <<_EOC_; lua_package_path '$t::TestCore::Stream::lua_package_path'; init_by_lua_block { $t::TestCore::Stream::init_by_lua_block $init_by_lua_block } _EOC_ $block->set_value("stream_config", $stream_config); }); no_long_string(); run_tests(); __DATA__ === TEST 1: errlog.raw_log with bad log level (ngx.ERROR, -1) --- stream_server_config content_by_lua_block { local errlog = require "ngx.errlog" local pok, err = pcall(errlog.raw_log, ngx.ERROR, "hello, log") if not pok then ngx.say("not ok: ", err) return end ngx.say("ok") } --- stream_response not ok: bad log level --- no_error_log [error] === TEST 2: errlog.raw_log with bad levels (9) --- stream_server_config content_by_lua_block { local errlog = require "ngx.errlog" local pok, err = pcall(errlog.raw_log, 9, "hello, log") if not pok then ngx.say("not ok: ", err) return end ngx.say("ok") } --- stream_response not ok: bad log level --- no_error_log [error] === TEST 3: errlog.raw_log with bad log message --- stream_server_config content_by_lua_block { local errlog = require "ngx.errlog" local pok, err = pcall(errlog.raw_log, ngx.ERR, 123) if not pok then ngx.say("not ok: ", err) return end ngx.say("ok") } --- stream_response not ok: bad argument #2 to 'raw_log' (must be a string) --- no_error_log [error] === TEST 4: errlog.raw_log test log-level ERR --- stream_server_config content_by_lua_block { local errlog = require "ngx.errlog" errlog.raw_log(ngx.ERR, "hello world") } --- error_log eval qr/\[error\] \S+: \S+ hello world/ === TEST 5: errlog.raw_log JITs --- init_by_lua_block -- local verbose = true local verbose = false local outfile = errlog_file -- local outfile = "/tmp/v.log" if verbose then local dump = require "jit.dump" dump.on(nil, outfile) else local v = require "jit.v" v.on(outfile) end require "resty.core" -- jit.opt.start("hotloop=1") -- jit.opt.start("loopunroll=1000000") -- jit.off() --- stream_server_config content_by_lua_block { local errlog = require "ngx.errlog" for i = 1, 100 do errlog.raw_log(ngx.ERR, "hello world") end } --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx.conf:\d+\):4 loop\]/ === TEST 6: errlog.raw_log in init_by_lua --- init_by_lua_block local errlog = require "ngx.errlog" errlog.raw_log(ngx.ERR, "hello world from init_by_lua") --- stream_server_config content_by_lua_block { ngx.say("ok") } --- grep_error_log chop hello world from init_by_lua --- grep_error_log_out eval ["hello world from init_by_lua\n", ""] === TEST 7: errlog.raw_log in init_worker_by_lua --- stream_config init_worker_by_lua_block { local errlog = require "ngx.errlog" errlog.raw_log(ngx.ERR, "hello world from init_worker_by_lua") } --- stream_server_config content_by_lua_block { ngx.say("ok") } --- grep_error_log chop hello world from init_worker_by_lua --- grep_error_log_out eval ["hello world from init_worker_by_lua\n", ""] === TEST 8: errlog.raw_log with \0 in the log message --- stream_server_config content_by_lua_block { local errlog = require "ngx.errlog" errlog.raw_log(ngx.ERR, "hello\0world") ngx.say("ok") } --- stream_response ok --- error_log eval "hello\0world, client: " === TEST 9: errlog.raw_log is captured by errlog.get_logs() --- stream_config lua_capture_error_log 4k; --- stream_server_config content_by_lua_block { local errlog = require "ngx.errlog" errlog.raw_log(ngx.ERR, "hello from raw_log()") local res, err = errlog.get_logs() if not res then error("FAILED " .. err) end ngx.say("log lines: ", #res / 3) } --- stream_response log lines: 1 --- error_log eval qr/\[error\] .*? hello from raw_log\(\)/ --- skip_nginx: 3: <1.11.2 lua-resty-core-0.1.31/t/stream/errlog.t000066400000000000000000000727661474236722600177230ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore::Stream; #worker_connections(1014); #master_process_enabled(1); log_level('error'); repeat_each(2); plan tests => repeat_each() * (blocks() * 2 + 10); add_block_preprocessor(sub { my $block = shift; my $stream_config = $block->stream_config || ''; $stream_config .= <<_EOC_; lua_package_path '$t::TestCore::Stream::lua_package_path'; init_by_lua_block { $t::TestCore::Stream::init_by_lua_block $init_by_lua_block } _EOC_ $block->set_value("stream_config", $stream_config); }); #no_diff(); no_long_string(); #check_accum_error_log(); run_tests(); __DATA__ === TEST 1: sanity --- stream_config lua_capture_error_log 4m; --- stream_server_config content_by_lua_block { ngx.log(ngx.ERR, "enter 1") ngx.log(ngx.ERR, "enter 11") local errlog = require "ngx.errlog" local res, err = errlog.get_logs() if not res then error("FAILED " .. err) end ngx.say("log lines:", #res / 3) } --- stream_response log lines:2 --- grep_error_log eval qr/enter \d+/ --- grep_error_log_out eval [ "enter 1 enter 11 ", "enter 1 enter 11 " ] --- skip_nginx: 3: <1.11.2 === TEST 2: overflow captured error logs --- stream_config lua_capture_error_log 4k; --- stream_server_config content_by_lua_block { ngx.log(ngx.ERR, "enter 1") ngx.log(ngx.ERR, "enter 22" .. string.rep("a", 4096)) local errlog = require "ngx.errlog" local res, err = errlog.get_logs() if not res then error("FAILED " .. err) end ngx.say("log lines:", #res / 3) } --- stream_response log lines:1 --- grep_error_log eval qr/enter \d+/ --- grep_error_log_out eval [ "enter 1 enter 22 ", "enter 1 enter 22 " ] --- skip_nginx: 3: <1.11.2 === TEST 3: client connected info --- log_level: info --- stream_config lua_capture_error_log 4m; --- stream_server_config content_by_lua_block { local errlog = require "ngx.errlog" local res, err = errlog.get_logs() if not res then error("FAILED " .. err) end ngx.log(ngx.ERR, "capture log line:", #res / 3) } --- grep_error_log eval qr/capture log line:\d+|client .*? connected to .*?/ --- grep_error_log_out eval [ qr/^client .*? connected to .*? capture log line:1 $/, qr/^client .*? connected to .*? capture log line:2 $/ ] --- skip_nginx: 2: <1.11.2 === TEST 4: 500 error --- stream_config lua_capture_error_log 4m; --- stream_server_config content_by_lua_block { local t = {}/4 } log_by_lua_block { local errlog = require "ngx.errlog" local res, err = errlog.get_logs() if not res then error("FAILED " .. err) end ngx.log(ngx.ERR, "capture log line:", #res / 3) } --- grep_error_log eval qr/capture log line:\d+|attempt to perform arithmetic on a table value/ --- grep_error_log_out eval [ qr/^attempt to perform arithmetic on a table value capture log line:1 $/, qr/^attempt to perform arithmetic on a table value capture log line:2 $/ ] --- skip_nginx: 2: <1.11.2 === TEST 5: no error log --- stream_config lua_capture_error_log 4m; --- stream_server_config content_by_lua_block { ngx.say("hello") } log_by_lua_block { local errlog = require "ngx.errlog" local res, err = errlog.get_logs() if not res then error("FAILED " .. err) end ngx.log(ngx.ERR, "capture log line:", #res / 3) } --- stream_response hello --- grep_error_log eval qr/capture log line:\d+/ --- grep_error_log_out eval [ qr/^capture log line:0 $/, qr/^capture log line:1 $/ ] --- skip_nginx: 3: <1.11.2 === TEST 6: customize the log path --- stream_config lua_capture_error_log 4m; error_log logs/error_stream.log error; --- stream_server_config error_log logs/error.log error; content_by_lua_block { ngx.log(ngx.ERR, "enter access /t") ngx.say("hello") } log_by_lua_block { local errlog = require "ngx.errlog" local res, err = errlog.get_logs() if not res then error("FAILED " .. err) end ngx.log(ngx.ERR, "capture log line:", #res / 3) } --- stream_response hello --- grep_error_log eval qr/capture log line:\d+|enter access/ --- grep_error_log_out eval [ qr/^enter access capture log line:1 $/, qr/^enter access capture log line:2 $/ ] --- skip_nginx: 3: <1.11.2 === TEST 7: invalid size (< 4k) --- stream_config lua_capture_error_log 3k; --- stream_server_config content_by_lua_block { ngx.say("hello") } --- must_die --- error_log invalid capture error log size "3k", minimum size is 4096 --- skip_nginx: 2: <1.11.2 === TEST 8: invalid size (no argu) --- stream_config lua_capture_error_log; --- stream_server_config content_by_lua_block { ngx.say("hello") } --- must_die --- error_log invalid number of arguments in "lua_capture_error_log" directive --- skip_nginx: 2: <1.11.2 === TEST 9: without directive + ngx.errlog --- stream_server_config content_by_lua_block { ngx.log(ngx.ERR, "enter 1") local errlog = require "ngx.errlog" local res, err = errlog.get_logs() if not res then error("FAILED " .. err) end ngx.say("log lines:", #res / 3) } --- error_log directive "lua_capture_error_log" is not set --- skip_nginx: 3: <1.11.2 === TEST 10: without directive + ngx.set_filter_level --- stream_server_config content_by_lua_block { local errlog = require "ngx.errlog" local status, err = errlog.set_filter_level(ngx.ERR) if not status then error(err) end } --- error_log directive "lua_capture_error_log" is not set --- skip_nginx: 3: <1.11.2 === TEST 11: filter log by level(ngx.INFO) --- stream_config lua_capture_error_log 4m; --- stream_server_config content_by_lua_block { local errlog = require "ngx.errlog" local status, err = errlog.set_filter_level(ngx.INFO) if not status then error(err) end ngx.log(ngx.NOTICE, "-->1") ngx.log(ngx.WARN, "-->2") ngx.log(ngx.ERR, "-->3") local res = errlog.get_logs() ngx.say("log lines:", #res / 3) } --- log_level: notice --- stream_response log lines:3 --- grep_error_log eval qr/-->\d+/ --- grep_error_log_out eval [ "-->1 -->2 -->3 ", "-->1 -->2 -->3 " ] --- skip_nginx: 3: <1.11.2 === TEST 12: filter log by level(ngx.WARN) --- stream_config lua_capture_error_log 4m; --- stream_server_config content_by_lua_block { local errlog = require "ngx.errlog" local status, err = errlog.set_filter_level(ngx.WARN) if not status then error(err) end ngx.log(ngx.NOTICE, "-->1") ngx.log(ngx.WARN, "-->2") ngx.log(ngx.ERR, "-->3") local res = errlog.get_logs() ngx.say("log lines:", #res / 3) } --- log_level: notice --- stream_response log lines:2 --- grep_error_log eval qr/-->\d+/ --- grep_error_log_out eval [ "-->1 -->2 -->3 ", "-->1 -->2 -->3 " ] --- skip_nginx: 3: <1.11.2 === TEST 13: filter log by level(ngx.CRIT) --- stream_config lua_capture_error_log 4m; --- log_level: notice --- stream_server_config content_by_lua_block { local errlog = require "ngx.errlog" local status, err = errlog.set_filter_level(ngx.CRIT) if not status then error(err) end ngx.log(ngx.NOTICE, "-->1") ngx.log(ngx.WARN, "-->2") ngx.log(ngx.ERR, "-->3") local res = errlog.get_logs() ngx.say("log lines:", #res / 3) } --- stream_response log lines:0 --- grep_error_log eval qr/-->\d+/ --- grep_error_log_out eval [ "-->1 -->2 -->3 ", "-->1 -->2 -->3 " ] --- skip_nginx: 3: <1.11.2 === TEST 14: set max count and reuse table --- stream_config lua_capture_error_log 4m; --- stream_server_config content_by_lua_block { tab_clear = require "table.clear" ngx.log(ngx.ERR, "enter 1") ngx.log(ngx.ERR, "enter 22") ngx.log(ngx.ERR, "enter 333") local errlog = require "ngx.errlog" local res = {} local err res, err = errlog.get_logs(2, res) if not res then error("FAILED " .. err) end ngx.say("log lines:", #res / 3) tab_clear(res) res, err = errlog.get_logs(2, res) if not res then error("FAILED " .. err) end ngx.say("log lines:", #res / 3) } --- stream_response log lines:2 log lines:1 --- skip_nginx: 2: <1.11.2 === TEST 15: wrong argument --- stream_config lua_capture_error_log 4m; --- stream_server_config content_by_lua_block { local errlog = require "ngx.errlog" local status, err = errlog.set_filter_level() if not status then error(err) end } --- grep_error_log eval qr/missing \"level\" argument/ --- grep_error_log_out eval [ "missing \"level\" argument ", "missing \"level\" argument ", ] --- skip_nginx: 3: <1.11.2 === TEST 16: check the captured error log body --- stream_config lua_capture_error_log 4m; --- stream_server_config content_by_lua_block { local errlog = require "ngx.errlog" local status, err = errlog.set_filter_level(ngx.WARN) if not status then error(err) end ngx.log(ngx.NOTICE, "-->1") ngx.log(ngx.WARN, "-->2") ngx.log(ngx.ERR, "-->3") local res = errlog.get_logs() for i = 1, #res, 3 do ngx.say("log level:", res[i]) ngx.say("log body:", res[i + 2]) end } --- log_level: notice --- stream_response_like log level:5 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[warn\] (\d+).*content_by_lua\(nginx.conf:\d+\):\d+: -->2, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*content_by_lua\(nginx.conf:\d+\):\d+: -->3, client: 127.0.0.1, server: 0.0.0.0:\d+ --- grep_error_log eval qr/-->\d+/ --- grep_error_log_out eval [ "-->1 -->2 -->3 ", "-->1 -->2 -->3 " ] --- skip_nginx: 3: <1.11.2 === TEST 17: flood the capturing buffer (4k) --- stream_config lua_capture_error_log 4k; --- stream_server_config content_by_lua_block { local errlog = require "ngx.errlog" local status, err = errlog.set_filter_level(ngx.WARN) if not status then error(err) end for i = 1, 100 do ngx.log(ngx.NOTICE, "--> ", i) ngx.log(ngx.WARN, "--> ", i) ngx.log(ngx.ERR, "--> ", i) end local res = errlog.get_logs(1000) ngx.say("log lines: #", #res / 3) -- first 3 logs for i = 1, 3 * 3, 3 do ngx.say("log level:", res[i]) ngx.say("log body:", res[i + 2]) end -- last 3 logs for i = #res - 8, #res, 3 do ngx.say("log level:", res[i]) ngx.say("log body:", res[i + 2]) end } --- log_level: notice --- stream_response_like chomp \A(?:log lines: #26 log level:5 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[warn\] (\d+).*content_by_lua\(nginx.conf:\d+\):\d+: --> 88, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*content_by_lua\(nginx.conf:\d+\):\d+: --> 88, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:5 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[warn\] (\d+).*content_by_lua\(nginx.conf:\d+\):\d+: --> 89, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*content_by_lua\(nginx.conf:\d+\):\d+: --> 99, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:5 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[warn\] (\d+).*content_by_lua\(nginx.conf:\d+\):\d+: --> 100, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*content_by_lua\(nginx.conf:\d+\):\d+: --> 100, client: 127.0.0.1, server: 0.0.0.0:\d+ )\z --- skip_nginx: 2: <1.11.2 --- wait: 0.1 === TEST 18: flood the capturing buffer (5k) --- stream_config lua_capture_error_log 5k; --- stream_server_config content_by_lua_block { local errlog = require "ngx.errlog" local status, err = errlog.set_filter_level(ngx.WARN) if not status then error(err) end for i = 1, 100 do ngx.log(ngx.NOTICE, "--> ", i) ngx.log(ngx.WARN, "--> ", i) ngx.log(ngx.ERR, "--> ", i) end local res = errlog.get_logs(1000) ngx.say("log lines: #", #res / 3) -- first 3 logs for i = 1, 3 * 3, 3 do ngx.say("log level:", res[i]) ngx.say("log body:", res[i + 2]) end -- last 3 logs for i = #res - 8, #res, 3 do ngx.say("log level:", res[i]) ngx.say("log body:", res[i + 2]) end } --- log_level: notice --- stream_response_like chomp \A(?:log lines: #33 log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*content_by_lua\(nginx.conf:\d+\):\d+: --> 84, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:5 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[warn\] (\d+).*content_by_lua\(nginx.conf:\d+\):\d+: --> 85, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*content_by_lua\(nginx.conf:\d+\):\d+: --> 85, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*content_by_lua\(nginx.conf:\d+\):\d+: --> 99, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:5 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[warn\] (\d+).*content_by_lua\(nginx.conf:\d+\):\d+: --> 100, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*content_by_lua\(nginx.conf:\d+\):\d+: --> 100, client: 127.0.0.1, server: 0.0.0.0:\d+ )\z --- skip_nginx: 2: <1.11.2 --- wait: 0.1 === TEST 19: fetch a few and generate a few, then fetch again (overflown again) --- stream_config lua_capture_error_log 5k; --- stream_server_config content_by_lua_block { local errlog = require "ngx.errlog" local status, err = errlog.set_filter_level(ngx.WARN) if not status then error(err) end for i = 1, 100 do ngx.log(ngx.NOTICE, "--> ", i) ngx.log(ngx.WARN, "--> ", i) ngx.log(ngx.ERR, "--> ", i) end local res = errlog.get_logs(3) ngx.say("msg count: ", #res / 3) -- first 3 logs for i = 1, #res, 3 do ngx.say("log level:", res[i]) ngx.say("log body:", res[i + 2]) end ngx.log(ngx.ERR, "--> 101") ngx.log(ngx.ERR, "--> 102") ngx.log(ngx.ERR, "--> 103") ngx.log(ngx.ERR, "--> 104") local res = errlog.get_logs(3) ngx.say("msg count: ", #res / 3) -- first 3 logs for i = 1, #res, 3 do ngx.say("log level:", res[i]) ngx.say("log body:", res[i + 2]) end local res = errlog.get_logs(1000) -- last 3 logs for i = #res - 8, #res, 3 do ngx.say("log level:", res[i]) ngx.say("log body:", res[i + 2]) end } --- log_level: notice --- stream_response_like chomp \Amsg count: 3 log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: --> 84, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:5 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[warn\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: --> 85, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: --> 85, client: 127.0.0.1, server: 0.0.0.0:\d+ msg count: 3 log level:5 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[warn\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: --> 86, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: --> 86, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:5 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[warn\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: --> 87, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: --> 102, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: --> 103, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: --> 104, client: 127.0.0.1, server: 0.0.0.0:\d+ |msg count: 3 log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: --> 84, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:5 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[warn\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: --> 85, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: --> 85, client: 127.0.0.1, server: 0.0.0.0:\d+ msg count: 3 log level:5 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[warn\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: --> 87, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: --> 87, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:5 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[warn\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: --> 88, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: --> 102, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: --> 103, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: --> 104, client: 127.0.0.1, server: 0.0.0.0:\d+ \z --- skip_nginx: 2: <1.11.2 === TEST 20: fetch a few and generate a few, then fetch again (not overflown again) --- stream_config lua_capture_error_log 5k; --- stream_server_config content_by_lua_block { local errlog = require "ngx.errlog" local status, err = errlog.set_filter_level(ngx.WARN) if not status then error(err) end for i = 1, 100 do ngx.log(ngx.NOTICE, "--> ", i) ngx.log(ngx.WARN, "--> ", i) ngx.log(ngx.ERR, "--> ", i) end local res = errlog.get_logs(3) ngx.say("msg count: ", #res / 3) -- first 3 logs for i = 1, #res, 3 do ngx.say("log level:", res[i]) ngx.say("log body:", res[i + 2]) end ngx.log(ngx.ERR, "howdy, something new!") ngx.log(ngx.ERR, "howdy, something even newer!") local res = errlog.get_logs(3) ngx.say("msg count: ", #res / 3) -- first 3 logs for i = 1, #res, 3 do ngx.say("log level:", res[i]) ngx.say("log body:", res[i + 2]) end local res = errlog.get_logs(1000) -- last 3 logs for i = #res - 8, #res, 3 do ngx.say("log level:", res[i]) ngx.say("log body:", res[i + 2]) end } --- log_level: notice --- stream_response_like chomp \Amsg count: 3 log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: --> 84, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:5 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[warn\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: --> 85, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: --> 85, client: 127.0.0.1, server: 0.0.0.0:\d+ msg count: 3 log level:5 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[warn\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: --> 86, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: --> 86, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:5 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[warn\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: --> 87, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: --> 100, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: howdy, something new!, client: 127.0.0.1, server: 0.0.0.0:\d+ log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: howdy, something even newer!, client: 127.0.0.1, server: 0.0.0.0:\d+ \z --- skip_nginx: 2: <1.11.2 === TEST 21: multi-line error log --- stream_config lua_capture_error_log 4k; --- stream_server_config content_by_lua_block { local errlog = require "ngx.errlog" local status, err = errlog.set_filter_level(ngx.WARN) if not status then error(err) end ngx.log(ngx.ERR, "-->\n", "new line") local res = errlog.get_logs() ngx.say("log lines: #", #res / 3) for i = 1, #res, 3 do ngx.say("log level:", res[i]) ngx.say("log body:", res[i + 2]) end } --- log_level: notice --- stream_response_like chomp \Alog lines: #1 log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*content_by_lua\(nginx.conf:\d+\):\d+: --> new line, client: 127.0.0.1, server: 0.0.0.0:\d+ \z --- skip_nginx: 2: <1.11.2 === TEST 22: user-supplied Lua table to hold the result (get one log + no log) --- stream_config lua_capture_error_log 4k; --- stream_server_config content_by_lua_block { local errlog = require "ngx.errlog" local status, err = errlog.set_filter_level(ngx.WARN) if not status then error(err) end ngx.log(ngx.ERR, "-->\n", "new line") local t = {} for i = 1, 2 do local res = errlog.get_logs(10, t) ngx.say("maybe log lines: #", #res / 3) for j = 1, #res, 3 do local level, msg = res[j], res[j + 2] if not level then break end ngx.say("log level:", level) ngx.say("log body:", msg) end ngx.say("end") end } --- log_level: notice --- stream_response_like chomp \Amaybe log lines: #1 log level:4 log body:\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*content_by_lua\(nginx.conf:\d+\):\d+: --> new line, client: 127.0.0.1, server: 0.0.0.0:\d+ end maybe log lines: #1 end \z --- skip_nginx: 2: <1.11.2 === TEST 23: the system default filter level is "debug" --- stream_server_config content_by_lua_block { local errlog = require "ngx.errlog" ngx.print('Is "debug" the system default filter level? ', errlog.get_sys_filter_level() == ngx.DEBUG) } --- log_level: debug --- stream_response chomp Is "debug" the system default filter level? true === TEST 24: the system default filter level is "emerg" --- stream_server_config content_by_lua_block { local errlog = require "ngx.errlog" ngx.print('Is "emerg" the system default filter level? ', errlog.get_sys_filter_level() == ngx.EMERG) } --- log_level: emerg --- stream_response chomp Is "emerg" the system default filter level? true === TEST 25: get system default filter level during Nginx starts (init) --- SKIP --- init_by_lua_block require "resty.core" local errlog = require "ngx.errlog" package.loaded.log_level = errlog.get_sys_filter_level() --- stream_server_config content_by_lua_block { local log_level = package.loaded.log_level if log_level >= ngx.WARN then ngx.log(ngx.WARN, "log a warning event") else ngx.log(ngx.WARN, "do not log another warning event") end } --- log_level: warn --- error_log log a warning event --- no_error_log do not log another warning event === TEST 26: get system default filter level during Nginx worker starts (init worker) --- SKIP --- stream_config init_worker_by_lua_block { local errlog = require "ngx.errlog" package.loaded.log_level = errlog.get_sys_filter_level() } --- stream_server_config content_by_lua_block { local log_level = package.loaded.log_level if log_level >= ngx.WARN then ngx.log(ngx.WARN, "log a warning event") else ngx.log(ngx.WARN, "do not log another warning event") end } --- log_level: warn --- error_log log a warning event --- no_error_log do not log another warning event === TEST 27: sanity (with log time) --- stream_config lua_capture_error_log 4m; --- stream_server_config content_by_lua_block { ngx.log(ngx.ERR, "enter 1") ngx.log(ngx.ERR, "enter 11") local errlog = require "ngx.errlog" local res, err = errlog.get_logs(nil, nil, {fetch_time = true}) if not res then error("FAILED " .. err) end ngx.say("log lines:", #res / 3) } --- stream_response log lines:2 --- grep_error_log eval qr/enter \d+/ --- grep_error_log_out eval [ "enter 1 enter 11 ", "enter 1 enter 11 " ] --- skip_nginx: 3: <1.11.2 === TEST 28: log time eq ngx.now --- stream_config lua_capture_error_log 4m; --- stream_server_config content_by_lua_block { local now = ngx.now() ngx.log(ngx.CRIT, "enter 1") ngx.log(ngx.ERR, "enter 11") local errlog = require "ngx.errlog" local res, err = errlog.get_logs(nil, nil, {fetch_time = true}) if not res then error("FAILED " .. err) end ngx.say("log lines: ", #res / 3) for i = 1, #res, 3 do ngx.say("log level: ", res[i]) ngx.say("log time: ", res[i + 1]) ngx.say("log body: ", res[i + 2]) ngx.say("same with now: ", res[i + 1] == now) end } --- stream_response_like chomp \Alog lines: 2 log level: 3 log time: \d+(?:\.\d+)? log body: \d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[crit\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: enter 1, client: 127.0.0.1, server: 0.0.0.0:\d+ same with now: true log level: 4 log time: \d{10}(?:\.\d+)? log body: \d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: enter 11, client: 127.0.0.1, server: 0.0.0.0:\d+ same with now: true --- grep_error_log eval qr/enter \d+/ --- grep_error_log_out eval [ "enter 1 enter 11 ", "enter 1 enter 11 " ] --- skip_nginx: 3: <1.11.2 === TEST 29: ringbuf overflow bug --- stream_config lua_capture_error_log 4k; --- stream_server_config content_by_lua_block { local errlog = require "ngx.errlog" local msg = string.rep("*", 10) for i = 1, 2 do ngx.log(ngx.ERR, msg .. i) end for i = 1, 40 do local res = errlog.get_logs(1) if res and #res then ngx.log(ngx.ERR, msg .. i) end end local res = errlog.get_logs() for i = 1, #res, 3 do ngx.say("log level: ", res[i]) ngx.say("log time: ", res[i + 1]) ngx.say("log body: ", res[i + 2]) end } --- log_level: notice --- stream_response_like chomp log level: 4 log time: \d+(?:\.\d+)? log body: \d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: \*\*\*\*\*\*\*\*\*\*39, client: 127.0.0.1, server: 0.0.0.0:\d+ log level: 4 log time: \d{10}(?:\.\d+)? log body: \d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2} \[error\] (\d+).*?content_by_lua\(nginx.conf:\d+\):\d+: \*\*\*\*\*\*\*\*\*\*40, client: 127.0.0.1, server: 0.0.0.0:\d+ --- skip_nginx: 2: <1.11.2 === TEST 30: ringbuf sentinel bug1 --- stream_config lua_capture_error_log 4k; --- stream_server_config content_by_lua_block { local errlog = require "ngx.errlog" local msg = string.rep("a", 20) local bigmsg = string.rep("A", 3000) for i = 1, 10 do ngx.log(ngx.ERR, msg) end ngx.log(ngx.ERR, bigmsg) ngx.log(ngx.ERR, msg) local res = errlog.get_logs(2) ngx.say("log lines: #", #res / 3) for i = 1, #res, 3 do ngx.say(string.gsub(res[i + 2], "^.*([Aa][Aa][Aa]).*$", "%1"), "") end } --- log_level: notice --- stream_response log lines: #2 AAA aaa --- skip_nginx: 2: <1.11.2 === TEST 31: ringbuf sentinel bug2 --- stream_config lua_capture_error_log 4k; --- stream_server_config content_by_lua_block { local errlog = require "ngx.errlog" local msg = string.rep("a", 20) for i = 1, 20 do ngx.log(ngx.ERR, msg) end local res = errlog.get_logs(18) ngx.say("log lines: #", #res / 3) ngx.flush(true) for i = 1, 18 do ngx.log(ngx.ERR, msg) end local bigmsg = string.rep("A", 2000) ngx.log(ngx.ERR, bigmsg) local res = errlog.get_logs() ngx.say("log lines: #", #res / 3) ngx.flush(true) } --- log_level: notice --- stream_response_like chomp \A(?:log lines: #18 log lines: #1 |log lines: #18 log lines: #2 )\z --- skip_nginx: 2: <1.11.2 lua-resty-core-0.1.31/t/stream/misc.t000066400000000000000000000016661474236722600173530ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore::Stream; #worker_connections(1014); #master_on(); #workers(2); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 5); #worker_connections(1024); #no_diff(); no_long_string(); run_tests(); __DATA__ === TEST 1: base.check_subsystem --- stream_server_config content_by_lua_block { local base = require "resty.core.base" base.allows_subsystem('http', 'stream') base.allows_subsystem('stream') ngx.say("ok") } --- stream_response ok --- no_error_log [error] -- NYI: bad argument === TEST 2: base.check_subsystem with non-stream subsystem --- stream_server_config content_by_lua_block { local base = require "resty.core.base" base.allows_subsystem('http') ngx.say("ok") } --- stream_response --- no_error_log -- NYI: bad argument --- error_log unsupported subsystem: stream lua-resty-core-0.1.31/t/stream/os-getenv-hup.t000066400000000000000000000055641474236722600211220ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: our $SkipReason; BEGIN { if ($ENV{TEST_NGINX_CHECK_LEAK}) { $SkipReason = "unavailable for the hup tests"; } else { undef $ENV{TEST_NGINX_USE_STAP}; } } use lib '.'; use t::TestCore::Stream $SkipReason ? (skip_all => $SkipReason) : (); plan tests => repeat_each() * (blocks() * 2 + 1); no_shuffle(); use_hup(); $ENV{TEST_NGINX_BAR} = 'old'; $ENV{TEST_NGINX_LUA_PACKAGE_PATH} = "$t::TestCore::Stream::lua_package_path"; run_tests(); __DATA__ === TEST 1: env directive explicit value is visible within init_by_lua* --- main_config env FOO=old; --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { require "resty.core" package.loaded.foo = os.getenv("FOO") } --- stream_server_config content_by_lua_block { ngx.say(package.loaded.foo) } --- stream_response old --- error_log [notice] === TEST 2: HUP reload changes env value (1/3) --- main_config env FOO=new; --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { require "resty.core" package.loaded.foo = os.getenv("FOO") } --- stream_server_config content_by_lua_block { ngx.say(package.loaded.foo) } --- stream_response new === TEST 3: HUP reload changes env value (2/3) --- main_config env FOO=; --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { require "resty.core" package.loaded.foo = os.getenv("FOO") } --- stream_server_config content_by_lua_block { ngx.say(package.loaded.foo) } --- stream_response_like chomp \s === TEST 4: HUP reload changes env value (3/3) --- main_config env FOO; --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { require "resty.core" package.loaded.foo = os.getenv("FOO") } --- stream_server_config content_by_lua_block { ngx.say(package.loaded.foo) } --- stream_response nil === TEST 5: HUP reload changes visible environment variable (1/2) --- main_config env TEST_NGINX_BAR; --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { require "resty.core" package.loaded.test_nginx_bar = os.getenv("TEST_NGINX_BAR") } --- stream_server_config content_by_lua_block { ngx.say(package.loaded.test_nginx_bar) } --- stream_response old === TEST 6: HUP reload changes visible environment variable (2/2) --- main_config env TEST_NGINX_BAR=new; --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { require "resty.core" package.loaded.test_nginx_bar = os.getenv("TEST_NGINX_BAR") } --- stream_server_config content_by_lua_block { ngx.say(package.loaded.test_nginx_bar) } --- stream_response new lua-resty-core-0.1.31/t/stream/os-getenv.t000066400000000000000000000115501474236722600203200ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore::Stream; plan tests => repeat_each() * (blocks() * 2 + 1); $ENV{TEST_NGINX_BAR} = 'world'; $ENV{TEST_NGINX_LUA_PACKAGE_PATH} = "$t::TestCore::Stream::lua_package_path"; run_tests(); __DATA__ === TEST 1: env directive explicit value is visible within init_by_lua* --- main_config env FOO=hello; --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { require "resty.core" package.loaded.foo = os.getenv("FOO") } --- stream_server_config content_by_lua_block { ngx.say(package.loaded.foo, "\n", os.getenv("FOO")) } --- stream_response hello hello === TEST 2: env directive explicit value is visible within init_by_lua* with lua_shared_dict --- main_config env FOO=hello; --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; lua_shared_dict dogs 24k; init_by_lua_block { require "resty.core" package.loaded.foo = os.getenv("FOO") } --- stream_server_config content_by_lua_block { ngx.say(package.loaded.foo, "\n", os.getenv("FOO")) } --- stream_response hello hello === TEST 3: env directive explicit value is case-sensitive within init_by_lua* --- main_config env FOO=hello; --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { require "resty.core" package.loaded.foo = os.getenv("foo") } --- stream_server_config content_by_lua_block { ngx.say(package.loaded.foo, "\n", os.getenv("foo")) } --- stream_response nil nil === TEST 4: env directives with no value are ignored --- main_config env FOO; --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { require "resty.core" package.loaded.foo = os.getenv("FOO") } --- stream_server_config content_by_lua_block { ngx.say(package.loaded.foo, "\n", os.getenv("FOO")) } --- stream_response nil nil === TEST 5: env is visible from environment --- main_config env TEST_NGINX_BAR; --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { require "resty.core" package.loaded.foo = os.getenv("TEST_NGINX_BAR") } --- stream_server_config content_by_lua_block { ngx.say(package.loaded.foo, "\n", os.getenv("TEST_NGINX_BAR")) } --- stream_response world world === TEST 6: env explicit set vs environment set --- main_config env TEST_NGINX_BAR=goodbye; --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { require "resty.core" package.loaded.foo = os.getenv("TEST_NGINX_BAR") } --- stream_server_config content_by_lua_block { ngx.say(package.loaded.foo, "\n", os.getenv("TEST_NGINX_BAR")) } --- stream_response goodbye goodbye === TEST 7: env directive with empty value --- main_config env FOO=; --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { require "resty.core" package.loaded.foo = os.getenv("FOO") } --- stream_server_config content_by_lua_block { ngx.say("in init: ", package.loaded.foo, "\n", "in content: ", os.getenv("FOO")) } --- stream_response_like in init:\s+ in content:\s+ === TEST 8: os.getenv() overwrite is reverted in worker phases --- main_config env FOO=hello; --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { package.loaded.init_os_getenv = os.getenv } --- stream_server_config content_by_lua_block { ngx.say("FOO=", os.getenv("FOO")) if os.getenv ~= package.loaded.init_os_getenv then ngx.say("os.getenv() overwrite was reverted") else ngx.say("os.getenv() overwrite was not reverted") end } --- stream_response FOO=hello os.getenv() overwrite was reverted === TEST 9: os.getenv() can be localized after loading resty.core --- main_config env FOO=hello; --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { do local getenv = os.getenv package.loaded.f = function () ngx.log(ngx.NOTICE, "FOO: ", getenv("FOO")) end end require "resty.core" package.loaded.f() package.loaded.is_os_getenv = os.getenv == package.loaded.os_getenv } --- stream_server_config content_by_lua_block { package.loaded.f() package.loaded.f() if os.getenv ~= package.loaded.init_os_getenv then ngx.say("os.getenv() overwrite was reverted") else ngx.say("os.getenv() overwrite was not reverted") end } --- stream_response os.getenv() overwrite was reverted --- grep_error_log eval qr/FOO: [a-z]+/ --- grep_error_log_out FOO: hello FOO: hello FOO: hello lua-resty-core-0.1.31/t/stream/process-type-hup.t000066400000000000000000000034701474236722600216420ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: our $SkipReason; BEGIN { if ($ENV{TEST_NGINX_CHECK_LEAK}) { $SkipReason = "unavailable for the hup tests"; } } use lib '.'; use t::TestCore::Stream $SkipReason ? (skip_all => $SkipReason) : (); repeat_each(2); plan tests => repeat_each() * (blocks() * 4); add_block_preprocessor(sub { my $block = shift; my $stream_config = $block->stream_config || ''; $stream_config .= <<_EOC_; lua_package_path '$t::TestCore::Stream::lua_package_path'; init_by_lua_block { $t::TestCore::Stream::init_by_lua_block $init_by_lua_block local process = require "ngx.process" local ok, err = process.enable_privileged_agent() if not ok then ngx.log(ngx.ERR, "enable_privileged_agent failed: ", err) end } init_worker_by_lua_block { local base = require "resty.core.base" local typ = require "ngx.process".type if typ() == "privileged agent" then ngx.log(ngx.WARN, "process type: ", typ()) end } _EOC_ $block->set_value("stream_config", $stream_config); }); master_on(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: sanity --- stream_server_config content_by_lua_block { local typ = require "ngx.process".type local f, err = io.open(ngx.config.prefix() .. "/logs/nginx.pid", "r") if not f then ngx.say("failed to open nginx.pid: ", err) return end local pid = f:read() -- ngx.say("master pid: [", pid, "]") f:close() ngx.say("type: ", typ()) os.execute("kill -HUP " .. pid) } --- stream_response type: worker --- error_log init_worker_by_lua:6: process type: privileged --- no_error_log [error] --- skip_nginx: 4: < 1.11.2 --- wait: 0.1 lua-resty-core-0.1.31/t/stream/process-type-master.t000066400000000000000000000022731474236722600223410ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore::Stream; repeat_each(2); plan tests => repeat_each() * (blocks() * 5); add_block_preprocessor(sub { my $block = shift; my $stream_config = $block->stream_config || ''; $stream_config .= <<_EOC_; lua_package_path '$t::TestCore::Stream::lua_package_path'; init_by_lua_block { $t::TestCore::Stream::init_by_lua_block $init_by_lua_block local v local typ = (require "ngx.process").type for i = 1, 400 do v = typ() end package.loaded.process_type = v } _EOC_ $block->set_value("stream_config", $stream_config); }); master_on(); #no_diff(); # no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: sanity --- stream_server_config content_by_lua_block { ngx.say("process type: ", package.loaded.process_type) } --- stream_response process type: master --- grep_error_log eval qr/\[TRACE\s+\d+ init_by_lua:\d+ loop\]/ --- grep_error_log_out eval [ qr/\A\[TRACE\s+\d+ init_by_lua:\d+ loop\] \z/, qr/\A\[TRACE\s+\d+ init_by_lua:\d+ loop\] \z/ ] --- no_error_log [error] -- NYI: --- skip_nginx: 5: < 1.11.2 lua-resty-core-0.1.31/t/stream/process-type-privileged-agent.t000066400000000000000000000047041474236722600242750ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore::Stream; repeat_each(2); plan tests => repeat_each() * (blocks() * 4 - 1); add_block_preprocessor(sub { my $block = shift; my $stream_config = $block->stream_config || ''; $stream_config .= <<_EOC_; lua_package_path '$t::TestCore::Stream::lua_package_path'; init_by_lua_block { $t::TestCore::Stream::init_by_lua_block $init_by_lua_block local process = require "ngx.process" local ok, err = process.enable_privileged_agent() if not ok then ngx.log(ngx.ERR, "enable_privileged_agent failed: ", err) end } init_worker_by_lua_block { local base = require "resty.core.base" local v local typ = (require "ngx.process").type for i = 1, 400 do v = typ() end if v == "privileged agent" then ngx.log(ngx.WARN, "process type: ", v) end } _EOC_ $block->set_value("stream_config", $stream_config); }); #no_diff(); # no_long_string(); master_process_enabled(1); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: sanity --- stream_server_config content_by_lua_block { ngx.sleep(0.1) local v local typ = require "ngx.process".type for i = 1, 200 do v = typ() end ngx.say("type: ", v) } --- stream_response type: worker --- grep_error_log eval qr/\[TRACE\s+\d+ init_worker_by_lua:\d+ loop\]|\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):\d+ loop\]|init_worker_by_lua:\d+: process type: \w+/ --- grep_error_log_out eval [ qr/\[TRACE\s+\d+ init_worker_by_lua:\d+ loop\] (?:\[TRACE\s+\d+ init_worker_by_lua:\d+ loop\] )?\[TRACE\s+\d+ content_by_lua\(nginx.conf:\d+\):\d+ loop\] init_worker_by_lua:10: process type: privileged /, qr/\[TRACE\s+\d+ init_worker_by_lua:\d+ loop\] (?:\[TRACE\s+\d+ init_worker_by_lua:\d+ loop\] )?\[TRACE\s+\d+ content_by_lua\(nginx.conf:\d+\):\d+ loop\] init_worker_by_lua:10: process type: privileged / ] --- no_error_log [error] -- NYI: --- skip_nginx: 5: < 1.11.2 --- wait: 0.2 === TEST 2: `enable_privileged_agent` disabled --- stream_server_config content_by_lua_block { local process = require "ngx.process" local ok, err = process.enable_privileged_agent() if not ok then error(err) end } --- error_log eval qr/\[error\] .*? API disabled in the current context/ --- skip_nginx: 3: < 1.11.2 lua-resty-core-0.1.31/t/stream/process-type-single.t000066400000000000000000000041441474236722600223260ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore::Stream; repeat_each(2); plan tests => repeat_each() * (blocks() * 5); add_block_preprocessor(sub { my $block = shift; my $stream_config = $block->stream_config || ''; $stream_config .= <<_EOC_; lua_package_path '$t::TestCore::Stream::lua_package_path'; init_by_lua_block { $t::TestCore::Stream::init_by_lua_block $init_by_lua_block local v local typ = (require "ngx.process").type for i = 1, 400 do v = typ() end package.loaded.process_type = v } init_worker_by_lua_block { local v local typ = (require "ngx.process").type for i = 1, 400 do v = typ() end ngx.log(ngx.WARN, "process type in init_by_lua*: ", package.loaded.process_type) ngx.log(ngx.WARN, "process type: ", v) } _EOC_ $block->set_value("stream_config", $stream_config); }); #no_diff(); # no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: sanity --- stream_server_config content_by_lua_block { local v local typ = (require "ngx.process").type for i = 1, 400 do v = typ() end ngx.say("process type: ", v) } --- stream_response process type: single --- grep_error_log eval qr/\[TRACE\s+\d+ init_by_lua:\d+ loop\]|\[TRACE\s+\d+ init_worker_by_lua:\d loop\]|\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):\d loop\]|process type in init_by_lua\*: \w+|init_worker_by_lua:\d+: process type: \w+/ --- grep_error_log_out eval [ qr/\[TRACE\s+\d+ init_by_lua:\d+ loop\] \[TRACE\s+\d+ init_worker_by_lua:\d+ loop\] \[TRACE\s+\d+ content_by_lua\(nginx.conf:\d+\):4 loop\] process type in init_by_lua\*: single init_worker_by_lua:10: process type: single /, qr/\[TRACE\s+\d+ init_by_lua:\d+ loop\] \[TRACE\s+\d+ init_worker_by_lua:\d+ loop\] \[TRACE\s+\d+ content_by_lua\(nginx.conf:\d+\):4 loop\] process type in init_by_lua\*: single init_worker_by_lua:10: process type: single / ] --- no_error_log [error] -- NYI: --- skip_nginx: 5: < 1.11.2 lua-resty-core-0.1.31/t/stream/process-type-worker.t000066400000000000000000000031741474236722600223600ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore::Stream; repeat_each(2); plan tests => repeat_each() * (blocks() * 5); add_block_preprocessor(sub { my $block = shift; my $stream_config = $block->stream_config || ''; $stream_config .= <<_EOC_; lua_package_path '$t::TestCore::Stream::lua_package_path'; init_by_lua_block { $t::TestCore::Stream::init_by_lua_block $init_by_lua_block } init_worker_by_lua_block { local v local typ = (require "ngx.process").type for i = 1, 400 do v = typ() end ngx.log(ngx.WARN, "process type: ", v) } _EOC_ $block->set_value("stream_config", $stream_config); }); master_on(); #no_diff(); # no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: sanity --- stream_server_config content_by_lua_block { local v local typ = (require "ngx.process").type for i = 1, 400 do v = typ() end ngx.say("process type: ", v) } --- stream_response process type: worker --- grep_error_log eval qr/\[TRACE\s+\d+ init_worker_by_lua:\d loop\]|\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):\d loop\]|init_worker_by_lua:\d: process type: \w+/ --- grep_error_log_out eval [ qr/\[TRACE\s+\d+ init_worker_by_lua:4 loop\] \[TRACE\s+\d+ content_by_lua\(nginx.conf:\d+\):4 loop\] init_worker_by_lua:8: process type: worker /, qr/\[TRACE\s+\d+ init_worker_by_lua:4 loop\] \[TRACE\s+\d+ content_by_lua\(nginx.conf:\d+\):4 loop\] init_worker_by_lua:8: process type: worker / ] --- no_error_log [error] -- NYI: --- skip_nginx: 5: < 1.11.2 lua-resty-core-0.1.31/t/stream/re-base.t000066400000000000000000000110511474236722600177230ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore::Stream; repeat_each(2); plan tests => repeat_each() * (blocks() * 3); no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: bad pattern --- stream_server_config content_by_lua_block { local it, err = ngx.re.gmatch("hello\\nworld", "(abc") if not err then ngx.say("good") else ngx.say("error: ", err) end } --- stream_response eval $Test::Nginx::Util::PcreVersion == 2 ? "error: pcre2_compile() failed: missing closing parenthesis in \"(abc\"\n" : "error: pcre_compile() failed: missing ) in \"(abc\"\n" --- no_error_log [error] === TEST 2: bad UTF-8 --- stream_server_config content_by_lua_block { local target = "你好" local regex = "你好" -- Note the D here local it, err = ngx.re.gmatch(string.sub(target, 1, 4), regex, "u") if err then ngx.say("error: ", err) return end local m, err = it() if err then ngx.say("error: ", err) return end if m then ngx.say("matched: ", m[0]) else ngx.say("not matched") end } --- stream_response eval $Test::Nginx::Util::PcreVersion == 2 ? "error: pcre_exec\(\) failed: -4\n" : "error: pcre_exec\(\) failed: -10\n" --- no_error_log [error] === TEST 3: UTF-8 mode without UTF-8 sequence checks --- stream_server_config content_by_lua_block { local it = ngx.re.gmatch("你好", ".", "U") local m = it() if m then ngx.say(m[0]) else ngx.say("not matched!") end } --- stap probe process("$LIBPCRE_PATH").function("pcre_compile") { printf("compile opts: %x\n", $options) } probe process("$LIBPCRE_PATH").function("pcre_exec") { printf("exec opts: %x\n", $options) } --- stap_out compile opts: 800 exec opts: 2000 --- stream_response 你 --- no_error_log [error] === TEST 4: UTF-8 mode with UTF-8 sequence checks --- stream_server_config content_by_lua_block { local it = ngx.re.gmatch("你好", ".", "u") local m = it() if m then ngx.say(m[0]) else ngx.say("not matched!") end } --- stap probe process("$LIBPCRE_PATH").function("pcre_compile") { printf("compile opts: %x\n", $options) } probe process("$LIBPCRE_PATH").function("pcre_exec") { printf("exec opts: %x\n", $options) } # TODO: PCRE2 use different option values from PCRE --- stap_out compile opts: 800 exec opts: 0 --- stream_response 你 --- no_error_log [error] === TEST 5: just hit match limit --- stream_config eval: "lua_regex_match_limit 5000;" . $t::TestCore::Stream::StreamConfig --- stream_server_config content_by_lua_file html/a.lua; --- user_files >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] local s = string.rep([[ABCDEFG]], 10) local it, err = ngx.re.gmatch(s, re, "o") if not it then ngx.say("failed to gen iterator: ", err) return end local res, err = it() if not res then if err then ngx.say("error: ", err) return end ngx.say("failed to match") return end --- stream_response eval # lua_regex_match_limit uses pcre_extra->match_limit in the PCRE, # but PCRE2 replaces this with pcre2_set_match_limit interface, # which has different effects. $Test::Nginx::Util::PcreVersion == 2 ? "failed to match\n" : "error: pcre_exec() failed: -8\n" === TEST 6: just not hit match limit --- stream_config eval: "lua_regex_match_limit 5100;" . $t::TestCore::Stream::StreamConfig --- stream_server_config content_by_lua_file html/a.lua; --- user_files >>> a.lua local re = [==[(?i:([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:=|<=>|r?like|sounds\s+like|regexp)([\s'\"`´’‘\(\)]*)?\2|([\s'\"`´’‘\(\)]*)?([\d\w]+)([\s'\"`´’‘\(\)]*)?(?:!=|<=|>=|<>|<|>|\^|is\s+not|not\s+like|not\s+regexp)([\s'\"`´’‘\(\)]*)?(?!\6)([\d\w]+))]==] local s = string.rep([[ABCDEFG]], 10) local it, err = ngx.re.gmatch(s, re, "o") if not it then ngx.say("failed to gen iterator: ", err) return end local res, err = it() if not res then if err then ngx.say("error: ", err) return end ngx.say("failed to match") return end --- stream_response failed to match lua-resty-core-0.1.31/t/stream/re-find.t000066400000000000000000000112501474236722600177320ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore::Stream; #worker_connections(1014); #master_process_enabled(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 5); #no_diff(); no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: matched, no submatch, no jit compile, no regex cache --- stream_server_config content_by_lua_block { local from, to, err local find = ngx.re.find local s = "a" for i = 1, $TEST_NGINX_HOTLOOP * 20 do from, to, err = find(s, "a") end if err then ngx.log(ngx.ERR, "failed: ", err) return end if not from then ngx.log(ngx.ERR, "no match") return end ngx.say("from: ", from) ngx.say("to: ", to) ngx.say("matched: ", string.sub(s, from, to)) } --- stream_response from: 1 to: 1 matched: a --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):5 loop\]/ --- no_error_log [error] bad argument type === TEST 2: matched, no submatch, jit compile, regex cache --- stream_server_config content_by_lua_block { local from, to, err local find = ngx.re.find local s = "a" for i = 1, 200 do from, to, err = find(s, "a", "jo") end if err then ngx.log(ngx.ERR, "failed: ", err) return end if not from then ngx.log(ngx.ERR, "no match") return end ngx.say("from: ", from) ngx.say("to: ", to) ngx.say("matched: ", string.sub(s, from, to)) } --- stream_response from: 1 to: 1 matched: a --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):5 loop\]/ --- no_error_log [error] NYI === TEST 3: not matched, no submatch, jit compile, regex cache --- stream_server_config content_by_lua_block { local from, to, err local find = ngx.re.find local s = "b" for i = 1, 200 do from, to, err = find(s, "a", "jo") end if err then ngx.log(ngx.ERR, "failed: ", err) return end if not from then ngx.say("no match") return end ngx.say("from: ", from) ngx.say("to: ", to) ngx.say("matched: ", string.sub(s, from, to)) } --- stream_response no match --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):5 loop\]/ --- no_error_log [error] NYI === TEST 4: nil submatch (2nd) --- stream_server_config content_by_lua_block { local s = "hello, 1234" local from, to, err for i = 1, $TEST_NGINX_HOTLOOP * 20 do from, to, err = ngx.re.find(s, "([0-9])|(hello world)", "jo", nil, 2) end if from or to then ngx.say("from: ", from) ngx.say("to: ", to) ngx.say("matched: ", string.sub(s, from, to)) else if err then ngx.say("error: ", err) return end ngx.say("not matched!") end } --- stream_response not matched! --- no_error_log [error] NYI --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ === TEST 5: nil submatch (1st) --- stream_server_config content_by_lua_block { local s = "hello, 1234" local from, to, err for i = 1, 400 do from, to, err = ngx.re.find(s, "(hello world)|([0-9])", "jo", nil, 1) end if from or to then ngx.say("from: ", from) ngx.say("to: ", to) ngx.say("matched: ", string.sub(s, from, to)) else if err then ngx.say("error: ", err) return end ngx.say("not matched!") end } --- stream_response not matched! --- no_error_log [error] NYI --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ === TEST 6: specify the group (2) --- stream_server_config content_by_lua_block { local s = "hello, 1234" local from, to, err for i = 1, $TEST_NGINX_HOTLOOP * 20 do from, to, err = ngx.re.find(s, "([0-9])([0-9]+)", "jo", nil, 2) end if from then ngx.say("from: ", from) ngx.say("to: ", to) ngx.say("matched: ", string.sub(s, from, to)) else if err then ngx.say("error: ", err) end ngx.say("not matched!") end } --- stream_response from: 9 to: 11 matched: 234 --- no_error_log [error] NYI --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ lua-resty-core-0.1.31/t/stream/re-gmatch.t000066400000000000000000000230551474236722600202630ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore::Stream; #worker_connections(1014); #master_process_enabled(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 3 + 9); #no_diff(); no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: matched, no submatch, no jit compile, no regex cache --- stream_server_config content_by_lua_block { local m1, m2 local gmatch = ngx.re.gmatch for _ = 1, 200 do local iter = gmatch("hello, world", [[\w+]]) m1 = iter() m2 = iter() end ngx.say("matched: ", m1[0]) ngx.say("matched: ", m2[0]) } --- stream_response matched: hello matched: world --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] === TEST 2: matched, no submatch, jit compile, regex cache --- stream_server_config content_by_lua_block { local m1, m2 local gmatch = ngx.re.gmatch for _ = 1, 200 do local iter = gmatch("hello, world", [[\w+]], "jo") m1 = iter() m2 = iter() end ngx.say("matched: ", m1[0]) ngx.say("matched: ", m2[0]) } --- stream_response matched: hello matched: world --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] === TEST 3: not matched, no submatch, jit compile, regex cache --- stream_server_config content_by_lua_block { local m, err local gmatch = ngx.re.gmatch for _ = 1, 200 do local iter = gmatch("hello, world", "[abc]+", "jo") m, err = iter() if err then ngx.log(ngx.ERR, "failed: ", err) return end end if not m then ngx.say("no match") return end } --- stream_response no match --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] === TEST 4: not matched, no submatch, no jit compile, no regex cache --- stream_server_config content_by_lua_block { local m, err local gmatch = ngx.re.gmatch for _ = 1, 200 do local iter = gmatch("hello, world", "[abc]+") m, err = iter() if err then ngx.log(ngx.ERR, "failed: ", err) return end end if not m then ngx.say("no match") return end } --- stream_response no match --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] === TEST 5: submatches, matched, no regex cache --- stream_server_config content_by_lua_block { local m1, m2 local gmatch = ngx.re.gmatch for _ = 1, 200 do local iter = gmatch("hello, world", [[(\w)(\w+)]]) m1 = iter() m2 = iter() end ngx.say("matched: ", m1[0]) ngx.say("$1: ", m1[1]) ngx.say("$2: ", m1[2]) ngx.say("$3: ", m1[3]) ngx.say("matched: ", m2[0]) ngx.say("$1: ", m2[1]) ngx.say("$2: ", m2[2]) ngx.say("$3: ", m2[3]) } --- stream_response matched: hello $1: h $2: ello $3: nil matched: world $1: w $2: orld $3: nil --- no_error_log [error] === TEST 6: submatches, matched, with regex cache --- stream_server_config content_by_lua_block { local m1, m2 local gmatch = ngx.re.gmatch for _ = 1, 200 do local iter = gmatch("hello, world", [[(\w)(\w+)]], "jo") m1 = iter() m2 = iter() end ngx.say("matched: ", m1[0]) ngx.say("$1: ", m1[1]) ngx.say("$2: ", m1[2]) ngx.say("$3: ", m1[3]) ngx.say("matched: ", m2[0]) ngx.say("$1: ", m2[1]) ngx.say("$2: ", m2[2]) ngx.say("$3: ", m2[3]) } --- stream_response matched: hello $1: h $2: ello $3: nil matched: world $1: w $2: orld $3: nil --- error_log eval qr/\[TRACE\s+\d+\s+/ --- no_error_log [error] === TEST 7: named submatches --- stream_server_config content_by_lua_block { local m1, m2 local gmatch = ngx.re.gmatch for _ = 1, 200 do local iter = gmatch("hello,world", [[(?\w)(\w+)]], "jo") m1 = iter() m2 = iter() end ngx.say("matched: ", m1[0]) ngx.say("$1: ", m1[1]) ngx.say("$2: ", m1[2]) ngx.say("$first: ", m1.first) ngx.say("$second: ", m1.second) ngx.say("matched: ", m2[0]) ngx.say("$1: ", m2[1]) ngx.say("$2: ", m2[2]) ngx.say("$first: ", m2.first) ngx.say("$second: ", m2.second) } --- stream_response matched: hello $1: h $2: ello $first: h $second: nil matched: world $1: w $2: orld $first: w $second: nil --- error_log eval qr/\[TRACE\s+\d+\s+/ --- no_error_log [error] === TEST 8: unmatched captures are false --- stream_server_config content_by_lua_block { local iter = ngx.re.gmatch( "hello! world!", [[(\w+)(, .+)?(!)]], "jo") if iter then while true do local m = iter() if not m then return end ngx.say(m[0]) ngx.say(m[1]) ngx.say(m[2]) ngx.say(m[3]) end end } --- stream_response hello! hello false ! world! world false ! --- error_log eval qr/\[TRACE\s+\d+\s+/ --- no_error_log [error] === TEST 9: unmatched trailing captures are false --- stream_server_config content_by_lua_block { local iter = ngx.re.gmatch("hello", [[(\w+)(, .+)?(!)?]], "jo") if iter then while true do local m = iter() if not m then return end ngx.say(m[0]) ngx.say(m[1]) ngx.say(m[2]) ngx.say(m[3]) end end } --- stream_response hello hello false false --- error_log eval qr/\[TRACE\s+\d+\s+/ --- no_error_log [error] === TEST 10: unmatched named captures are false --- stream_server_config content_by_lua_block { local iter = ngx.re.gmatch( "hello! world!", [[(?\w+)(?, .+)?(?!)]], "jo") if iter then while true do local m = iter() if not m then return end ngx.say(m[0]) ngx.say(m[1]) ngx.say(m[2]) ngx.say(m[3]) ngx.say(m.first) ngx.say(m.second) ngx.say(m.third) end end } --- stream_response hello! hello false ! hello false ! world! world false ! world false ! --- error_log eval qr/\[TRACE\s+\d+\s+/ --- no_error_log [error] === TEST 11: subject is not a string type --- stream_server_config content_by_lua_block { local iter = ngx.re.gmatch(120345, "[1-9]+", "jo") local m1 = iter() local m2 = iter() ngx.say(m1[0]) ngx.say(m2[0]) } --- stream_response 12 345 --- no_error_log [error] attempt to get length of local 'subj' (a number value) === TEST 12: an exhausted gmatch iterator should return nil --- stream_server_config content_by_lua_block { local iter = ngx.re.gmatch("hello", [[\w+]]) local m = iter() ngx.say("matched: ", m[0]) ngx.say("matched: ", iter()) ngx.say("matched: ", iter()) } --- stream_response matched: hello matched: nil matched: nil --- no_error_log [error] === TEST 13: an error-ed out gmatch iterator should return nil --- stream_server_config content_by_lua_block { local target = "你好" local regex = "你好" -- trigger a BADUTF8 error local iter = ngx.re.gmatch(string.sub(target, 1, 4), regex, "u") local m, err = iter() if err then ngx.say("error: ", err) local m = iter() if m then ngx.say("matched: ", m[0]) else ngx.say("not matched") end return end if m then ngx.say("matched: ", m[0]) else ngx.say("not matched") end } --- stream_response eval # PCRE2_ERROR_UTF8_ERR2 (-4) # PCRE_ERROR_BADUTF8 (-10) $Test::Nginx::Util::PcreVersion == 2 ? "error: pcre_exec\(\) failed: -4\nnot matched\n" : "error: pcre_exec\(\) failed: -10\nnot matched\n" --- no_error_log [error] === TEST 14: each gmatch iterator is separate --- stream_server_config content_by_lua_block { local gmatch = ngx.re.gmatch local iter1 = gmatch("98", [[\d]]) local iter2 = gmatch("12", [[\d]]) local m1 = iter1() local m2 = iter2() ngx.say("matched iter1 (1/2): ", m1[0]) ngx.say("matched iter2 (1/2): ", m2[0]) m1 = iter1() m2 = iter2() ngx.say("matched iter1 (2/2): ", m1[0]) ngx.say("matched iter2 (2/2): ", m2[0]) } --- stream_response matched iter1 (1/2): 9 matched iter2 (1/2): 1 matched iter1 (2/2): 8 matched iter2 (2/2): 2 --- no_error_log [error] === TEST 15: gmatch (empty matched string) --- stream_server_config content_by_lua_block { for m in ngx.re.gmatch("hello", "a|") do if m then ngx.say("matched: [", m[0], "]") else ngx.say("not matched: ", m) end end } --- stream_response matched: [] matched: [] matched: [] matched: [] matched: [] matched: [] lua-resty-core-0.1.31/t/stream/re-match.t000066400000000000000000000246611474236722600201200ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore::Stream; #worker_connections(1014); #master_process_enabled(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 5 + 1); #no_diff(); no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: matched, no submatch, no jit compile, no regex cache --- stream_server_config content_by_lua_block { local m, err local match = ngx.re.match for i = 1, 400 do m, err = match("a", "a") end if err then ngx.log(ngx.ERR, "failed: ", err) return end if not m then ngx.log(ngx.ERR, "no match") return end ngx.say("matched: ", m[0]) ngx.say("$1: ", m[1]) -- ngx.say("$2: ", m[2]) -- ngx.say("$3: ", m[3]) -- collectgarbage() } --- stream_response matched: a $1: nil --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] bad argument type === TEST 2: matched, no submatch, jit compile, regex cache --- stream_server_config content_by_lua_block { local m, err local match = ngx.re.match for i = 1, 400 do m, err = match("a", "a", "jo") end if err then ngx.log(ngx.ERR, "failed: ", err) return end if not m then ngx.log(ngx.ERR, "no match") return end ngx.say("matched: ", m[0]) ngx.say("$1: ", m[1]) -- collectgarbage() } --- stream_response matched: a $1: nil --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] NYI === TEST 3: not matched, no submatch, jit compile, regex cache --- stream_server_config content_by_lua_block { local m, err local match = ngx.re.match for i = 1, 200 do m, err = match("b", "a", "jo") end if err then ngx.log(ngx.ERR, "failed: ", err) return end if not m then ngx.say("no match") return end ngx.say("matched: ", m[0]) ngx.say("$1: ", m[1]) -- collectgarbage() } --- stream_response no match --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] === TEST 4: not matched, no submatch, no jit compile, no regex cache --- stream_server_config content_by_lua_block { local m, err local match = ngx.re.match for i = 1, 100 do m, err = match("b", "a") end if err then ngx.log(ngx.ERR, "failed: ", err) return end if not m then ngx.say("no match") return end ngx.say("matched: ", m[0]) ngx.say("$1: ", m[1]) -- collectgarbage() } --- stream_response no match --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] bad argument type === TEST 5: submatches, matched, no regex cache --- stream_server_config content_by_lua_block { local m, err local match = ngx.re.match for i = 1, 100 do m, err = match("hello, 1234", [[(\d)(\d+)]]) end if err then ngx.log(ngx.ERR, "failed: ", err) return end if not m then ngx.log(ngx.ERR, "no match") return end ngx.say("matched: ", m[0]) ngx.say("$1: ", m[1]) ngx.say("$2: ", m[2]) ngx.say("$3: ", m[3]) -- collectgarbage() } --- stream_response matched: 1234 $1: 1 $2: 234 $3: nil --- no_error_log [error] bad argument type NYI === TEST 6: submatches, matched, with regex cache --- stream_server_config content_by_lua_block { local m, err local match = ngx.re.match for i = 1, 100 do m, err = match("hello, 1234", [[(\d)(\d+)]], "jo") end if err then ngx.log(ngx.ERR, "failed: ", err) return end if not m then ngx.log(ngx.ERR, "no match") return end ngx.say("matched: ", m[0]) ngx.say("$1: ", m[1]) ngx.say("$2: ", m[2]) ngx.say("$3: ", m[3]) -- ngx.say(table.maxn(m)) -- collectgarbage() } --- stream_response matched: 1234 $1: 1 $2: 234 $3: nil --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] bad argument type NYI === TEST 7: named subpatterns w/ extraction (matched) --- stream_server_config content_by_lua_block { local m, err local match = ngx.re.match for i = 1, 100 do m, err = match("hello, 1234", "(?[a-z]+), [0-9]+", "jo") end if m then ngx.say(m[0]) ngx.say(m[1]) ngx.say(m.first) ngx.say(m.second) else if err then ngx.say("error: ", err) return end ngx.say("not matched!") end } --- stream_response hello, 1234 hello hello nil --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] bad argument type NYI === TEST 8: named subpatterns w/ extraction (use of duplicate names in non-duplicate mode) --- stream_server_config content_by_lua_block { local m, err local match = ngx.re.match for i = 1, 200 do m, err = match("hello, 1234", "(?[a-z])(?[a-z]+), [0-9]+", "jo") end if m then ngx.say(m[0]) ngx.say(m[1]) ngx.say(m.first) ngx.say(m.second) else if err then ngx.say("error: ", err) return end ngx.say("not matched!") end } --- stream_response eval $Test::Nginx::Util::PcreVersion == 2 ? "error: pcre2_compile\(\) failed: two named subpatterns have the same name \(PCRE2_DUPNAMES not set\) in \"\(\?[a-z])\(\?[a-z]+\), [0-9]+\" at \"[a-z]+\), [0-9]+\"\n" : "error: pcre_compile\(\) failed: two named subpatterns have the same name in \"\(\?[a-z])\(\?[a-z]+\), [0-9]+\" at \">[a-z]+\), [0-9]+\"\n" --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] bad argument type NYI === TEST 9: named subpatterns w/ extraction (use of duplicate names in duplicate mode) --- stream_server_config content_by_lua_block { local m, err local match = ngx.re.match for i = 1, 100 do m, err = match("hello, 1234", "(?[a-z])(?[a-z]+), [0-9]+", "joD") m, err = match("hello, 1234", "(?[a-z])(?[a-z]+), [0-9]+", "joD") m, err = match("hello, 1234", "(?[a-z])(?[a-z]+), [0-9]+", "joD") m, err = match("hello, 1234", "(?[a-z])(?[a-z]+), [0-9]+", "joD") m, err = match("hello, 1234", "(?[a-z])(?[a-z]+), [0-9]+", "joD") end if m then ngx.say(m[0]) ngx.say(m[1]) ngx.say(m[2]) ngx.say(table.concat(m.first, "|")) ngx.say(m.second) else if err then ngx.say("error: ", err) return end ngx.say("not matched!") end } --- stream_response_like hello, 1234 h ello h|ello nil --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] bad argument type NYI === TEST 10: captures input table in ngx.re.match --- stream_server_config content_by_lua_block { local new_tab = require "table.new" local clear_tab = require "table.clear" local m local res = new_tab(5, 0) res[5] = "hello" for i = 1, 100 do m = ngx.re.match("hello, 1234", "([0-9])([0-9])([0-9])([0-9])", "jo", nil, res) end if m then ngx.say(m[0]) ngx.say(m[1]) ngx.say(m[2]) ngx.say(m[3]) ngx.say(m[4]) ngx.say(m[5]) else ngx.say("not matched!") end } --- stream_response 1234 1 2 3 4 hello --- no_error_log [error] NYI --- error_log eval qr/\[TRACE\s+\d+\s+/ === TEST 11: unmatched captures are false --- stream_server_config content_by_lua_block { local m = ngx.re.match("hello!", "(hello)(, .+)?(!)", "jo") if m then ngx.say(m[0]) ngx.say(m[1]) ngx.say(m[2]) ngx.say(m[3]) else ngx.say("not matched!") end } --- stream_response hello! hello false ! --- no_error_log [error] NYI --- error_log eval qr/\[TRACE\s+\d+\s+/ === TEST 12: unmatched trailing captures are false --- stream_server_config content_by_lua_block { local m = ngx.re.match("hello", "(hello)(, .+)?(!)?", "jo") if m then ngx.say(m[0]) ngx.say(m[1]) ngx.say(m[2]) ngx.say(m[3]) else ngx.say("not matched!") end } --- stream_response hello hello false false --- no_error_log [error] NYI --- error_log eval qr/\[TRACE\s+\d+\s+/ === TEST 13: unmatched named captures are false --- stream_server_config content_by_lua_block { local m = ngx.re.match("hello!", "(?hello)(?, .+)?(?!)", "jo") if m then ngx.say(m[0]) ngx.say(m[1]) ngx.say(m[2]) ngx.say(m[3]) ngx.say(m.first) ngx.say(m.second) ngx.say(m.third) else ngx.say("not matched!") end } --- stream_response hello! hello false ! hello false ! --- no_error_log [error] NYI --- error_log eval qr/\[TRACE\s+\d+\s+/ === TEST 14: subject is not a string type --- stream_server_config content_by_lua_block { local m = ngx.re.match(12345, [=[(\d+)]=], "jo") if m then ngx.say(m[0]) ngx.say(m[1]) else ngx.say("not matched") end } --- stream_response 12345 12345 --- no_error_log [error] attempt to get length of local 'subj' (a number value) === TEST 15: subject is not a string type --- stream_server_config content_by_lua_block { local m = ngx.re.match(12345, "123", "jo") if m then ngx.say(m[0]) else ngx.say("not matched") end } --- stream_response 123 --- no_error_log [error] attempt to get length of local 'regex' (a number value) lua-resty-core-0.1.31/t/stream/re-opt.t000066400000000000000000000147431474236722600176260ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore::Stream; #worker_connections(1014); #master_process_enabled(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * blocks() * 3; no_diff(); no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: default jit_stack_size too small --- stream_server_config content_by_lua_block { -- regex is taken from https://github.com/JuliaLang/julia/issues/8278 local very_long_string = [[71.163.72.113 - - [30/Jul/2014:16:40:55 -0700] "GET emptymind.org/thevacantwall/wp-content/uploads/2013/02/DSC_006421.jpg HTTP/1.1" 200 492513 "http://images.search.yahoo.com/images/view;_ylt=AwrB8py9gdlTGEwADcSjzbkF;_ylu=X3oDMTI2cGZrZTA5BHNlYwNmcC1leHAEc2xrA2V4cARvaWQDNTA3NTRiMzYzY2E5OTEwNjBiMjc2YWJhMjkxMTEzY2MEZ3BvcwM0BGl0A2Jpbmc-?back=http%3A%2F%2Fus.yhs4.search.yahoo.com%2Fyhs%2Fsearch%3Fei%3DUTF-8%26p%3Dapartheid%2Bwall%2Bin%2Bpalestine%26type%3Dgrvydef%26param1%3D1%26param2%3Dsid%253Db01676f9c26355f014f8a9db87545d61%2526b%253DChrome%2526ip%253D71.163.72.113%2526p%253Dgroovorio%2526x%253DAC811262A746D3CD%2526dt%253DS940%2526f%253D7%2526a%253Dgrv_tuto1_14_30%26hsimp%3Dyhs-fullyhosted_003%26hspart%3Dironsource&w=588&h=387&imgurl=occupiedpalestine.files.wordpress.com%2F2012%2F08%2F5-peeking-through-the-wall.jpg%3Fw%3D588%26h%3D387&rurl=http%3A%2F%2Fwww.stopdebezetting.com%2Fwereldpers%2Fcompare-the-berlin-wall-vs-israel-s-apartheid-wall-in-palestine.html&size=49.0KB&name=...+%3Cb%3EApartheid+wall+in+Palestine%3C%2Fb%3E...+%7C+Or+you+go+peeking+through+the+%3Cb%3Ewall%3C%2Fb%3E&p=apartheid+wall+in+palestine&oid=50754b363ca991060b276aba291113cc&fr2=&fr=&tt=...+%3Cb%3EApartheid+wall+in+Palestine%3C%2Fb%3E...+%7C+Or+you+go+peeking+through+the+%3Cb%3Ewall%3C%2Fb%3E&b=0&ni=21&no=4&ts=&tab=organic&sigr=13evdtqdq&sigb=19k7nsjvb&sigi=12o2la1db&sigt=12lia2m0j&sign=12lia2m0j&.crumb=.yUtKgFI6DE&hsimp=yhs-fullyhosted_003&hspart=ironsource" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36]] local very_complicated_regex = [[([\d\.]+) ([\w.-]+) ([\w.-]+) (\[.+\]) "([^"\r\n]*|[^"\r\n\[]*\[.+\][^"]+|[^"\r\n]+.[^"]+)" (\d{3}) (\d+|-) ("(?:[^"]|\")+)"? ("(?:[^"]|\")+)"?]] local from, to, err = ngx.re.find(very_long_string, very_complicated_regex, "jo") if from or to then ngx.say("from: ", from) ngx.say("to: ", to) else if err then ngx.say("error: ", err) return end ngx.say("not matched!") end } --- stream_response eval # PCRE2_ERROR_JIT_STACKLIMIT (-46) # PCRE_ERROR_JIT_STACKLIMIT (-27) $Test::Nginx::Util::PcreVersion == 2 ? "error: pcre_exec\(\) failed: -46\n" : "error: pcre_exec\(\) failed: -27\n" --- no_error_log [error] --- timeout: 10 === TEST 2: increase jit_stack_size --- stream_config eval qq{ lua_package_path "$t::TestCore::Stream::lua_package_path"; init_by_lua_block { $t::TestCore::Stream::init_by_lua_block local ngx_re = require "ngx.re" ngx_re.opt("jit_stack_size", 128 * 1024) } } --- stream_server_config content_by_lua_block { -- regex is taken from https://github.com/JuliaLang/julia/issues/8278 local very_long_string = [[71.163.72.113 - - [30/Jul/2014:16:40:55 -0700] "GET emptymind.org/thevacantwall/wp-content/uploads/2013/02/DSC_006421.jpg HTTP/1.1" 200 492513 "http://images.search.yahoo.com/images/view;_ylt=AwrB8py9gdlTGEwADcSjzbkF;_ylu=X3oDMTI2cGZrZTA5BHNlYwNmcC1leHAEc2xrA2V4cARvaWQDNTA3NTRiMzYzY2E5OTEwNjBiMjc2YWJhMjkxMTEzY2MEZ3BvcwM0BGl0A2Jpbmc-?back=http%3A%2F%2Fus.yhs4.search.yahoo.com%2Fyhs%2Fsearch%3Fei%3DUTF-8%26p%3Dapartheid%2Bwall%2Bin%2Bpalestine%26type%3Dgrvydef%26param1%3D1%26param2%3Dsid%253Db01676f9c26355f014f8a9db87545d61%2526b%253DChrome%2526ip%253D71.163.72.113%2526p%253Dgroovorio%2526x%253DAC811262A746D3CD%2526dt%253DS940%2526f%253D7%2526a%253Dgrv_tuto1_14_30%26hsimp%3Dyhs-fullyhosted_003%26hspart%3Dironsource&w=588&h=387&imgurl=occupiedpalestine.files.wordpress.com%2F2012%2F08%2F5-peeking-through-the-wall.jpg%3Fw%3D588%26h%3D387&rurl=http%3A%2F%2Fwww.stopdebezetting.com%2Fwereldpers%2Fcompare-the-berlin-wall-vs-israel-s-apartheid-wall-in-palestine.html&size=49.0KB&name=...+%3Cb%3EApartheid+wall+in+Palestine%3C%2Fb%3E...+%7C+Or+you+go+peeking+through+the+%3Cb%3Ewall%3C%2Fb%3E&p=apartheid+wall+in+palestine&oid=50754b363ca991060b276aba291113cc&fr2=&fr=&tt=...+%3Cb%3EApartheid+wall+in+Palestine%3C%2Fb%3E...+%7C+Or+you+go+peeking+through+the+%3Cb%3Ewall%3C%2Fb%3E&b=0&ni=21&no=4&ts=&tab=organic&sigr=13evdtqdq&sigb=19k7nsjvb&sigi=12o2la1db&sigt=12lia2m0j&sign=12lia2m0j&.crumb=.yUtKgFI6DE&hsimp=yhs-fullyhosted_003&hspart=ironsource" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36]] local very_complicated_regex = [[([\d\.]+) ([\w.-]+) ([\w.-]+) (\[.+\]) "([^"\r\n]*|[^"\r\n\[]*\[.+\][^"]+|[^"\r\n]+.[^"]+)" (\d{3}) (\d+|-) ("(?:[^"]|\")+)"? ("(?:[^"]|\")+)"?]] local from, to, err = ngx.re.find(very_long_string, very_complicated_regex, "jo") if from or to then ngx.say("from: ", from) ngx.say("to: ", to) else if err then ngx.say("error: ", err) return end ngx.say("not matched!") end } --- stream_response from: 1 to: 1563 --- no_error_log [error] --- timeout: 10 === TEST 3: jit_stack_size change disallowed once regex cache is populated --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local status, err = pcall(ngx_re.opt, "jit_stack_size", 128 * 1024) if err then ngx.log(ngx.ERR, err) end local s = "hello, 1234" local from, to = ngx.re.find(s, "(hello world)|([0-9])", "jo") ngx.say("from: ", from) ngx.say("to: ", to) } --- stream_response from: 8 to: 8 --- grep_error_log eval qr/changing jit stack size is not allowed when some regexs have already been compiled and cached/ --- grep_error_log_out eval ["", "changing jit stack size is not allowed when some regexs have already been compiled and cached\n"] --- timeout: 10 === TEST 4: passing unknown options to ngx_re.opt throws an error --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local status, err = pcall(ngx_re.opt, "foo", 123) ngx.say(err) } --- stream_response_like chomp unrecognized option name$ --- no_error_log [error] --- timeout: 10 lua-resty-core-0.1.31/t/stream/re-split.t000066400000000000000000000500401474236722600201450ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore::Stream; #worker_connections(1014); #master_process_enabled(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * blocks() * 4 + (2 * repeat_each()); no_diff(); no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: split matches, no submatch, no jit compile, no regex cache --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("a,b,c,d", ",") if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end } --- stream_response a b c d --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 2: split matches, no submatch, no jit compile, no regex cache --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("a;,b;,c;,d;e", ";,") if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end } --- stream_response a b c d;e --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 3: split matches, no submatch, jit compile, regex cache --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("a,b,c,d", ",", "jo") if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end } --- stream_response a b c d --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 4: split matches + submatch (matching) --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("a;,b;,c;,d,e", "(;),") if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end } --- stream_response a ; b ; c ; d,e --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 5: split matches + submatch (not matching) --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("a,b,c,d,e", "(;)|,") if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end } --- stream_response a b c d e --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 6: split matches + max limiter --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("a,b,c,d,e", ",", nil, nil, 3) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end } --- stream_response a b c,d,e --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 7: split matches + submatch + max limiter --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("a,b,c,d,e", "(,)", nil, nil, 3) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end } --- stream_response a , b , c,d,e --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 8: split matches + max limiter set to 0 --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("a,b,c,d,e", ",", nil, nil, 0) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end } --- stream_response a b c d e --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 9: split matches + max limiter set to a negative value --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("a,b,c,d,e", ",", nil, nil, -1) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end } --- stream_response a b c d e --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 10: split matches + max limiter set to 1 --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("a,b,c,d,e", ",", nil, nil, 1) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end } --- stream_response a,b,c,d,e --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 11: split matches, provided res table --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local my_table = {} local res, err = ngx_re.split("a,b,c,d,e", ",", nil, nil, nil, my_table) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end } --- stream_response a b c d e --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 12: split matches, provided res table (non-cleared) --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local my_table = {} for i = 1, 10 do my_table[i] = i.." hello world" end local res, err = ngx_re.split("a,b,c,d,e", ",", nil, nil, nil, my_table) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i in ipairs(my_table) do ngx.say(res[i]) end } --- stream_response a b c d e --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 13: split matches, provided res table + max limiter --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local my_table = {"hello, world"} local res, err = ngx_re.split("a,b,c,d,e", ",", nil, nil, 3, my_table) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #my_table do ngx.say(res[i]) end } --- stream_response a b c,d,e --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 14: split matches, provided res table (non-cleared) + max limiter --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local my_table = {} for i = 1, 10 do my_table[i] = i.." hello world" end local res, err = ngx_re.split("a,b,c,d,e", ",", nil, nil, 3, my_table) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i in ipairs(my_table) do ngx.say(res[i]) end } --- stream_response a b c,d,e --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 15: split matches, provided res table + max limiter + sub-match capturing group --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local my_table = {"hello, world"} local res, err = ngx_re.split("a,b,c,d,e", "(,)", nil, nil, 3, my_table) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #my_table do ngx.say(res[i]) end } --- stream_response a , b , c,d,e --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 16: split matches, ctx arg --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("a,b,c,d,e", ",", nil, { pos = 5 }) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end } --- stream_response c d e --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 17: split matches, trailing subjects --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split(",a,b,c,d,", ",") if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do if res[i] == "" then ngx.say("_blank_") else ngx.say(res[i]) end end } --- stream_response _blank_ a b c d --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] attempt to get length of local 'regex' (a number value) === TEST 18: split matches, real use-case --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("abcd,erfg,ghij;hello world;aaa", ",|;") if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end } --- stream_response abcd erfg ghij hello world aaa --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 19: split no matches --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("abcd", ",") if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end } --- stream_response abcd --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 20: subject is not a string type --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split(1234512345, "23", "jo") if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end } --- stream_response 1 451 45 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] attempt to get length of local 'subj' (a number value) === TEST 21: split matches, pos is larger than subject length --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("a,b,c,d,e", ",", nil, { pos = 10 }) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end ngx.say("len: ", #res) } --- stream_response len: 0 --- no_error_log [error] [TRACE === TEST 22: regex is "" --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("12345", "", "jo") if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end ngx.say("len: ", #res) } --- stream_response 1 2 3 4 5 len: 5 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 23: regex is "" with max --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("12345", "", "jo", nil, 3) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end ngx.say("len: ", #res) } --- stream_response 1 2 345 len: 3 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 24: regex is "" with pos --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("12345", "", "jo", { pos = 2 }) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end ngx.say("len: ", #res) } --- stream_response 2 3 4 5 len: 4 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 25: regex is "" with pos larger than subject length --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("12345", "", "jo", { pos = 10 }) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end ngx.say("len: ", #res) } --- stream_response len: 0 --- no_error_log [error] [TRACE === TEST 26: regex is "" with pos & max --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("12345", "", "jo", { pos = 2 }, 2) if err then ngx.log(ngx.ERR, "failed: ", err) return end for i = 1, #res do ngx.say(res[i]) end ngx.say("len: ", #res) } --- stream_response 2 345 len: 2 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 27: no match separator (github issue #104) --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("abcd", "|") if err then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say(table.concat(res, ":")) ngx.say("len: ", #res) } --- stream_response a:b:c:d len: 4 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 28: no match separator (github issue #104) & max --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("abcd", "|", nil, nil, 2) if err then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say(table.concat(res, ":")) ngx.say("len: ", #res) } --- stream_response a:bcd len: 2 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 29: no match separator bis (github issue #104) --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("abcd", "()") if err then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say(table.concat(res, ":")) ngx.say("len: ", #res) } --- stream_response a::b::c::d len: 7 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 30: behavior with /^/ differs from Perl's split --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("ab\ncd\nef", "^") if err then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say(table.concat(res, ":")) ngx.say("len: ", #res) } --- stream_response ab cd ef len: 1 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 31: behavior with /^/m --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("ab\ncd\nef", "^", "m") if err then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say(table.concat(res, ":")) ngx.say("len: ", #res) } --- stream_response ab :cd :ef len: 3 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 32: behavior with /^()/m (capture) --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("ab\ncd\nef", "^()", "m") if err then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say(table.concat(res, ":")) ngx.say("len: ", #res) } --- stream_response ab ::cd ::ef len: 5 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 33: behavior with /^/m & max --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("ab\ncd\nef", "^", "m", nil, 2) if err then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say(table.concat(res, ":")) ngx.say("len: ", #res) } --- stream_response ab :cd ef len: 2 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 34: behavior with /^\d/m --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("ab\n1cdefg\n2hij", "^\\d", "m") if err then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say(table.concat(res, ":")) ngx.say("len: ", #res) } --- stream_response ab :cdefg :hij len: 3 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 35: behavior with /^(\d)/m (capture) --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local res, err = ngx_re.split("ab\n1cdefg\n2hij", "^(\\d)", "m") if err then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say(table.concat(res, ":")) ngx.say("len: ", #res) } --- stream_response ab :1:cdefg :2:hij len: 5 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 36: split by unit separator 1/2 (GH issue lua-nginx-module #1217) --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local subjs = { "1\x1fT\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f15", "1\x1fT\x1fT\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f15", "1\x1fT\x1fT\x1fT\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f15", } for _, subj in ipairs(subjs) do local col_list = ngx_re.split(subj, "\\x1f") ngx.say(#col_list, " ", table.concat(col_list, "|")) end } --- stream_response 15 1|T|||||||||||||15 15 1|T|T||||||||||||15 15 1|T|T|T|||||||||||15 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 37: split by unit separator 2/2 (with ctx.pos) --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local subjs = { "1\x1fT\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f15", "1\x1fT\x1fT\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f15", "1\x1fT\x1fT\x1fT\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f\x1f15", } for _, subj in ipairs(subjs) do local col_list = ngx_re.split(subj, "\\x1f", nil, { pos = 6 }) ngx.say(#col_list, " ", table.concat(col_list, "|")) end } --- stream_response 12 |||||||||||15 13 ||||||||||||15 13 |T|||||||||||15 --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 38: remaining characters are matched by regex (without max) --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local subj = "a,b,cd,,," local res, err = ngx_re.split(subj, ",") if err then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say(#res, " ", table.concat(res, "|")) } --- stream_response 3 a|b|cd --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] === TEST 39: remaining characters are matched by regex (with max) --- stream_server_config content_by_lua_block { local ngx_re = require "ngx.re" local subj = "a,b,cd,,," for max = 1, 7 do local res, err = ngx_re.split(subj, ",", nil, nil, max) if err then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say(#res, " ", table.concat(res, "|")) end } --- stream_response 1 a,b,cd,,, 2 a|b,cd,,, 3 a|b|cd,,, 4 a|b|cd|,, 5 a|b|cd||, 6 a|b|cd||| 6 a|b|cd||| --- error_log eval qr/\[TRACE\s+\d+/ --- no_error_log [error] lua-resty-core-0.1.31/t/stream/re-sub.t000066400000000000000000000136701474236722600176130ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore::Stream; #worker_connections(1014); #master_process_enabled(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 4 + 8); #no_diff(); no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: sub, no submatch, no jit compile, regex cache --- stream_server_config content_by_lua_block { local m, err local sub = ngx.re.sub for i = 1, 350 do s, n, err = sub("abcbd", "b", "B", "jo") end if not s then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say("s: ", s) ngx.say("n: ", n) } --- stream_response s: aBcbd n: 1 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] bad argument type NYI === TEST 2: sub, no submatch, no jit compile, no regex cache --- stream_server_config content_by_lua_block { local m, err local sub = ngx.re.sub for i = 1, 400 do s, n, err = sub("abcbd", "b", "B") end if not s then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say("s: ", s) ngx.say("n: ", n) } --- stream_response s: aBcbd n: 1 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] bad argument type === TEST 3: func + submatches --- stream_server_config content_by_lua_block { local m, err local function f(m) return "[" .. m[0] .. "(" .. m[1] .. ")]" end local sub = ngx.re.sub for i = 1, 200 do s, n, err = sub("abcbd", "b(c)", f, "jo") end if not s then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say("s: ", s) ngx.say("n: ", n) } --- stream_response s: a[bc(c)]bd n: 1 --- no_error_log eval [ "[error]", "bad argument type", qr/NYI (?!bytecode 51 at)/, ] === TEST 4: replace template + submatches --- stream_server_config content_by_lua_block { local m, err local sub = ngx.re.sub for i = 1, 350 do s, n, err = sub("abcbd", "b(c)", "[$0($1)]", "jo") end if not s then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say("s: ", s) ngx.say("n: ", n) } --- stream_response s: a[bc(c)]bd n: 1 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] bad argument type NYI === TEST 5: replace template + submatches (exceeding buffers) --- stream_server_config content_by_lua_block { local m, err local gsub = ngx.re.gsub local subj = string.rep("bcbd", 2048) for i = 1, 10 do s, n, err = gsub(subj, "b(c)", "[$0($1)]", "jo") end if not s then ngx.log(ngx.ERR, "failed: ", err) return end ngx.say("s: ", s) ngx.say("n: ", n) } --- stream_response eval "s: " . ("[bc(c)]bd" x 2048) . "\nn: 2048\n" --- no_error_log [error] bad argument type === TEST 6: ngx.re.gsub: use of resty.core's API in the user callback --- stream_config lua_shared_dict dogs 12k; --- stream_server_config content_by_lua_block { local dogs = ngx.shared.dogs assert(dogs:set("foo", "bar")) local data = [[ INNER INNER ]] local res = ngx.re.gsub(data, "INNER", function(inner_matches) assert(dogs:get("foo")) return "INNER_REPLACED" end, "s") ngx.print(res) } --- stream_response INNER_REPLACED INNER_REPLACED --- no_error_log [error] bad argument type NYI === TEST 7: ngx.re.gsub: recursive calling (github openresty/lua-nginx-module#445) --- stream_server_config content_by_lua_block { function test() local data = [[ OUTER {FIRST} ]] local p1 = "(OUTER)(.+)" local p2 = "{([A-Z]+)}" ngx.print(data) local res = ngx.re.gsub(data, p1, function(m) -- ngx.say("pre: m[1]: [", m[1], "]") -- ngx.say("pre: m[2]: [", m[2], "]") local res = ngx.re.gsub(m[2], p2, function(_) return "REPLACED" end, "") -- ngx.say("post: m[1]: [", m[1], "]") -- ngx.say("post m[2]: [", m[2], "]") return m[1] .. res end, "") ngx.print(res) end test() } --- stream_response OUTER {FIRST} OUTER REPLACED --- no_error_log [error] bad argument type NYI === TEST 8: string replace subj is not a string type --- stream_server_config content_by_lua_block { local newstr, n, err = ngx.re.sub(1234, "([0-9])[0-9]", 5, "jo") ngx.say(newstr) } --- stream_response 534 --- no_error_log [error] attempt to get length of local 'subj' (a number value) === TEST 9: func replace return is not a string type (ngx.re.sub) --- stream_server_config content_by_lua_block { local lookup = function(m) -- note we are returning a number type here return 5 end local newstr, n, err = ngx.re.sub("hello, 1234", "([0-9])[0-9]", lookup, "jo") ngx.say(newstr) } --- stream_response hello, 534 --- no_error_log [error] attempt to get length of local 'bit' (a number value) === TEST 10: func replace return is not a string type (ngx.re.gsub) --- stream_server_config content_by_lua_block { local lookup = function(m) -- note we are returning a number type here return 5 end local newstr, n, err = ngx.re.gsub("hello, 1234", "([0-9])[0-9]", lookup, "jo") ngx.say(newstr) } --- stream_response hello, 55 --- no_error_log [error] attempt to get length of local 'bit' (a number value) lua-resty-core-0.1.31/t/stream/request.t000066400000000000000000000014351474236722600201020ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore::Stream; repeat_each(2); plan tests => repeat_each() * (blocks() * 6); no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: ngx.req.start_time() --- stream_server_config content_by_lua_block { local t for i = 1, 500 do t = ngx.req.start_time() end ngx.sleep(0.10) local elapsed = ngx.now() - t ngx.say(t > 1399867351) ngx.say(">= 0.099: ", elapsed >= 0.099) ngx.say("< 0.11: ", elapsed < 0.11) -- ngx.say(t, " ", elapsed) } --- stream_response true >= 0.099: true < 0.11: true --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] bad argument type stitch lua-resty-core-0.1.31/t/stream/semaphore.t000066400000000000000000000634201474236722600203770ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore::Stream; #worker_connections(10140); #workers(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 3 + 2); no_long_string(); #no_diff(); $ENV{TEST_NGINX_LUA_PACKAGE_PATH} = "$t::TestCore::Stream::lua_package_path"; our $HttpConfig = <<_EOC_; lua_package_path "$t::TestCore::Stream::lua_package_path"; _EOC_ run_tests(); __DATA__ === TEST 1: basic semaphore in uthread --- stream_config eval: $::HttpConfig --- stream_server_config content_by_lua_block { local semaphore = require "ngx.semaphore" local sem = semaphore.new() local function sem_wait() ngx.say("enter waiting") local ok, err = sem:wait(1) if not ok then ngx.say("err: ", err) else ngx.say("wait success") end end local co = ngx.thread.spawn(sem_wait) ngx.say("back in main thread") sem:post() ngx.say("still in main thread") ngx.sleep(0.01) ngx.say("main thread end") } --- stream_response enter waiting back in main thread still in main thread wait success main thread end --- no_error_log [error] === TEST 2: semaphore wait order --- stream_config eval: $::HttpConfig --- stream_server_config content_by_lua_block { local semaphore = require "ngx.semaphore" local sem = semaphore.new() local function sem_wait(id) ngx.say("enter waiting, id: ", id) local ok, err = sem:wait(1) if not ok then ngx.say("err: ", err) else ngx.say("wait success, id: ", id) end end local co1 = ngx.thread.spawn(sem_wait, 1) local co2 = ngx.thread.spawn(sem_wait, 2) ngx.say("back in main thread") sem:post(2) local ok, err = sem:wait(0) if ok then ngx.say("wait success in main thread") else ngx.say("wait failed in main thread: ", err) -- busy end ngx.say("still in main thread") local ok, err = sem:wait(0.01) if ok then ngx.say("wait success in main thread") else ngx.say("wait failed in main thread: ", err) end ngx.sleep(0.01) ngx.say("main thread end") } --- stream_response enter waiting, id: 1 enter waiting, id: 2 back in main thread wait failed in main thread: timeout still in main thread wait success, id: 1 wait success, id: 2 wait failed in main thread: timeout main thread end --- no_error_log [error] === TEST 3: semaphore wait time=0 --- stream_config eval: $::HttpConfig --- stream_server_config content_by_lua_block { local semaphore = require "ngx.semaphore" local sem = semaphore.new(1) local function wait_1s() ngx.say("enter 1s wait") local ok, err = sem:wait(1) if not ok then ngx.say("err in wait 1s: ", err) else ngx.say("wait success in 1s wait") end end local function wait_0() local ok, err = sem:wait(0) if not ok then ngx.say("err: ", err) else ngx.say("wait success") end end wait_0() wait_0() local co = ngx.thread.spawn(wait_1s) ngx.say("back in main thread") wait_0() sem:post(2) wait_0() ngx.say("still in main thread") ngx.sleep(0.01) wait_0() ngx.say("main thread end") } --- stream_response wait success err: timeout enter 1s wait back in main thread err: timeout err: timeout still in main thread wait success in 1s wait wait success main thread end --- no_error_log [error] === TEST 4: semaphore.new in init_by_lua* (w/o shdict) --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { local semaphore = require "ngx.semaphore" local sem, err = semaphore.new(0) if not sem then ngx.log(ngx.ERR, err) else ngx.log(ngx.WARN, "sema created: ", tostring(sem)) end sem:post(2) package.loaded.my_sema = sem } --- stream_server_config content_by_lua_block { local sem = package.loaded.my_sema ngx.say("sem count: ", sem:count()) -- sem:post(1) local ok, err = sem:wait(0) if not ok then ngx.say("failed to wait: ", err) return end ngx.say("waited successfully.") } --- stream_response_like sem count: [12] waited successfully. --- grep_error_log eval qr/\[lua\] init_by_lua:\d+: sema created: table: 0x[a-f0-9]+/ --- grep_error_log_out eval [ qr/\[lua\] init_by_lua:\d+: sema created: table: 0x[a-f0-9]+/, "", ] === TEST 5: semaphore.new in init_by_lua* (with shdict) --- stream_config lua_shared_dict dogs 1m; lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_by_lua_block { local semaphore = require "ngx.semaphore" local sem, err = semaphore.new(0) if not sem then ngx.log(ngx.ERR, err) else ngx.log(ngx.WARN, "sema created: ", tostring(sem)) end sem:post(2) package.loaded.my_sema = sem } --- stream_server_config content_by_lua_block { local sem = package.loaded.my_sema ngx.say("sem count: ", sem:count()) -- sem:post(1) local ok, err = sem:wait(0) if not ok then ngx.say("failed to wait: ", err) return end ngx.say("waited successfully.") } --- stream_response_like sem count: [12] waited successfully. --- grep_error_log eval qr/\[lua\] init_by_lua:\d+: sema created: table: 0x[a-f0-9]+/ --- grep_error_log_out eval [ qr/\[lua\] init_by_lua:\d+: sema created: table: 0x[a-f0-9]+/, "", ] === TEST 6: semaphore in init_worker_by_lua (wait is not allowed) --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_worker_by_lua_block { local semaphore = require "ngx.semaphore" local sem, err = semaphore.new(0) if not sem then ngx.log(ngx.ERR, "sem new: ", err) end sem:post(1) local count = sem:count() ngx.log(ngx.ERR, "sem count: ", count) local ok, err = sem:wait(0.1) if not ok then ngx.log(ngx.ERR, "sem wait: ", err) end } --- stream_server_config return "ok"; --- stream_response chop ok --- grep_error_log eval: qr/sem \w+: .*?,/ --- grep_error_log_out eval [ "sem count: 1, sem wait: API disabled in the context of init_worker_by_lua*, ", "", ] === TEST 7: semaphore in init_worker_by_lua (new and post) --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_worker_by_lua_block { local semaphore = require "ngx.semaphore" local sem, err = semaphore.new(0) if not sem then ngx.log(ngx.ERR, "sem new: ", err) end sem:post(2) local count = sem:count() ngx.log(ngx.WARN, "sem count: ", count) package.loaded.my_sema = sem } --- stream_server_config content_by_lua_block { local sem = package.loaded.my_sema local ok, err = sem:wait(0.1) if not ok then ngx.say("failed to wait: ", err) return end ngx.say("sem wait successfully.") } --- stream_response sem wait successfully. --- grep_error_log eval: qr/sem \w+: .*?,/ --- grep_error_log_out eval [ "sem count: 2, ", "" ] --- no_error_log [error] === TEST 8: semaphore in preread_by_lua (all allowed) --- stream_config eval: $::HttpConfig --- stream_server_config preread_by_lua_block { local semaphore = require "ngx.semaphore" local sem, err = semaphore.new(0) if not sem then ngx.log(ngx.ERR, "sem: ", err) end local ok, err = sem:wait(0.01) if not ok then ngx.log(ngx.ERR, "sem: ", err) end sem:post(1) local count = sem:count() ngx.log(ngx.ERR, "sem: ", count) local ok, err = sem:wait(0.1) if not ok then ngx.log(ngx.ERR, "sem: ", err) end } return "ok"; --- stream_response chop ok --- grep_error_log eval: qr/sem: .*?,/ --- grep_error_log_out eval [ "sem: timeout while prereading client data, sem: 1 while prereading client data, ", "sem: timeout while prereading client data, sem: 1 while prereading client data, ", ] === TEST 9: semaphore in content_by_lua (all allowed) --- stream_config eval: $::HttpConfig --- stream_server_config content_by_lua_block { local semaphore = require "ngx.semaphore" local sem, err = semaphore.new(0) if not sem then ngx.log(ngx.ERR, "sem: ", err) end local ok, err = sem:wait(0.01) if not ok then ngx.log(ngx.ERR, "sem: ", err) end sem:post(1) local count = sem:count() ngx.log(ngx.ERR, "sem: ", count) local ok, err = sem:wait(0.1) if not ok then ngx.log(ngx.ERR, "sem: ", err) else ngx.say("ok") end } --- stream_response ok --- grep_error_log eval: qr/sem: .*?,/ --- grep_error_log_out eval [ "sem: timeout, sem: 1, ", "sem: timeout, sem: 1, ", ] === TEST 10: semaphore in log_by_lua (wait not allowed) --- stream_config eval: $::HttpConfig --- stream_server_config return "ok"; log_by_lua_block { local semaphore = require "ngx.semaphore" local sem, err = semaphore.new(0) if not sem then ngx.log(ngx.ERR, "sem: ", err) end sem:post(1) local count = sem:count() ngx.log(ngx.ERR, "sem: ", count) local ok, err = sem:wait(0.1) if not ok then ngx.log(ngx.ERR, "sem: ", err) end } --- stream_response chop ok --- grep_error_log eval: qr/sem: .*?,/ --- grep_error_log_out eval [ "sem: 1 while returning text, sem: API disabled in the context of log_by_lua* while returning text, ", "sem: 1 while returning text, sem: API disabled in the context of log_by_lua* while returning text, ", ] --- wait: 0.2 === TEST 11: semaphore in ngx.timer (all allowed) --- stream_config eval: $::HttpConfig --- stream_server_config content_by_lua_block { local function func_sem() local semaphore = require "ngx.semaphore" local sem, err = semaphore.new(0) if not sem then ngx.log(ngx.ERR, "sem: ", err) end local ok, err = sem:wait(0.01) if not ok then ngx.log(ngx.ERR, "sem: ", err) end sem:post(1) local count = sem:count() ngx.log(ngx.ERR, "sem: ", count) local ok, err = sem:wait(0.1) if not ok then ngx.log(ngx.ERR, "sem: ", err) end end local ok, err = ngx.timer.at(0, func_sem) if ok then ngx.sleep(0.01) ngx.say("ok") end } --- stream_response ok --- grep_error_log eval: qr/sem: .*?,/ --- grep_error_log_out eval [ "sem: timeout, sem: 1, ", "sem: timeout, sem: 1, ", ] --- wait: 0.2 === TEST 12: semaphore post in all phase (in a request) --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; init_worker_by_lua_block { local semaphore = require "ngx.semaphore" local sem, err = semaphore.new(0) if not sem then ngx.log(ngx.ERR, err) end package.loaded.sem = sem local function wait() local i = 0 while true do local ok, err = sem:wait(1) if not ok then ngx.log(ngx.ERR, "sem: ", err) end i = i + 1 if i % 3 == 0 then ngx.log(ngx.ERR, "sem: 3 times") end end end local ok, err = ngx.timer.at(0, wait) if not ok then ngx.log(ngx.ERR, "sem: ", err) end } --- stream_server_config preread_by_lua_block { local sem = package.loaded.sem sem:post() } content_by_lua_block { local sem = package.loaded.sem sem:post() ngx.say("ok") } log_by_lua_block { local sem = package.loaded.sem sem:post() } --- stream_response ok --- grep_error_log eval: qr/sem: .*?,/ --- grep_error_log_out eval [ "sem: 3 times, ", "sem: 3 times, ", ] --- wait: 0.2 === TEST 13: semaphore wait post in preread_by_lua --- stream_config eval: $::HttpConfig --- stream_server_config preread_by_lua_block { local semaphore = require "ngx.semaphore" local sem = semaphore.new(0) local func_wait = function () ngx.say("enter wait") local ok, err = sem:wait(1) if ok then ngx.say("wait success") end end local func_post = function () ngx.say("enter post") sem:post() ngx.say("post success") end local co1 = ngx.thread.spawn(func_wait) local co2 = ngx.thread.spawn(func_post) ngx.thread.wait(co1) ngx.thread.wait(co2) } return "done"; --- stream_response chop enter wait enter post post success wait success done --- no_error_log [error] === TEST 14: semaphore wait in timer.at --- stream_config eval: $::HttpConfig --- stream_server_config content_by_lua_block { local semaphore = require "ngx.semaphore" local sem = semaphore.new() local function func_wait(premature) local ok, err = sem:wait(1) if not ok then ngx.log(ngx.ERR, err) else ngx.log(ngx.ERR, "wait success") end end ngx.timer.at(0, func_wait) sem:post() ngx.sleep(0.01) ngx.say("ok") } --- stream_response ok --- error_log wait success === TEST 15: two thread wait for each other --- stream_config eval: $::HttpConfig --- stream_server_config content_by_lua_block { local semaphore = require "ngx.semaphore" local sem_A = semaphore.new(0) local sem_B = semaphore.new(0) if not sem_A or not sem_B then error("create failed") end local function th_A() for i = 1, 11 do local ok, err = sem_A:wait(1) if not ok then ngx.log(ngx.ERR, err) end sem_B:post(1) end ngx.say("count in A: ", sem_A:count()) end local function th_B() for i = 1, 10 do local ok, err = sem_B:wait(1) if not ok then ngx.log(ngx.ERR, err) end sem_A:post(1) end ngx.say("count in B: ", sem_B:count()) end local co_A = ngx.thread.spawn(th_A) local co_B = ngx.thread.spawn(th_B) sem_A:post(1) } --- log_level: debug --- stream_response count in B: 0 count in A: 0 --- no_error_log [error] === TEST 16: kill a light thread that is waiting on a semaphore (no resource) --- stream_config eval: $::HttpConfig --- stream_server_config content_by_lua_block { local semaphore = require "ngx.semaphore" local sem = semaphore.new(0) if not sem then error("create failed") end local function func_wait() sem:wait(1) end local co = ngx.thread.spawn(func_wait) local ok, err = ngx.thread.kill(co) if ok then ngx.say("ok") else ngx.say(err) end } --- log_level: debug --- stream_response ok --- no_error_log [error] === TEST 17: kill a light thread that is waiting on a semaphore (after post) --- stream_config eval: $::HttpConfig --- stream_server_config content_by_lua_block { local semaphore = require "ngx.semaphore" local sem = semaphore.new(0) if not sem then error("create failed") end local function func_wait() sem:wait(1) end local co = ngx.thread.spawn(func_wait) sem:post() local ok, err = ngx.thread.kill(co) if ok then ngx.say("ok") else ngx.say(err) end ngx.sleep(0.01) local count = sem:count() ngx.say("count: ", count) } --- log_level: debug --- stream_response ok count: 1 --- no_error_log [error] === TEST 18: kill a thread that is waiting on another thread that is waiting on semaphore --- stream_config eval: $::HttpConfig --- stream_server_config content_by_lua_block { local semaphore = require "ngx.semaphore" local sem = semaphore.new(0) if not sem then error("create failed") end local function sem_wait() ngx.say("sem waiting start") local ok, err = sem:wait(0.1) if not ok then ngx.say("sem wait err: ", err) end ngx.say("sem waiting done") end local function thread_wait() local co = ngx.thread.spawn(sem_wait) ngx.say("thread waiting start") local ok, err = ngx.thread.wait(co) if not ok then ngx.say("thread wait err: ", err) end ngx.say("thread waiting done") end local co2 = ngx.thread.spawn(thread_wait) ngx.sleep(0.01) local ok, err = ngx.thread.kill(co2) if ok then ngx.say("thread kill success") else ngx.say("kill err: ", err) end } --- log_level: debug --- stream_response sem waiting start thread waiting start thread kill success sem wait err: timeout sem waiting done --- no_error_log [error] === TEST 19: a light thread that is going to exit is waiting on a semaphore --- stream_config eval: $::HttpConfig --- stream_server_config content_by_lua_block { local semaphore = require "ngx.semaphore" local sem = semaphore.new(0) if not sem then error("create failed") end local function func(sem) ngx.say("sem waiting") local ok, err = sem:wait(0.1) if ok then ngx.say("wait success") else ngx.say("err: ", err) end end local co = ngx.thread.spawn(func, sem) ngx.say("ok") ngx.exit(200) } --- log_level: debug --- stream_response sem waiting ok --- error_log stream lua semaphore cleanup === TEST 20: main thread wait a light thread that is waiting on a semaphore --- stream_config eval: $::HttpConfig --- stream_server_config content_by_lua_block { local semaphore = require "ngx.semaphore" local sem = semaphore.new(0) if not sem then error("create failed") end local function func(sem) local ok, err = sem:wait(0.001) if ok then ngx.say("wait success") else ngx.say("err: ", err) end end local co = ngx.thread.spawn(func, sem) ngx.thread.wait(co) } --- log_level: debug --- stream_response err: timeout --- no_error_log [error] === TEST 21: multi wait and mult post with one semaphore --- stream_config eval: $::HttpConfig --- stream_server_config content_by_lua_block { local semaphore = require "ngx.semaphore" local sem, err = semaphore.new(0) if not sem then ngx.log(ngx.ERR, err) ngx.exit(500) end local function func(op, id) ngx.say(op, ": ", id) if op == "wait" then local ok, err = sem:wait(1) if ok then ngx.say("wait success: ", id) end else sem:post() end end local tco = {} for i = 1, 3 do tco[#tco + 1] = ngx.thread.spawn(func, "wait", i) end for i = 1, 3 do tco[#tco + 1] = ngx.thread.spawn(func, "post", i) end for i = 1, #tco do ngx.thread.wait(tco[i]) end } --- stream_response wait: 1 wait: 2 wait: 3 post: 1 post: 2 post: 3 wait success: 1 wait success: 2 wait success: 3 --- no_error_log [error] === TEST 22: semaphore wait time is zero --- stream_config eval: $::HttpConfig --- stream_server_config content_by_lua_block { local semaphore = require "ngx.semaphore" local sem = semaphore.new(0) local ok, err = sem:wait(0) if not ok then ngx.say(err) end } --- stream_response timeout --- no_error_log [error] === TEST 23: test semaphore gc --- stream_config eval: $::HttpConfig --- stream_server_config content_by_lua_block { local semaphore = require "ngx.semaphore" local sem, err = semaphore.new(0) if sem then ngx.say("success") end sem = nil collectgarbage("collect") } --- stream_response success --- log_level: debug --- error_log in lua gc, semaphore === TEST 24: basic semaphore_mm alloc --- stream_config eval: $::HttpConfig --- stream_server_config content_by_lua_block { local semaphore = require "ngx.semaphore" local sem = semaphore.new(0) if sem then ngx.say("ok") end } --- log_level: debug --- stream_response ok --- grep_error_log eval: qr/(new block, alloc semaphore|from head of free queue, alloc semaphore)/ --- grep_error_log_out eval [ "new block, alloc semaphore ", "from head of free queue, alloc semaphore ", ] === TEST 25: basic semaphore_mm free insert tail --- stream_config eval: $::HttpConfig --- stream_server_config content_by_lua_block { local semaphore = require "ngx.semaphore" local sems = package.loaded.sems or {} package.loaded.sems = sems local num_per_block = 4095 if not sems[num_per_block] then for i = 1, num_per_block * 3 do sems[i] = semaphore.new(0) end end for i = 1, 2 do if sems[i] then sems[i] = nil ngx.say("ok") break end end collectgarbage("collect") } --- log_level: debug --- stream_response ok --- error_log add to free queue tail === TEST 26: basic semaphore_mm free insert head --- stream_config eval: $::HttpConfig --- stream_server_config content_by_lua_block { local semaphore = require "ngx.semaphore" local sems = package.loaded.sems or {} package.loaded.sems = sems local num_per_block = 4095 if not sems[num_per_block] then for i = 1, num_per_block * 3 do sems[i] = semaphore.new(0) end end if sems[#sems] then sems[#sems] = nil ngx.say("ok") end collectgarbage("collect") } --- log_level: debug --- stream_response ok --- error_log add to free queue head === TEST 27: semaphore_mm free block (load <= 50% & the on the older side) --- stream_config eval: $::HttpConfig --- stream_server_config content_by_lua_block { local semaphore = require "ngx.semaphore" local sems = package.loaded.sems or {} package.loaded.sems = sems local num_per_block = 4095 if not sems[num_per_block * 3] then for i = 1, num_per_block * 3 do sems[i] = semaphore.new(0) end for i = num_per_block + 1, num_per_block * 2 do sems[i] = nil end else for i = 1, num_per_block do sems[i] = nil end end collectgarbage("collect") ngx.say("ok") } --- log_level: debug --- stream_response ok --- grep_error_log eval: qr/free semaphore block/ --- grep_error_log_out eval [ "", "free semaphore block ", ] --- timeout: 10 === TEST 28: basic semaphore count --- stream_config eval: $::HttpConfig --- stream_server_config content_by_lua_block { local semaphore = require "ngx.semaphore" local sem = semaphore.new(10) local count = sem:count() ngx.say(count) sem:wait(0) local count = sem:count() ngx.say(count) sem:post(3) local count = sem:count() ngx.say(count) } --- stream_response 10 9 12 --- no_error_log [error] === TEST 29: basic semaphore count (negative number) --- stream_config eval: $::HttpConfig --- stream_server_config content_by_lua_block { local semaphore = require "ngx.semaphore" local sem = semaphore.new() local count = sem:count() ngx.say(count) local function wait() sem:wait(0.01) end local co = ngx.thread.spawn(wait) local count = sem:count() ngx.say(count) } --- stream_response 0 -1 --- no_error_log [error] === TEST 30: bugfix: semaphore instance can't be garbage collected when someone is waiting on it --- stream_config eval: $::HttpConfig --- stream_server_config content_by_lua_block { local semaphore = require "ngx.semaphore" local my_sema = {} local key = "my key" local function my_clean() print("cleaning up") my_sema[key]:post() my_sema[key] = nil collectgarbage() end local ok, err = ngx.timer.at(0.001, my_clean) if not ok then ngx.log(ngx.ERR, "failed to create timer: ", err) ngx.exit(500) end my_sema[key] = semaphore:new(0) local ok, err = my_sema[key]:wait(2) ngx.say(ok, ", ", err) } --- stream_response true, nil --- no_error_log [error] [crit] lua-resty-core-0.1.31/t/stream/shdict.t000066400000000000000000001011541474236722600176670ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore::Stream; #worker_connections(1014); #master_process_enabled(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 5); add_block_preprocessor(sub { my $block = shift; my $stream_config = $block->stream_config || ''; $stream_config .= <<_EOC_; lua_shared_dict dogs 1m; lua_shared_dict cats 16k; lua_shared_dict birds 100k; $t::TestCore::Stream::StreamConfig _EOC_ $block->set_value("stream_config", $stream_config); }); #no_diff(); no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: get a string value --- stream_server_config content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) local ok, err, forcible = dogs:set("foo", "bar", 0, 72) if not ok then ngx.say("failed to set: ", err) return end for i = 1, 100 do val, flags = dogs:get("foo") end ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } --- stream_response value type: string value: bar flags: 72 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):11 loop\]/ --- no_error_log [error] -- NYI: === TEST 2: get an nonexistent key --- stream_server_config content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) -- dogs:set("foo", "bar") for i = 1, 100 do val, flags = dogs:get("nonexistent") end ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } --- stream_response value type: nil value: nil flags: nil --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):7 loop\]/ --- no_error_log [error] -- NYI: === TEST 3: get a boolean value (true) --- stream_server_config content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) dogs:set("foo", true, 0, 5678) for i = 1, 100 do val, flags = dogs:get("foo") end ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } --- stream_response value type: boolean value: true flags: 5678 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):7 loop\]/ --- no_error_log [error] -- NYI: === TEST 4: get a boolean value (false) --- stream_server_config content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) dogs:set("foo", false, 0, 777) for i = 1, 100 do val, flags = dogs:get("foo") end ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } --- stream_response value type: boolean value: false flags: 777 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):7 loop\]/ --- no_error_log [error] -- NYI: === TEST 5: get a number value (int) --- stream_server_config content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) dogs:set("foo", 51203) for i = 1, 100 do val, flags = dogs:get("foo") end ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } --- stream_response value type: number value: 51203 flags: nil --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):7 loop\]/ --- no_error_log [error] -- NYI: === TEST 6: get a number value (double) --- stream_server_config content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) dogs:set("foo", 3.1415926, 0, 78) for i = 1, 100 do val, flags = dogs:get("foo") end ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } --- stream_response value type: number value: 3.1415926 flags: 78 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):7 loop\]/ --- no_error_log [error] -- NYI: === TEST 7: get a large string value --- stream_server_config content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) dogs:flush_all() dogs:flush_expired() dogs:set("foo", string.rep("bbbb", 1024) .. "a", 0, 912) for i = 1, 100 do val, flags = dogs:get("foo") end ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } --- stream_response eval "value type: string value: " . ("bbbb" x 1024) . "a flags: 912 " --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):9 loop\]/ --- no_error_log [error] -- NYI: === TEST 8: get_stale (false) --- stream_server_config content_by_lua_block { local ffi = require "ffi" local val, flags, stale local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) dogs:flush_all() dogs:flush_expired() dogs:set("foo", "bar", 0, 72) for i = 1, 100 do val, flags, stale = dogs:get_stale("foo") end ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) ngx.say("stale: ", stale) } --- stream_response value type: string value: bar flags: 72 stale: false --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):9 loop\]/ --- no_error_log [error] -- NYI: === TEST 9: get_stale (true) --- stream_server_config content_by_lua_block { local ffi = require "ffi" local val, flags, stale local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) local ok, err, forcible = dogs:set("foo", "bar", 0.01, 72) if not ok then ngx.say("failed to set: ", err) return end ngx.update_time() ngx.sleep(0.02) for i = 1, 100 do val, flags, stale = dogs:get_stale("foo") end ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) ngx.say("stale: ", stale) } --- stream_response value type: string value: bar flags: 72 stale: true --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):13 loop\]/ --- no_error_log [error] -- NYI: === TEST 10: incr int --- stream_server_config content_by_lua_block { local ffi = require "ffi" local val local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) local ok, err, forcible = dogs:set("foo", 56) if not ok then ngx.say("failed to set: ", err) return end for i = 1, 100 do val, err = dogs:incr("foo", 2) end ngx.say("value: ", val) ngx.say("err: ", err) } --- stream_response value: 256 err: nil --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):11 loop\]/ --- no_error_log [error] -- NYI: === TEST 11: incr double --- stream_server_config content_by_lua_block { local ffi = require "ffi" local val, err local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) dogs:set("foo", 56) for i = 1, 150 do val, err = dogs:incr("foo", 2.1) end ngx.say("value: ", val) ngx.say("err: ", err) } --- stream_response value: 371 err: nil --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):7 loop\]/ --- no_error_log [error] -- NYI: === TEST 12: set a string value --- stream_server_config content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) local ok, err, forcible for i = 1, 100 do ok, err, forcible = dogs:set("foo", "bar", 0, 72) end if not ok then ngx.say("failed to set: ", err) return end val, flags = dogs:get("foo") ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } --- stream_response value type: string value: bar flags: 72 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):7 loop\]/ --- no_error_log [error] -- NYI: === TEST 13: set a boolean value (true) --- stream_server_config content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) local ok, err, forcible for i = 1, 100 do ok, err, forcible = dogs:set("foo", true, 0, 5678) end if not ok then ngx.say("failed to set: ", err) return end val, flags = dogs:get("foo") ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } --- stream_response value type: boolean value: true flags: 5678 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):7 loop\]/ --- no_error_log [error] -- NYI: === TEST 14: set a boolean value (false) --- stream_server_config content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) for i = 1, 100 do dogs:set("foo", false, 0, 777) end val, flags = dogs:get("foo") ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } --- stream_response value type: boolean value: false flags: 777 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):6 loop\]/ --- no_error_log [error] -- NYI: === TEST 15: set a number value (int) --- stream_server_config content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) for i = 1, 100 do dogs:set("foo", 51203) end val, flags = dogs:get("foo") ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } --- stream_response value type: number value: 51203 flags: nil --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):6 loop\]/ --- no_error_log [error] -- NYI: === TEST 16: set a number value (double) --- stream_server_config content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) for i = 1, 100 do dogs:set("foo", 3.1415926, 0, 78) end val, flags = dogs:get("foo") ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } --- stream_response value type: number value: 3.1415926 flags: 78 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):6 loop\]/ --- no_error_log [error] -- NYI: === TEST 17: set a number value and a nil --- stream_server_config content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) for i = 1, 150 do dogs:set("foo", 3.1415926, 0, 78) dogs:set("foo", nil) end val, flags = dogs:get("foo") ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } --- stream_response value type: nil value: nil flags: nil --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):6 loop\]/ --- no_error_log [error] -- NYI: === TEST 18: safe set a number value --- stream_server_config content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) dogs:flush_all() dogs:flush_expired() for i = 1, 100 do dogs:safe_set("foo", 3.1415926, 0, 78) end val, flags = dogs:get("foo") ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } --- stream_response value type: number value: 3.1415926 flags: 78 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):8 loop\]/ --- no_error_log [error] -- NYI: === TEST 19: add a string value --- stream_server_config content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) dogs:flush_all() local ok, err, forcible for i = 1, 100 do ok, err, forcible = dogs:add("foo" .. i, "bar", 0, 72) end if not ok then ngx.say("failed to set: ", err) return end val, flags = dogs:get("foo100") ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } --- stream_response value type: string value: bar flags: 72 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):8 loop\]/ --- no_error_log [error] -- NYI: === TEST 20: safe add a string value --- stream_server_config content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) dogs:flush_all() dogs:flush_expired() local ok, err, forcible for i = 1, 100 do ok, err, forcible = dogs:safe_add("foo" .. i, "bar", 0, 72) end if not ok then ngx.say("failed to set: ", err) return end val, flags = dogs:get("foo100") ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } --- stream_response value type: string value: bar flags: 72 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):9 loop\]/ --- no_error_log [error] -- NYI: === TEST 21: replace a string value --- stream_server_config content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) dogs:set("foo", "hello") local ok, err, forcible for i = 1, 100 do ok, err, forcible = dogs:replace("foo", "bar" .. i, 0, 72) end if not ok then ngx.say("failed to set: ", err) return end val, flags = dogs:get("foo") ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } --- stream_response value type: string value: bar100 flags: 72 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):8 loop\]/ --- no_error_log [error] -- NYI: === TEST 22: set a number value and delete --- stream_server_config content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs -- local cd = ffi.cast("void *", dogs) for i = 1, 150 do dogs:set("foo", 3.1415926, 0, 78) dogs:delete("foo") end val, flags = dogs:get("foo") ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } --- stream_response value type: nil value: nil flags: nil --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):6 loop\]/ --- no_error_log [error] -- NYI: stitch === TEST 23: set nil key --- stream_server_config content_by_lua_block { local val, flags local dogs = ngx.shared.dogs local ok, err = dogs:set(nil, "bar") if not ok then ngx.say("failed to set: ", err) end } --- stream_response failed to set: nil key --- no_error_log [error] [alert] [crit] === TEST 24: get nil key --- stream_server_config content_by_lua_block { local val, flags local dogs = ngx.shared.dogs local value, err = dogs:get(nil, "bar") if not ok then ngx.say("failed to get: ", err) end } --- stream_response failed to get: nil key --- no_error_log [error] [alert] [crit] === TEST 25: get stale key --- stream_server_config content_by_lua_block { local val, flags local dogs = ngx.shared.dogs local value, err = dogs:get_stale(nil, "bar") if not ok then ngx.say("failed to get stale: ", err) end } --- stream_response failed to get stale: nil key --- no_error_log [error] [alert] [crit] === TEST 26: incr key --- stream_server_config content_by_lua_block { local val, flags local dogs = ngx.shared.dogs local value, err = dogs:incr(nil, 32) if not value then ngx.say("failed to incr: ", err) end } --- stream_response failed to incr: nil key --- no_error_log [error] [alert] [crit] === TEST 27: flush_all --- stream_server_config content_by_lua_block { local ffi = require "ffi" local val, flags local dogs = ngx.shared.dogs dogs:set("foo", "bah") -- local cd = ffi.cast("void *", dogs) for i = 1, 150 do dogs:flush_all() end val, flags = dogs:get("foo") ngx.say("value type: ", type(val)) ngx.say("value: ", val) ngx.say("flags: ", flags) } --- stream_response value type: nil value: nil flags: nil --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):7 loop\]/ --- no_error_log [error] -- NYI: stitch === TEST 28: incr, value is not number --- stream_server_config content_by_lua_block { local val, flags local dogs = ngx.shared.dogs local value, err = dogs:incr("foo", "bar") if not value then ngx.say("failed to incr: ", err) end } --- error_log cannot convert 'nil' to 'double' --- no_error_log [alert] [crit] === TEST 29: incr with init --- stream_server_config content_by_lua_block { local val, flags local dogs = ngx.shared.dogs dogs:flush_all() local value, err = dogs:incr("foo", 10) if not value then ngx.say("failed to incr: ", err) end local value, err, forcible = dogs:incr("foo", 10, 10) if not value then ngx.say("failed to incr: ", err) return end ngx.say("incr ok, value: ", value, ", forcible: ", forcible) } --- stream_response failed to incr: not found incr ok, value: 20, forcible: false --- no_error_log [error] [alert] [crit] === TEST 30: incr, init is not number --- stream_server_config content_by_lua_block { local val, flags local dogs = ngx.shared.dogs local value, err = dogs:incr("foo", 10, "bar") if not ok then ngx.say("failed to incr: ", err) end } --- error_log number expected, got string --- no_error_log [alert] [crit] === TEST 31: capacity --- stream_server_config content_by_lua_block { local cats = ngx.shared.cats local capacity = cats:capacity() ngx.say("capacity type: ", type(capacity)) ngx.say("capacity: ", capacity) } --- stream_response capacity type: number capacity: 16384 --- no_error_log [error] [alert] [crit] === TEST 32: free_space, empty (16k zone) --- skip_nginx: 5: < 1.11.7 --- stream_server_config content_by_lua_block { local cats = ngx.shared.cats cats:flush_all() cats:flush_expired() local free_page_bytes = cats:free_space() ngx.say("free_page_bytes type: ", type(free_page_bytes)) ngx.say("free_page_bytes: ", free_page_bytes) } --- stream_response free_page_bytes type: number free_page_bytes: 4096 --- no_error_log [error] [alert] [crit] === TEST 33: free_space, empty (100k zone) --- skip_nginx: 5: < 1.11.7 --- stream_server_config content_by_lua_block { local birds = ngx.shared.birds birds:flush_all() birds:flush_expired() local free_page_bytes = birds:free_space() ngx.say("free_page_bytes type: ", type(free_page_bytes)) ngx.say("free_page_bytes: ", free_page_bytes) } --- stream_response_like chomp \Afree_page_bytes type: number free_page_bytes: (?:90112|94208) \z --- no_error_log [error] [alert] [crit] === TEST 34: free_space, about half full, one page left --- skip_nginx: 5: < 1.11.7 --- stream_server_config content_by_lua_block { local cats = ngx.shared.cats cats:flush_all() cats:flush_expired() for i = 1, 31 do local key = string.format("key%05d", i) local val = string.format("val%05d", i) local success, err, forcible = cats:set(key, val) if err ~= nil then ngx.say(string.format("got error, i=%d, err=%s", i, err)) end if forcible then ngx.say(string.format("got forcible, i=%d", i)) end if not success then ngx.say(string.format("got not success, i=%d", i)) end end local free_page_bytes = cats:free_space() ngx.say("free_page_bytes type: ", type(free_page_bytes)) ngx.say("free_page_bytes: ", free_page_bytes) } --- stream_response free_page_bytes type: number free_page_bytes: 4096 --- no_error_log [error] [alert] [crit] === TEST 35: free_space, about half full, no page left --- skip_nginx: 5: < 1.11.7 --- stream_server_config content_by_lua_block { local cats = ngx.shared.cats cats:flush_all() cats:flush_expired() for i = 1, 32 do local key = string.format("key%05d", i) local val = string.format("val%05d", i) local success, err, forcible = cats:set(key, val) if err ~= nil then ngx.say(string.format("got error, i=%d, err=%s", i, err)) end if forcible then ngx.say(string.format("got forcible, i=%d", i)) end if not success then ngx.say(string.format("got not success, i=%d", i)) end end local free_page_bytes = cats:free_space() ngx.say("free_page_bytes type: ", type(free_page_bytes)) ngx.say("free_page_bytes: ", free_page_bytes) } --- stream_response_like chomp \Afree_page_bytes type: number free_page_bytes: (?:0|4096) \z --- no_error_log [error] [alert] [crit] === TEST 36: free_space, full --- skip_nginx: 5: < 1.11.7 --- stream_server_config content_by_lua_block { local cats = ngx.shared.cats cats:flush_all() cats:flush_expired() for i = 1, 63 do local key = string.format("key%05d", i) local val = string.format("val%05d", i) local success, err, forcible = cats:set(key, val) if err ~= nil then ngx.say(string.format("got error, i=%d, err=%s", i, err)) end if forcible then ngx.say(string.format("got forcible, i=%d", i)) end if not success then ngx.say(string.format("got not success, i=%d", i)) end end local free_page_bytes = cats:free_space() ngx.say("free_page_bytes type: ", type(free_page_bytes)) ngx.say("free_page_bytes: ", free_page_bytes) } --- stream_response free_page_bytes type: number free_page_bytes: 0 --- no_error_log [error] [alert] [crit] === TEST 37: free_space, got forcible --- skip_nginx: 5: < 1.11.7 --- stream_server_config content_by_lua_block { local cats = ngx.shared.cats cats:flush_all() cats:flush_expired() for i = 1, 64 do local key = string.format("key%05d", i) local val = string.format("val%05d", i) local success, err, forcible = cats:set(key, val) if err ~= nil then ngx.say(string.format("got error, i=%d, err=%s", i, err)) end if forcible then ngx.say(string.format("got forcible, i=%d", i)) end if not success then ngx.say(string.format("got not success, i=%d", i)) end end local free_page_bytes = cats:free_space() ngx.say("free_page_bytes type: ", type(free_page_bytes)) ngx.say("free_page_bytes: ", free_page_bytes) } --- stream_response_like chomp \A(?:got forcible, i=64 )?free_page_bytes type: number free_page_bytes: 0 \z --- no_error_log [error] [alert] [crit] === TEST 38: free_space, full (100k) --- skip_nginx: 5: < 1.11.7 --- stream_server_config content_by_lua_block { local birds = ngx.shared.birds birds:flush_all() birds:flush_expired() for i = 1, 1000 do local key = string.format("key%05d", i) local val = string.format("val%05d", i) local ok, err, forcible = birds:set(key, val) if err ~= nil then ngx.say(string.format("got error, i=%d, err=%s", i, err)) end if forcible then ngx.say(string.format("got forcible, i=%d", i)) break end if not ok then ngx.say(string.format("got not ok, i=%d", i)) break end end local free_page_bytes = birds:free_space() ngx.say("free_page_bytes type: ", type(free_page_bytes)) ngx.say("free_page_bytes: ", free_page_bytes) } --- stream_response_like chomp \A(?:got forcible, i=736 )?free_page_bytes type: number free_page_bytes: (?:0|32768) \z --- no_error_log [error] [alert] [crit] === TEST 39: incr bad init_ttl argument --- stream_server_config content_by_lua_block { local dogs = ngx.shared.dogs local pok, err = pcall(dogs.incr, dogs, "foo", 1, 0, -1) if not pok then ngx.say("not ok: ", err) return end ngx.say("ok") } --- stream_response not ok: bad "init_ttl" argument --- no_error_log [error] [alert] [crit] === TEST 40: incr init_ttl argument is not a number --- stream_server_config content_by_lua_block { local dogs = ngx.shared.dogs local pok, err = pcall(dogs.incr, dogs, "foo", 1, 0, "bar") if not pok then ngx.say("not ok: ", err) return end ngx.say("ok") } --- stream_response not ok: bad init_ttl arg: number expected, got string --- no_error_log [error] [alert] [crit] === TEST 41: incr init_ttl argument without init --- stream_server_config content_by_lua_block { local dogs = ngx.shared.dogs local pok, err = pcall(dogs.incr, dogs, "foo", 1, nil, 0.01) if not pok then ngx.say("not ok: ", err) return end ngx.say("ok") } --- stream_response not ok: must provide "init" when providing "init_ttl" --- no_error_log [error] [alert] [crit] === TEST 42: incr key with init_ttl (key exists) --- stream_server_config content_by_lua_block { local dogs = ngx.shared.dogs dogs:set("foo", 32) local res, err = dogs:incr("foo", 10502, 0, 0.01) ngx.say("incr: ", res, " ", err) ngx.say("foo = ", dogs:get("foo")) ngx.update_time() ngx.sleep(0.02) ngx.say("foo after incr init_ttl = ", dogs:get("foo")) } --- stream_response incr: 10534 nil foo = 10534 foo after incr init_ttl = 10534 --- no_error_log [error] [alert] [crit] === TEST 43: incr key with init and init_ttl (key not exists) --- stream_server_config content_by_lua_block { local dogs = ngx.shared.dogs dogs:flush_all() local res, err = dogs:incr("foo", 10502, 1, 0.01) ngx.say("incr: ", res, " ", err) ngx.say("foo = ", dogs:get("foo")) ngx.update_time() ngx.sleep(0.02) ngx.say("foo after init_ttl = ", dogs:get("foo")) } --- stream_response incr: 10503 nil foo = 10503 foo after init_ttl = nil --- no_error_log [error] [alert] [crit] === TEST 44: incr key with init and init_ttl as string (key not exists) --- stream_server_config content_by_lua_block { local dogs = ngx.shared.dogs dogs:flush_all() local res, err = dogs:incr("foo", 10502, 1, "0.01") ngx.say("incr: ", res, " ", err) ngx.say("foo = ", dogs:get("foo")) ngx.update_time() ngx.sleep(0.02) ngx.say("foo after init_ttl = ", dogs:get("foo")) } --- stream_response incr: 10503 nil foo = 10503 foo after init_ttl = nil --- no_error_log [error] [alert] [crit] === TEST 45: incr key with init and init_ttl (key expired and size matched) --- stream_server_config content_by_lua_block { local dogs = ngx.shared.dogs for i = 1, 100 do dogs:set("bar" .. i, i, 0.02) end dogs:set("foo", 32, 0.02) ngx.update_time() ngx.sleep(0.03) local res, err = dogs:incr("foo", 10502, 0, 0.01) ngx.say("incr: ", res, " ", err) ngx.say("foo = ", dogs:get("foo")) ngx.update_time() ngx.sleep(0.02) ngx.say("foo after init_ttl = ", dogs:get("foo")) } --- stream_response incr: 10502 nil foo = 10502 foo after init_ttl = nil --- no_error_log [error] [alert] [crit] === TEST 46: incr key with init and init_ttl (forcibly override other valid entries) --- stream_server_config content_by_lua_block { local dogs = ngx.shared.dogs dogs:flush_all() local long_prefix = string.rep("1234567890", 100) for i = 1, 1000 do local success, err, forcible = dogs:set(long_prefix .. i, i) if forcible then dogs:delete(long_prefix .. i) break end end local res, err, forcible = dogs:incr(long_prefix .. "bar", 10502, 0) ngx.say("incr: ", res, " ", err, " ", forcible) local res, err, forcible = dogs:incr(long_prefix .. "foo", 10502, 0, 0.01) ngx.say("incr: ", res, " ", err, " ", forcible) ngx.say("foo = ", dogs:get(long_prefix .. "foo")) ngx.update_time() ngx.sleep(0.02) ngx.say("foo after init_ttl = ", dogs:get("foo")) } --- stream_response incr: 10502 nil false incr: 10502 nil true foo = 10502 foo after init_ttl = nil --- no_error_log [error] [alert] [crit] === TEST 47: exptime uses long type to avoid overflow in set() + ttl() --- stream_server_config content_by_lua_block { local dogs = ngx.shared.dogs dogs:flush_all() local ok, err = dogs:set("huge_ttl", true, 2 ^ 31) if not ok then ngx.say("err setting: ", err) return end local ttl, err = dogs:ttl("huge_ttl") if not ttl then ngx.say("err retrieving ttl: ", err) return end ngx.say("ttl: ", ttl) } --- stream_response ttl: 2147483648 --- no_error_log [error] [alert] [crit] === TEST 48: exptime uses long type to avoid overflow in expire() + ttl() --- stream_server_config content_by_lua_block { local dogs = ngx.shared.dogs dogs:flush_all() local ok, err = dogs:set("updated_huge_ttl", true) if not ok then ngx.say("err setting: ", err) return end local ok, err = dogs:expire("updated_huge_ttl", 2 ^ 31) if not ok then ngx.say("err expire: ", err) return end local ttl, err = dogs:ttl("updated_huge_ttl") if not ttl then ngx.say("err retrieving ttl: ", err) return end ngx.say("ttl: ", ttl) } --- stream_response ttl: 2147483648 --- no_error_log [error] [alert] [crit] === TEST 49: init_ttl uses long type to avoid overflow in incr() + ttl() --- stream_server_config content_by_lua_block { local dogs = ngx.shared.dogs dogs:flush_all() local ok, err = dogs:incr("incr_huge_ttl", 1, 0, 2 ^ 31) if not ok then ngx.say("err incr: ", err) return end local ttl, err = dogs:ttl("incr_huge_ttl") if not ttl then ngx.say("err retrieving ttl: ", err) return end ngx.say("ttl: ", ttl) } --- stream_response ttl: 2147483648 --- no_error_log [error] [alert] [crit] lua-resty-core-0.1.31/t/stream/ssl.t000066400000000000000000001702301474236722600172130ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore::Stream; #worker_connections(10140); #workers(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 6 + 1); no_long_string(); #no_diff(); env_to_nginx("PATH=" . $ENV{'PATH'}); $ENV{TEST_NGINX_LUA_PACKAGE_PATH} = "$t::TestCore::Stream::lua_package_path"; $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); run_tests(); __DATA__ === TEST 1: clear certs --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" ssl.clear_certs() } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; return 'it works!\n'; } --- stream_server_config lua_ssl_trusted_certificate ../../cert/test.crt; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } --- stream_response connected: 1 failed to do SSL handshake: handshake failed --- error_log lua ssl server name: "test.com" sslv3 alert handshake failure --- no_error_log [alert] [emerg] === TEST 2: set DER cert and private key --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" ssl.clear_certs() local f = assert(io.open("t/cert/test.crt.der")) local cert_data = f:read("*a") f:close() local ok, err = ssl.set_der_cert(cert_data) if not ok then ngx.log(ngx.ERR, "failed to set DER cert: ", err) return end local f = assert(io.open("t/cert/test.key.der")) local pkey_data = f:read("*a") f:close() local ok, err = ssl.set_der_priv_key(pkey_data) if not ok then ngx.log(ngx.ERR, "failed to set DER cert: ", err) return end } ssl_certificate ../../cert/test2.crt; ssl_certificate_key ../../cert/test2.key; return 'it works!\n'; } --- stream_server_config lua_ssl_trusted_certificate ../../cert/test.crt; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } --- stream_response connected: 1 ssl handshake: userdata received: it works! close: 1 nil --- error_log lua ssl server name: "test.com" --- no_error_log [error] [alert] [emerg] === TEST 3: read SNI name via ssl.server_name() --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" print("read SNI name from Lua: ", ssl.server_name()) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; return 'it works!\n'; } --- stream_server_config lua_ssl_trusted_certificate ../../cert/test.crt; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } --- stream_response connected: 1 ssl handshake: userdata received: it works! close: 1 nil --- error_log lua ssl server name: "test.com" read SNI name from Lua: test.com --- no_error_log [error] [alert] === TEST 4: read SNI name via ssl.server_name() when no SNI name specified --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local name = ssl.server_name(), print("read SNI name from Lua: ", name, ", type: ", type(name)) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; return 'it works!\n'; } --- stream_server_config lua_ssl_trusted_certificate ../../cert/test.crt; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, nil, true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } --- stream_response connected: 1 ssl handshake: userdata received: it works! close: 1 nil --- error_log read SNI name from Lua: nil, type: nil --- no_error_log [error] [alert] [emerg] === TEST 5: read raw server addr via ssl.raw_server_addr() (unix domain socket) --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local addr, addrtyp, err = ssl.raw_server_addr() if not addr then ngx.log(ngx.ERR, "failed to fetch raw server addr: ", err) return end if addrtyp == "inet" then -- IPv4 ip = string.format("%d.%d.%d.%d", byte(addr, 1), byte(addr, 2), byte(addr, 3), byte(addr, 4)) print("Using IPv4 address: ", ip) elseif addrtyp == "inet6" then -- IPv6 ip = string.format("%d.%d.%d.%d", byte(addr, 13), byte(addr, 14), byte(addr, 15), byte(addr, 16)) print("Using IPv6 address: ", ip) else -- unix print("Using unix socket file ", addr) end } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; return 'it works!\n'; } --- stream_server_config lua_ssl_trusted_certificate ../../cert/test.crt; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } --- stream_response connected: 1 ssl handshake: userdata received: it works! close: 1 nil --- error_log eval [ 'lua ssl server name: "test.com"', qr/Using unix socket file .*?nginx\.sock/ ] --- no_error_log [error] [alert] --- no_check_leak === TEST 6: read raw server addr via ssl.raw_server_addr() (IPv4) --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen 127.0.0.1:$TEST_NGINX_RAND_PORT_1 ssl; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local byte = string.byte local addr, addrtyp, err = ssl.raw_server_addr() if not addr then ngx.log(ngx.ERR, "failed to fetch raw server addr: ", err) return end if addrtyp == "inet" then -- IPv4 ip = string.format("%d.%d.%d.%d", byte(addr, 1), byte(addr, 2), byte(addr, 3), byte(addr, 4)) print("Using IPv4 address: ", ip) elseif addrtyp == "inet6" then -- IPv6 ip = string.format("%d.%d.%d.%d", byte(addr, 13), byte(addr, 14), byte(addr, 15), byte(addr, 16)) print("Using IPv6 address: ", ip) else -- unix print("Using unix socket file ", addr) end } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; return 'it works!\n'; } --- stream_server_config lua_ssl_trusted_certificate ../../cert/test.crt; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } --- stream_response connected: 1 ssl handshake: userdata received: it works! close: 1 nil --- error_log lua ssl server name: "test.com" Using IPv4 address: 127.0.0.1 --- no_error_log [error] [alert] --- no_check_leak === TEST 7: read raw server addr via ssl.raw_server_addr() (IPv6) --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen [::1]:$TEST_NGINX_RAND_PORT_1 ssl; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local byte = string.byte local addr, addrtyp, err = ssl.raw_server_addr() if not addr then ngx.log(ngx.ERR, "failed to fetch raw server addr: ", err) return end if addrtyp == "inet" then -- IPv4 ip = string.format("%d.%d.%d.%d", byte(addr, 1), byte(addr, 2), byte(addr, 3), byte(addr, 4)) print("Using IPv4 address: ", ip) elseif addrtyp == "inet6" then -- IPv6 ip = string.format("%d.%d.%d.%d", byte(addr, 13), byte(addr, 14), byte(addr, 15), byte(addr, 16)) print("Using IPv6 address: ", ip) else -- unix print("Using unix socket file ", addr) end } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; return 'it works!\n'; } --- stream_server_config lua_ssl_trusted_certificate ../../cert/test.crt; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("[::1]", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } --- stream_response connected: 1 ssl handshake: userdata received: it works! close: 1 nil --- error_log lua ssl server name: "test.com" Using IPv6 address: 0.0.0.1 --- no_error_log [error] [alert] --- skip_eval: 6: system("ping6 -c 1 ::1 >/dev/null 2>&1") ne 0 --- no_check_leak === TEST 8: set DER cert chain --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" ssl.clear_certs() local f = assert(io.open("t/cert/chain/chain.der")) local cert_data = f:read("*a") f:close() local ok, err = ssl.set_der_cert(cert_data) if not ok then ngx.log(ngx.ERR, "failed to set DER cert: ", err) return end local f = assert(io.open("t/cert/chain/test-com.key.der")) local pkey_data = f:read("*a") f:close() local ok, err = ssl.set_der_priv_key(pkey_data) if not ok then ngx.log(ngx.ERR, "failed to set DER cert: ", err) return end } ssl_certificate ../../cert/test2.crt; ssl_certificate_key ../../cert/test2.key; return 'it works!\n'; } --- stream_server_config lua_ssl_trusted_certificate ../../cert/chain/root-ca.crt; lua_ssl_verify_depth 3; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } --- stream_response connected: 1 ssl handshake: userdata received: it works! close: 1 nil --- error_log lua ssl server name: "test.com" --- no_error_log [error] [alert] [emerg] === TEST 9: read PEM cert chain but set DER cert chain --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" ssl.clear_certs() local f = assert(io.open("t/cert/chain/chain.pem")) local cert_data = f:read("*a") f:close() local cert, err = ssl.cert_pem_to_der(cert_data) if not cert then ngx.log(ngx.ERR, "failed to convert pem cert to der cert: ", err) return end local ok, err = ssl.set_der_cert(cert) if not ok then ngx.log(ngx.ERR, "failed to set DER cert: ", err) return end local f = assert(io.open("t/cert/chain/test-com.key.der")) local pkey_data = f:read("*a") f:close() local ok, err = ssl.set_der_priv_key(pkey_data) if not ok then ngx.log(ngx.ERR, "failed to set DER private key: ", err) return end } ssl_certificate ../../cert/test2.crt; ssl_certificate_key ../../cert/test2.key; return 'it works!\n'; } --- stream_server_config lua_ssl_trusted_certificate ../../cert/chain/root-ca.crt; lua_ssl_verify_depth 3; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } --- stream_response connected: 1 ssl handshake: userdata received: it works! close: 1 nil --- error_log lua ssl server name: "test.com" --- no_error_log [error] [alert] [emerg] === TEST 10: tls version - SSLv3 --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen 127.0.0.2:$TEST_NGINX_RAND_PORT_1 ssl; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ver, err = ssl.get_tls1_version_str(resp) if not ver then ngx.log(ngx.ERR, "failed to get TLS1 version: ", err) return end ngx.log(ngx.WARN, "got TLS1 version: ", ver) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; ssl_protocols SSLv3; return 'it works!\n'; } --- stream_server_config lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_verify_depth 3; lua_ssl_protocols SSLv3; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("127.0.0.2", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(false, nil, true, false) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) end -- do } --- stream_response connected: 1 ssl handshake: boolean --- error_log got TLS1 version: SSLv3, --- no_error_log [error] [alert] [emerg] === TEST 11: tls version - TLSv1 --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen 127.0.0.2:$TEST_NGINX_RAND_PORT_1 ssl; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ver, err = ssl.get_tls1_version_str(resp) if not ver then ngx.log(ngx.ERR, "failed to get TLS1 version: ", err) return end ngx.log(ngx.WARN, "got TLS1 version: ", ver) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; ssl_protocols TLSv1; return 'it works!\n'; } --- stream_server_config lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_verify_depth 3; lua_ssl_protocols TLSv1; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("127.0.0.2", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(false, nil, true, false) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) end -- do } --- stream_response connected: 1 ssl handshake: boolean --- error_log got TLS1 version: TLSv1, --- no_error_log [error] [alert] [emerg] === TEST 12: tls version - TLSv1.1 --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen 127.0.0.2:$TEST_NGINX_RAND_PORT_1 ssl; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ver, err = ssl.get_tls1_version_str(resp) if not ver then ngx.log(ngx.ERR, "failed to get TLS1 version: ", err) return end ngx.log(ngx.WARN, "got TLS1 version: ", ver) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; ssl_protocols TLSv1.1; return 'it works!\n'; } --- stream_server_config lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_verify_depth 3; lua_ssl_protocols TLSv1.1; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("127.0.0.2", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(false, nil, true, false) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) end -- do } --- stream_response connected: 1 ssl handshake: boolean --- error_log got TLS1 version: TLSv1.1, --- no_error_log [error] [alert] [emerg] === TEST 13: tls version - TLSv1.2 --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen 127.0.0.2:$TEST_NGINX_RAND_PORT_1 ssl; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ver, err = ssl.get_tls1_version_str(resp) if not ver then ngx.log(ngx.ERR, "failed to get TLS1 version: ", err) return end ngx.log(ngx.WARN, "got TLS1 version: ", ver) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; ssl_protocols TLSv1.2; return 'it works!\n'; } --- stream_server_config lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_verify_depth 3; lua_ssl_protocols TLSv1.2; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("127.0.0.2", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(false, nil, true, false) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) end -- do } --- stream_response connected: 1 ssl handshake: boolean --- error_log got TLS1 version: TLSv1.2, --- no_error_log [error] [alert] [emerg] === TEST 14: ngx.semaphore in ssl_certificate_by_lua* --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen 127.0.0.2:$TEST_NGINX_RAND_PORT_1 ssl; ssl_certificate_by_lua_block { local semaphore = require "ngx.semaphore" local sema = assert(semaphore.new()) local function f() assert(sema:wait(1)) end local t = assert(ngx.thread.spawn(f)) ngx.sleep(0.25) assert(sema:post()) assert(ngx.thread.wait(t)) print("ssl cert by lua done") } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; ssl_protocols TLSv1.2; return 'it works!\n'; } --- stream_server_config lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_verify_depth 3; lua_ssl_protocols TLSv1.2; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("127.0.0.2", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(false, nil, true, false) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) end -- do } --- stream_response connected: 1 ssl handshake: boolean --- grep_error_log eval: qr/stream lua semaphore (?:wait yielding|\w[^:,]*)/ --- grep_error_log_out stream lua semaphore new stream lua semaphore wait stream lua semaphore wait yielding stream lua semaphore post --- error_log ssl cert by lua done --- no_error_log [error] [alert] [emerg] === TEST 15: read PEM key chain but set DER key chain --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" ssl.clear_certs() local f = assert(io.open("t/cert/chain/chain.pem")) local cert_data = f:read("*a") f:close() local cert, err = ssl.cert_pem_to_der(cert_data) if not cert then ngx.log(ngx.ERR, "failed to convert pem cert to der cert: ", err) return end local ok, err = ssl.set_der_cert(cert) if not ok then ngx.log(ngx.ERR, "failed to set DER cert: ", err) return end local f = assert(io.open("t/cert/chain/test-com.key.pem")) local pkey_data = f:read("*a") f:close() pkey_data, err = ssl.priv_key_pem_to_der(pkey_data) if not pkey_data then ngx.log(ngx.ERR, "failed to convert pem key to der key: ", err) return end local ok, err = ssl.set_der_priv_key(pkey_data) if not ok then ngx.log(ngx.ERR, "failed to set private key: ", err) return end } ssl_certificate ../../cert/test2.crt; ssl_certificate_key ../../cert/test2.key; return 'it works!\n'; } --- stream_server_config lua_ssl_trusted_certificate ../../cert/chain/root-ca.crt; lua_ssl_verify_depth 3; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } --- stream_response connected: 1 ssl handshake: userdata received: it works! close: 1 nil --- error_log lua ssl server name: "test.com" --- no_error_log [error] [alert] [emerg] === TEST 16: parse PEM cert and key to cdata --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" ssl.clear_certs() local f = assert(io.open("t/cert/chain/chain.pem")) local cert_data = f:read("*a") f:close() local cert, err = ssl.parse_pem_cert(cert_data) if not cert then ngx.log(ngx.ERR, "failed to parse pem cert: ", err) return end local ok, err = ssl.set_cert(cert) if not ok then ngx.log(ngx.ERR, "failed to set cert: ", err) return end local f = assert(io.open("t/cert/chain/test-com.key.pem")) local pkey_data = f:read("*a") f:close() local pkey, err = ssl.parse_pem_priv_key(pkey_data) if not pkey then ngx.log(ngx.ERR, "failed to parse pem key: ", err) return end local ok, err = ssl.set_priv_key(pkey) if not ok then ngx.log(ngx.ERR, "failed to set private key: ", err) return end } ssl_certificate ../../cert/test2.crt; ssl_certificate_key ../../cert/test2.key; return 'it works!\n'; } --- stream_server_config lua_ssl_trusted_certificate ../../cert/chain/root-ca.crt; lua_ssl_verify_depth 3; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } --- stream_response connected: 1 ssl handshake: userdata received: it works! close: 1 nil --- error_log lua ssl server name: "test.com" --- no_error_log [error] [alert] [emerg] === TEST 17: parse PEM cert and key to cdata (bad cert 0 in the chain) --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" ssl.clear_certs() local f = assert(io.open("t/cert/chain/chain-bad0.pem")) local cert_data = f:read("*a") f:close() local cert, err = ssl.parse_pem_cert(cert_data) if not cert then ngx.log(ngx.ERR, "failed to parse pem cert: ", err) return end local ok, err = ssl.set_cert(cert) if not ok then ngx.log(ngx.ERR, "failed to set cert: ", err) return end local f = assert(io.open("t/cert/chain/test-com.key.pem")) local pkey_data = f:read("*a") f:close() local pkey, err = ssl.parse_pem_priv_key(pkey_data) if not pkey then ngx.log(ngx.ERR, "failed to parse pem key: ", err) return end local ok, err = ssl.set_priv_key(pkey) if not ok then ngx.log(ngx.ERR, "failed to set private key: ", err) return end } ssl_certificate ../../cert/test2.crt; ssl_certificate_key ../../cert/test2.key; return 'it works!\n'; } --- stream_server_config lua_ssl_trusted_certificate ../../cert/chain/root-ca.crt; lua_ssl_verify_depth 3; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } --- stream_response connected: 1 failed to do SSL handshake: handshake failed --- error_log eval qr/\[error\] .*? failed to parse pem cert: PEM_read_bio_X509_AUX\(\) failed/ --- no_error_log [alert] [emerg] [crit] === TEST 18: parse PEM cert and key to cdata (bad cert 2 in the chain) --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" ssl.clear_certs() local f = assert(io.open("t/cert/chain/chain-bad2.pem")) local cert_data = f:read("*a") f:close() local cert, err = ssl.parse_pem_cert(cert_data) if not cert then ngx.log(ngx.ERR, "failed to parse pem cert: ", err) return end local ok, err = ssl.set_cert(cert) if not ok then ngx.log(ngx.ERR, "failed to set cert: ", err) return end local f = assert(io.open("t/cert/chain/test-com.key.pem")) local pkey_data = f:read("*a") f:close() local pkey, err = ssl.parse_pem_priv_key(pkey_data) if not pkey then ngx.log(ngx.ERR, "failed to parse pem key: ", err) return end local ok, err = ssl.set_priv_key(pkey) if not ok then ngx.log(ngx.ERR, "failed to set private key: ", err) return end } ssl_certificate ../../cert/test2.crt; ssl_certificate_key ../../cert/test2.key; return 'it works!\n'; } --- stream_server_config lua_ssl_trusted_certificate ../../cert/chain/root-ca.crt; lua_ssl_verify_depth 3; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } --- stream_response connected: 1 failed to do SSL handshake: handshake failed --- error_log eval qr/\[error\] .*? failed to parse pem cert: PEM_read_bio_X509\(\) failed/ --- no_error_log [alert] [emerg] [crit] === TEST 19: parse PEM cert and key to cdata (bad priv key) --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" ssl.clear_certs() local f = assert(io.open("t/cert/chain/chain.pem")) local cert_data = f:read("*a") f:close() local cert, err = ssl.parse_pem_cert(cert_data) if not cert then ngx.log(ngx.ERR, "failed to parse pem cert: ", err) return end local ok, err = ssl.set_cert(cert) if not ok then ngx.log(ngx.ERR, "failed to set cert: ", err) return end local f = assert(io.open("t/cert/chain/test-com-bad.key.pem")) local pkey_data = f:read("*a") f:close() local pkey, err = ssl.parse_pem_priv_key(pkey_data) if not pkey then ngx.log(ngx.ERR, "failed to parse pem key: ", err) return end local ok, err = ssl.set_priv_key(pkey) if not ok then ngx.log(ngx.ERR, "failed to set private key: ", err) return end } ssl_certificate ../../cert/test2.crt; ssl_certificate_key ../../cert/test2.key; return 'it works!\n'; } --- stream_server_config lua_ssl_trusted_certificate ../../cert/chain/root-ca.crt; lua_ssl_verify_depth 3; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } --- stream_response connected: 1 failed to do SSL handshake: handshake failed --- error_log eval qr/\[error\] .*? failed to parse pem key: PEM_read_bio_PrivateKey\(\) failed/ --- no_error_log [alert] [emerg] [crit] === TEST 20: read client addr via ssl.raw_client_addr() --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen 127.0.0.1:$TEST_NGINX_RAND_PORT_1 ssl; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local byte = string.byte local addr, addrtype, err = ssl.raw_client_addr() local ip = string.format("%d.%d.%d.%d", byte(addr, 1), byte(addr, 2), byte(addr, 3), byte(addr, 4)) print("client ip: ", ip) } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; return 'it works!\n'; } --- stream_server_config lua_ssl_trusted_certificate ../../cert/test.crt; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, nil, true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } --- stream_response connected: 1 ssl handshake: userdata received: it works! close: 1 nil --- error_log client ip: 127.0.0.1 --- no_error_log [error] [alert] [emerg] === TEST 21: yield during doing handshake with client which uses low version OpenSSL --- no_check_leak --- stream_config lua_shared_dict done 16k; lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH/?.lua;;"; server { listen $TEST_NGINX_RAND_PORT_1 ssl; ssl_session_tickets off; ssl_certificate ../../cert/test2.crt; ssl_certificate_key ../../cert/test2.key; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" ssl.clear_certs() local f = assert(io.open("t/cert/test.crt.der")) local cert_data = f:read("*a") f:close() ngx.sleep(0.01) -- yield local ok, err = ssl.set_der_cert(cert_data) if not ok then ngx.log(ngx.ERR, "failed to set DER cert: ", err) return end local f = assert(io.open("t/cert/test.key.der")) local pkey_data = f:read("*a") f:close() local ok, err = ssl.set_der_priv_key(pkey_data) if not ok then ngx.log(ngx.ERR, "failed to set DER cert: ", err) return end } content_by_lua_block { ngx.shared.done:set("handshake", true) } } --- stream_server_config lua_ssl_trusted_certificate ../../cert/test.crt; content_by_lua_block { ngx.shared.done:delete("handshake") local addr = ngx.var.addr; local req = "'GET / HTTP/1.0\r\nHost: test.com\r\nConnection: close\r\n\r\n'" local f, err = io.popen("echo -n " .. req .. " | timeout 3s openssl s_client -connect 127.0.0.1:$TEST_NGINX_RAND_PORT_1") if not f then ngx.say(err) return end local step = 0.001 while step < 2 do ngx.sleep(step) step = step * 2 if ngx.shared.done:get("handshake") then local out = f:read('*a') ngx.log(ngx.INFO, out) ngx.say("ok") f:close() return end end ngx.log(ngx.ERR, "openssl client handshake timeout") } --- stream_response ok --- error_log eval [ qr/content_by_lua\(nginx\.conf:\d+\):\d+: CONNECTED/, qr/subject=\/?C(?\s?=\s?)US(?\/|,\s)ST\kCalifornia\kL\kSan Francisco\kO\kOpenResty\kOU\kOpenResty\kCN\ktest\.com\kemailAddress\kagentzh\@gmail\.com/, ] --- no_error_log [error] [alert] --- timeout: 5 === TEST 22: tls version - TLSv1.3 --- skip_openssl: 6: < 1.1.1 --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; ssl_protocols TLSv1.3; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ver, err = ssl.get_tls1_version_str(resp) if not ver then ngx.log(ngx.ERR, "failed to get TLS1 version: ", err) return end ngx.log(ngx.WARN, "got TLS1 version: ", ver) } return 'it works!\n'; } --- stream_server_config lua_ssl_trusted_certificate ../../cert/test.crt; lua_ssl_verify_depth 3; lua_ssl_protocols TLSv1.3; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(false, nil, true, false) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) end -- do } --- stream_response connected: 1 ssl handshake: boolean --- error_log got TLS1 version: TLSv1.3, --- no_error_log [error] [alert] [emerg] === TEST 23: verify client with CA certificates --- stream_config server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; ssl_certificate ../../cert/test2.crt; ssl_certificate_key ../../cert/test2.key; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local f = assert(io.open("t/cert/test.crt", "rb")) local cert_data = f:read("*all") f:close() local cert = ssl.parse_pem_cert(cert_data) if not cert then ngx.log(ngx.ERR, "failed to parse pem cert: ", err) return end local ok, err = ssl.verify_client(cert, 1) if not ok then ngx.log(ngx.ERR, "failed to verify client: ", err) return end } content_by_lua_block { print('client certificate subject: ', ngx.var.ssl_client_s_dn) ngx.say(ngx.var.ssl_client_verify) } } --- stream_server_config proxy_pass unix:$TEST_NGINX_HTML_DIR/nginx.sock; proxy_ssl on; proxy_ssl_certificate ../../cert/test.crt; proxy_ssl_certificate_key ../../cert/test.key; proxy_ssl_session_reuse off; --- stream_response SUCCESS --- error_log client certificate subject: emailAddress=agentzh@gmail.com,CN=test.com --- no_error_log [error] [alert] [emerg] === TEST 24: verify client without CA certificates --- stream_config server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; ssl_certificate ../../cert/test2.crt; ssl_certificate_key ../../cert/test2.key; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local ok, err = ssl.verify_client() if not ok then ngx.log(ngx.ERR, "failed to verify client: ", err) return end } content_by_lua_block { print('client certificate subject: ', ngx.var.ssl_client_s_dn) ngx.say(ngx.var.ssl_client_verify) } } --- stream_server_config proxy_pass unix:$TEST_NGINX_HTML_DIR/nginx.sock; proxy_ssl on; proxy_ssl_certificate ../../cert/test.crt; proxy_ssl_certificate_key ../../cert/test.key; proxy_ssl_session_reuse off; --- stream_response FAILED:self signed certificate --- error_log client certificate subject: emailAddress=agentzh@gmail.com,CN=test.com --- no_error_log [error] [alert] [emerg] === TEST 25: verify client but client provides no certificate --- stream_config server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; ssl_certificate ../../cert/test2.crt; ssl_certificate_key ../../cert/test2.key; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local f = assert(io.open("t/cert/test.crt", "rb")) local cert_data = f:read("*all") f:close() local cert = ssl.parse_pem_cert(cert_data) if not cert then ngx.log(ngx.ERR, "failed to parse pem cert: ", err) return end local ok, err = ssl.verify_client(cert, 1) if not ok then ngx.log(ngx.ERR, "failed to verify client: ", err) return end } content_by_lua_block { print('client certificate subject: ', ngx.var.ssl_client_s_dn) ngx.say(ngx.var.ssl_client_verify) } } --- stream_server_config proxy_pass unix:$TEST_NGINX_HTML_DIR/nginx.sock; proxy_ssl on; proxy_ssl_session_reuse off; --- stream_response NONE --- error_log client certificate subject: nil --- no_error_log [error] [alert] [emerg] === TEST 26: private key protected by passphrase --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" ssl.clear_certs() local f = assert(io.open("t/cert/test_passphrase.crt")) local cert_data = f:read("*a") f:close() local cert, err = ssl.cert_pem_to_der(cert_data) if not cert then ngx.log(ngx.ERR, "failed to convert pem cert to der cert: ", err) return end local ok, err = ssl.set_der_cert(cert) if not ok then ngx.log(ngx.ERR, "failed to set DER cert: ", err) return end local f = assert(io.open("t/cert/test_passphrase.key")) local pkey_data = f:read("*a") f:close() pkey_data, err = ssl.priv_key_pem_to_der(pkey_data, "123456") if not pkey_data then ngx.log(ngx.ERR, "failed to convert pem key to der key: ", err) return end local ok, err = ssl.set_der_priv_key(pkey_data) if not ok then ngx.log(ngx.ERR, "failed to set DER private key: ", err) return end } ssl_certificate ../../cert/test2.crt; ssl_certificate_key ../../cert/test2.key; return 'it works!\n'; } --- stream_server_config lua_ssl_trusted_certificate ../../cert/chain/root-ca.crt; lua_ssl_verify_depth 3; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com") if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } --- stream_response connected: 1 ssl handshake: userdata received: it works! close: 1 nil --- error_log lua ssl server name: "test.com" --- no_error_log [error] [alert] [emerg] === TEST 27: parse DER cert and key to cdata --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" ssl.clear_certs() local f = assert(io.open("t/cert/chain/chain.der")) local cert_data = f:read("*a") f:close() local cert, err = ssl.parse_der_cert(cert_data) if not cert then ngx.log(ngx.ERR, "failed to parse DER cert: ", err) return end local ok, err = ssl.set_cert(cert) if not ok then ngx.log(ngx.ERR, "failed to set cert: ", err) return end local f = assert(io.open("t/cert/chain/test-com.key.der")) local pkey_data = f:read("*a") f:close() local pkey, err = ssl.parse_der_priv_key(pkey_data) if not pkey then ngx.log(ngx.ERR, "failed to parse DER key: ", err) return end local ok, err = ssl.set_priv_key(pkey) if not ok then ngx.log(ngx.ERR, "failed to set private key: ", err) return end } ssl_certificate ../../cert/test2.crt; ssl_certificate_key ../../cert/test2.key; return 'it works!\n'; } --- stream_server_config lua_ssl_trusted_certificate ../../cert/chain/root-ca.crt; lua_ssl_verify_depth 3; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, "test.com", true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } --- stream_response connected: 1 ssl handshake: userdata received: it works! close: 1 nil --- error_log lua ssl server name: "test.com" --- no_error_log [error] [alert] [emerg] === TEST 28: read client random via ssl.get_client_random() --- stream_config lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH"; server { listen 127.0.0.1:$TEST_NGINX_RAND_PORT_1 ssl; ssl_certificate_by_lua_block { local ssl = require "ngx.ssl" local client_random_len = ssl.get_client_random(0) print("client-random length: ", client_random_len) local init_v = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" local client_random = ssl.get_client_random() if client_random == init_v then print("maybe the client random value is incorrect") end } ssl_certificate ../../cert/test.crt; ssl_certificate_key ../../cert/test.key; return 'it works!\n'; } --- stream_server_config lua_ssl_trusted_certificate ../../cert/test.crt; content_by_lua_block { do local sock = ngx.socket.tcp() sock:settimeout(3000) local ok, err = sock:connect("127.0.0.1", $TEST_NGINX_RAND_PORT_1) if not ok then ngx.say("failed to connect: ", err) return end ngx.say("connected: ", ok) local sess, err = sock:sslhandshake(nil, nil, true) if not sess then ngx.say("failed to do SSL handshake: ", err) return end ngx.say("ssl handshake: ", type(sess)) while true do local line, err = sock:receive() if not line then -- ngx.say("failed to receive response status line: ", err) break end ngx.say("received: ", line) end local ok, err = sock:close() ngx.say("close: ", ok, " ", err) end -- do -- collectgarbage() } --- stream_response connected: 1 ssl handshake: userdata received: it works! close: 1 nil --- error_log client-random length: 32 --- no_error_log [error] [alert] [emerg] lua-resty-core-0.1.31/t/stream/time.t000066400000000000000000000102751474236722600173520ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore::Stream; repeat_each(2); plan tests => repeat_each() * (blocks() * 6); no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: ngx.now() --- stream_server_config content_by_lua_block { local t for i = 1, 500 do t = ngx.now() end ngx.sleep(0.10) local elapsed = ngx.now() - t ngx.say(t > 1399867351) ngx.say(">= 0.099: ", elapsed >= 0.099) ngx.say("< 0.11: ", elapsed < 0.11) -- ngx.say(t, " ", elapsed) } --- stream_response true >= 0.099: true < 0.11: true --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] bad argument type stitch === TEST 2: ngx.time() --- stream_server_config content_by_lua_block { local t for i = 1, 500 do t = ngx.time() end ngx.say(t > 1400960598) local diff = os.time() - t ngx.say("<= 1: ", diff <= 1) } --- stream_response true <= 1: true --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] bad argument type stitch === TEST 3: ngx.update_time() --- stream_server_config content_by_lua_block { local start = ngx.now() for _ = 1, 1e5 do ngx.update_time() end ngx.say(ngx.now() - start > 0) } --- stream_response true --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] bad argument type stitch === TEST 4: ngx.today() --- stream_server_config content_by_lua_block { local t for i = 1, 500 do t = ngx.today() end ngx.say(t) } --- stream_response_like: ^\d{4}-\d{2}-\d{2} --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] bad argument type stitch === TEST 5: ngx.localtime() --- stream_server_config content_by_lua_block { local t for i = 1, 500 do t = ngx.localtime() end ngx.say(t) } --- stream_response_like: ^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$ --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] bad argument type stitch === TEST 6: ngx.utctime() --- stream_server_config content_by_lua_block { local t for i = 1, 500 do t = ngx.utctime() end ngx.say(t) } --- stream_response_like: ^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$ --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] bad argument type stitch === TEST 7: "resty.core.time".monotonic_msec --- stream_server_config content_by_lua_block { local cur_msec = require "resty.core.time".monotonic_msec local proc = io.open("/proc/uptime", "r") local content = proc:read() proc:close() local idx = string.find(content, " ", 1, true) local uptime = 1000 * tonumber(string.sub(content, 1, idx - 1)) ngx.update_time() local t for i = 1, 500 do t = cur_msec() end ngx.say(t >= uptime) local diff = t - uptime ngx.say("< 10: ", diff < 10) } --- stream_response true < 10: true --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):11 loop\]/ --- no_error_log [error] bad argument type stitch === TEST 8: "resty.core.time".monotonic_time --- stream_server_config content_by_lua_block { local cur_time = require "resty.core.time".monotonic_time local proc = io.open("/proc/uptime", "r") local content = proc:read() proc:close() local idx = string.find(content, " ", 1, true) local uptime = tonumber(string.sub(content, 1, idx - 1)) ngx.update_time() local t for i = 1, 500 do t = cur_time() end ngx.say(t >= uptime) local diff = t - uptime ngx.say("< 0.1: ", diff < 0.1) } --- stream_response true < 0.1: true --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):11 loop\]/ --- no_error_log [error] bad argument type stitch lua-resty-core-0.1.31/t/time.t000066400000000000000000000173311474236722600160570ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(1014); #master_process_enabled(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 6); #no_diff(); no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: ngx.now() --- config location = /t { access_log off; content_by_lua_block { local t for i = 1, 30 do t = ngx.now() end ngx.sleep(0.10) local elapsed = ngx.now() - t ngx.say(t > 1399867351) ngx.say(">= 0.099: ", elapsed >= 0.099) ngx.say("< 0.11: ", elapsed < 0.11) -- ngx.say(t, " ", elapsed) } } --- request GET /t --- response_body true >= 0.099: true < 0.11: true --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] bad argument type stitch === TEST 2: ngx.time() --- config location = /t { access_log off; content_by_lua_block { local t for i = 1, 30 do t = ngx.time() end ngx.say(t > 1400960598) local diff = os.time() - t ngx.say("<= 1: ", diff <= 1) } } --- request GET /t --- response_body true <= 1: true --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] bad argument type stitch === TEST 3: ngx.update_time() --- config location = /t { content_by_lua_block { local start = ngx.now() for _ = 1, 1e5 do ngx.update_time() end ngx.say(ngx.now() - start > 0) } } --- request GET /t --- response_body true --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] bad argument type stitch === TEST 4: ngx.today() --- config location = /t { content_by_lua_block { local t for i = 1, 30 do t = ngx.today() end ngx.say(t) } } --- request GET /t --- response_body_like: ^\d{4}-\d{2}-\d{2} --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] bad argument type stitch === TEST 5: ngx.localtime() --- config location = /t { content_by_lua_block { local t for i = 1, 30 do t = ngx.localtime() end ngx.say(t) } } --- request GET /t --- response_body_like: ^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$ --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] bad argument type stitch === TEST 6: ngx.utctime() --- config location = /t { content_by_lua_block { local t for i = 1, 30 do t = ngx.utctime() end ngx.say(t) } } --- request GET /t --- response_body_like: ^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$ --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] bad argument type stitch === TEST 7: ngx.cookie_time() --- config location /t { content_by_lua_block { local t for i = 1, 30 do t = ngx.cookie_time(1290079655) end ngx.say(t) ngx.say(ngx.cookie_time(2200000000)) } } --- request GET /t --- response_body Thu, 18-Nov-10 11:27:35 GMT Sun, 18-Sep-2039 23:06:40 GMT --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] bad argument type stitch === TEST 8: ngx.cookie_time() bad argument --- config location /t { content_by_lua_block { local pok, err = pcall(ngx.cookie_time, "foo") if not pok then ngx.say("not ok: ", err) return end ngx.say("ok") } } --- request GET /t --- response_body not ok: number argument only --- no_error_log [error] [alert] bad argument type stitch === TEST 9: ngx.http_time() --- config location /t { content_by_lua_block { local t for i = 1, 30 do t = ngx.http_time(1290079655) end ngx.say(t) } } --- request GET /t --- response_body Thu, 18 Nov 2010 11:27:35 GMT --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] bad argument type stitch === TEST 10: ngx.http_time() bad argument --- config location /t { content_by_lua_block { t = ngx.http_time(1290079655) local pok, err = pcall(ngx.http_time, "foo") if not pok then ngx.say("not ok: ", err) return end ngx.say("ok") } } --- request GET /t --- response_body not ok: number argument only --- no_error_log [error] [alert] bad argument type stitch === TEST 11: ngx.parse_http_time() --- config location /t { content_by_lua_block { local t for i = 1, 30 do t = ngx.parse_http_time("Thu, 18 Nov 2010 11:27:35 GMT") end ngx.say(t) ngx.say(ngx.parse_http_time("Thu, Nov 2010")) } } --- request GET /t --- response_body 1290079655 nil --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] bad argument type stitch === TEST 12: ngx.parse_http_time() bad argument --- config location /t { content_by_lua_block { t = ngx.http_time(1290079655) local pok, err = pcall(ngx.parse_http_time, 123) if not pok then ngx.say("not ok: ", err) return end ngx.say("ok") } } --- request GET /t --- response_body not ok: string argument only --- no_error_log [error] [alert] bad argument type stitch === TEST 13: "resty.core.time".monotonic_msec --- config location = /t { access_log off; content_by_lua_block { local cur_msec = require "resty.core.time".monotonic_msec local proc = io.open("/proc/uptime", "r") local content = proc:read() proc:close() local idx = string.find(content, " ", 1, true) local uptime = 1000 * tonumber(string.sub(content, 1, idx - 1)) ngx.update_time() local t for i = 1, 30 do t = cur_msec() end ngx.say(t >= uptime) local diff = t - uptime ngx.say("< 10: ", diff < 10) } } --- request GET /t --- response_body true < 10: true --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):11 loop\]/ --- no_error_log [error] bad argument type stitch === TEST 14: "resty.core.time".monotonic_time --- config location = /t { access_log off; content_by_lua_block { local cur_time = require "resty.core.time".monotonic_time local proc = io.open("/proc/uptime", "r") local content = proc:read() proc:close() local idx = string.find(content, " ", 1, true) local uptime = tonumber(string.sub(content, 1, idx - 1)) ngx.update_time() local t for i = 1, 30 do t = cur_time() end ngx.say(t >= uptime) local diff = t - uptime ngx.say("< 0.01: ", diff < 0.01) } } --- request GET /t --- response_body true < 0.01: true --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):11 loop\]/ --- no_error_log [error] bad argument type stitch lua-resty-core-0.1.31/t/uri.t000066400000000000000000000106531474236722600157200ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(1014); #master_process_enabled(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 4); #no_diff(); #no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: unescape_uri (string) --- config location = /uri { content_by_lua_block { local s for i = 1, 30 do s = ngx.unescape_uri("hello%20world") end ngx.say(s) } } --- request GET /uri --- response_body hello world --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] === TEST 2: unescape_uri (nil) --- config location = /uri { content_by_lua_block { local s for i = 1, 30 do s = ngx.unescape_uri(nil) end ngx.say(s) } } --- request GET /uri --- response_body eval: "\n" --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] === TEST 3: unescape_uri (number) --- config location = /uri { content_by_lua_block { local s for i = 1, 30 do s = ngx.unescape_uri(3.14) end ngx.say(s) } } --- request GET /uri --- response_body 3.14 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] === TEST 4: escape_uri (string, escaped) --- config location = /uri { content_by_lua_block { local s for i = 1, 30 do s = ngx.escape_uri("hello world") end ngx.say(s) } } --- request GET /uri --- response_body hello%20world --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] === TEST 5: escape_uri (string, no escaped) --- config location = /uri { content_by_lua_block { local s for i = 1, 30 do s = ngx.escape_uri("helloworld") end ngx.say(s) } } --- request GET /uri --- response_body helloworld --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] === TEST 6: escape_uri (nil) --- config location = /uri { content_by_lua_block { local s for i = 1, 30 do s = ngx.escape_uri(nil) end ngx.say(s) } } --- request GET /uri --- response_body eval: "\n" --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] === TEST 7: escape_uri (number) --- config location = /uri { content_by_lua_block { local s for i = 1, 30 do s = ngx.escape_uri(3.14) end ngx.say(s) } } --- request GET /uri --- response_body 3.14 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] === TEST 8: escape_uri (larger than 4k, nothing to be escaped) --- config location = /uri { content_by_lua_block { local s for i = 1, 30 do s = ngx.escape_uri(string.rep("a", 4097)) end ngx.say(s) } } --- request GET /uri --- response_body eval: "a" x 4097 . "\n" --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] === TEST 9: escape_uri (a little smaller than 4k, need to be escaped) --- config location = /uri { content_by_lua_block { local s for i = 1, 30 do s = ngx.escape_uri(string.rep(" ", 1365)) end ngx.say(s) } } --- request GET /uri --- response_body eval: "%20" x 1365 . "\n" --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] === TEST 10: escape_uri (a little bigger than 4k, need to be escaped) --- config location = /uri { content_by_lua_block { local s for i = 1, 30 do s = ngx.escape_uri(string.rep(" ", 1366)) end ngx.say(s) } } --- request GET /uri --- response_body eval: "%20" x 1366 . "\n" --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] lua-resty-core-0.1.31/t/utils.t000066400000000000000000000050151474236722600162550ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; plan tests => repeat_each() * blocks() * 3; add_block_preprocessor(sub { my $block = shift; if (!defined $block->error_log) { $block->set_value("no_error_log", "[error]"); } if (!defined $block->request) { $block->set_value("request", "GET /t"); } }); no_diff(); no_long_string(); run_tests(); __DATA__ === TEST 1: utils.str_replace_char() sanity (replaces a single character) --- config location /t { content_by_lua_block { local utils = require "resty.core.utils" local strings = { "Header_Name", "_Header_Name_", "Header__Name", "Header-Name", "Hello world", } for i = 1, #strings do ngx.say(utils.str_replace_char(strings[i], "_", "-")) end } } --- response_body Header-Name -Header-Name- Header--Name Header-Name Hello world === TEST 2: utils.str_replace_char() JIT compiles when match --- config location /t { content_by_lua_block { local utils = require "resty.core.utils" for i = 1, $TEST_NGINX_HOTLOOP * 10 do utils.str_replace_char("Header_Name", "_", "-") end } } --- ignore_response_body --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/, --- no_error_log [error] === TEST 3: utils.str_replace_char() JIT compiles when no match --- config location /t { content_by_lua_block { local utils = require "resty.core.utils" for i = 1, $TEST_NGINX_HOTLOOP * 10 do utils.str_replace_char("Header_Name", "-", "_") end } } --- ignore_response_body --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/, --- no_error_log [error] === TEST 4: utils.str_replace_char() replacing more than one character is not supported --- config location /t { content_by_lua_block { local utils = require "resty.core.utils" local strings = { "Header01Name", "01Header01Name01", "Header0Name", "Header1Name", "Hello world", } for i = 1, #strings do ngx.say(utils.str_replace_char(strings[i], "02", "02")) end } } --- response_body Header01Name 01Header01Name01 Header0Name Header1Name Hello world lua-resty-core-0.1.31/t/var.t000066400000000000000000000105331474236722600157060ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(1014); #master_process_enabled(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 5); #no_diff(); #no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: get normal var --- config location = /t { set $foo hello; content_by_lua_block { local ffi = require "ffi" local val for i = 1, 30 do val = ngx.var.foo end ngx.say("value: ", val) } } --- request GET /t --- response_body value: hello --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] -- NYI: (?!return to lower frame) === TEST 2: get normal var (case) --- config location = /t { set $foo hello; content_by_lua_block { local ffi = require "ffi" local val for i = 1, 30 do val = ngx.var.FOO end ngx.say("value: ", val) } } --- request GET /t --- response_body value: hello --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] -- NYI: (?!return to lower frame) === TEST 3: get capturing var (bad) --- config location = /t { set $foo hello; content_by_lua_block { local ffi = require "ffi" local val for i = 1, 30 do val = ngx.var[0] end ngx.say("value: ", val) } } --- request GET /t --- response_body value: nil --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] -- NYI: === TEST 4: get capturing var --- config location ~ '^(/t)' { set $foo hello; content_by_lua_block { local ffi = require "ffi" local val for i = 1, 30 do val = ngx.var[1] end ngx.say("value: ", val) } } --- request GET /t --- response_body value: /t --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] -- NYI: (?!return to lower frame) === TEST 5: set normal var (string value) --- config location = /t { set $foo hello; content_by_lua_block { local ffi = require "ffi" local val = "hello" for i = 1, 30 do ngx.var.foo = val end ngx.say("value: ", val) } } --- request GET /t --- response_body value: hello --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] -- NYI: === TEST 6: set normal var (nil value) --- config location = /t { set $foo hello; content_by_lua_block { local ffi = require "ffi" for i = 1, 30 do ngx.var.foo = nil end ngx.say("value: ", ngx.var.foo) } } --- request GET /t --- response_body value: nil --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] -- NYI: === TEST 7: set normal var (number value) --- config location = /t { set $foo hello; content_by_lua_block { local ffi = require "ffi" for i = 1, 30 do ngx.var.foo = i end ngx.say("value: ", ngx.var.foo) } } --- request GET /t --- response_body value: 30 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):3 loop\]/ --- no_error_log [error] -- NYI: === TEST 8: error buffer overread --- config location = /test { content_by_lua_block { local ok1, err1 = pcall(function () ngx.var.foo = 32; end) local ok2, err2 = pcall(function () ngx.var.server_port = 32; end) assert(not ok1) ngx.say(err1) assert(not ok2) ngx.say(err2) } } --- request GET /test --- response_body_like content_by_lua\(nginx\.conf:\d+\):\d+: variable "foo" not found for writing; maybe it is a built-in variable that is not changeable or you forgot to use "set \$foo '';" in the config file to define it first content_by_lua\(nginx\.conf:\d+\):\d+: variable "server_port" not changeable --- no_error_log [error] [alert] -- NYI: lua-resty-core-0.1.31/t/worker-count-5.t000066400000000000000000000013741474236722600177220ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; workers(5); #worker_connections(1014); #master_process_enabled(1); master_on(); #log_level('warn'); repeat_each(3); plan tests => repeat_each() * (blocks() * 6); #no_diff(); #no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: ngx.worker.count --- config location = /t { content_by_lua_block { local v local count = ngx.worker.count for i = 1, 30 do v = count() end ngx.say("workers: ", v) } } --- request GET /t --- response_body workers: 5 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] -- NYI: stitch lua-resty-core-0.1.31/t/worker.t000066400000000000000000000055011474236722600164260ustar00rootroot00000000000000# vim:set ft= ts=4 sw=4 et fdm=marker: use lib '.'; use t::TestCore; #worker_connections(1014); #master_process_enabled(1); #log_level('warn'); repeat_each(2); plan tests => repeat_each() * (blocks() * 6 - 3); #no_diff(); #no_long_string(); check_accum_error_log(); run_tests(); __DATA__ === TEST 1: ngx.worker.exiting --- config location = /t { content_by_lua_block { local v local exiting = ngx.worker.exiting for i = 1, 30 do v = exiting() end ngx.say(v) } } --- request GET /t --- response_body false --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] -- NYI: stitch === TEST 2: ngx.worker.pid --- config location = /t { content_by_lua_block { local v local pid = ngx.worker.pid for i = 1, 30 do v = pid() end ngx.say(v == tonumber(ngx.var.pid)) ngx.say(v) } } --- request GET /t --- response_body_like chop ^true \d+$ --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] -- NYI: stitch === TEST 3: ngx.worker.id --- config location = /t { content_by_lua_block { local v local id = ngx.worker.id for i = 1, 30 do v = id() end ngx.say("worker id: ", v) } } --- request GET /t --- response_body_like chop ^worker id: [0-1]$ --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] -- NYI: stitch --- skip_nginx: 3: <=1.9.0 === TEST 4: ngx.worker.count --- config location = /t { content_by_lua_block { local v local count = ngx.worker.count for i = 1, 30 do v = count() end ngx.say("workers: ", v) } } --- request GET /t --- response_body workers: 1 --- error_log eval qr/\[TRACE\s+\d+ content_by_lua\(nginx\.conf:\d+\):4 loop\]/ --- no_error_log [error] -- NYI: stitch === TEST 5: ngx.worker.pids --- config location /lua { content_by_lua_block { local pids = ngx.worker.pids() local pid = ngx.worker.pid() ngx.say("worker pid: ", pid) local count = ngx.worker.count() if count ~= #pids then ngx.say("worker pids is wrong.") end for i = 1, count do if pids[i] == pid then ngx.say("worker pid is correct.") return end end ngx.say("worker pid is wrong.") } } --- request GET /lua --- response_body_like worker pid: \d+ worker pid is correct\. --- no_error_log [error] lua-resty-core-0.1.31/util/000077500000000000000000000000001474236722600154415ustar00rootroot00000000000000lua-resty-core-0.1.31/util/ver-ge000077500000000000000000000010551474236722600165550ustar00rootroot00000000000000#!/usr/bin/env perl use strict; use warnings; sub usage { die "Usage: $0 \n"; } my $a = shift or usage(); my $b = shift or usage(); my @as = split /\./, $a; my @bs = split /\./, $b; my $n = @as > @bs ? scalar(@as) : scalar(@bs); for (my $i = 0; $i < $n; $i++) { my $x = $as[$i]; my $y = $bs[$i]; if (!defined $x) { $x = 0; } if (!defined $y) { $y = 0; } if ($x > $y) { print "Y\n"; exit; } elsif ($x < $y) { print "N\n"; exit; } } print "Y\n"; lua-resty-core-0.1.31/valgrind.suppress000066400000000000000000000076121474236722600201060ustar00rootroot00000000000000{ Memcheck:Leak fun:malloc fun:ngx_alloc fun:ngx_event_process_init } { Memcheck:Param epoll_ctl(event) fun:epoll_ctl fun:ngx_epoll_add_event } { Memcheck:Cond fun:index fun:expand_dynamic_string_token fun:_dl_map_object fun:map_doit fun:_dl_catch_error fun:do_preload fun:dl_main fun:_dl_sysdep_start fun:_dl_start } { Memcheck:Param epoll_ctl(event) fun:epoll_ctl fun:ngx_epoll_init fun:ngx_event_process_init } { Memcheck:Param epoll_ctl(event) fun:epoll_ctl fun:ngx_epoll_notify_init fun:ngx_epoll_init fun:ngx_event_process_init } { Memcheck:Param epoll_ctl(event) fun:epoll_ctl fun:ngx_epoll_add_connection fun:ngx_event_connect_peer } { Memcheck:Param epoll_ctl(event) fun:epoll_ctl fun:ngx_epoll_test_rdhup } { Memcheck:Param epoll_pwait(sigmask) fun:epoll_pwait } { Memcheck:Cond obj:* } { Memcheck:Leak match-leak-kinds: definite fun:malloc fun:ngx_alloc fun:ngx_set_environment fun:ngx_single_process_cycle } { Memcheck:Leak match-leak-kinds: definite fun:malloc fun:ngx_alloc fun:ngx_set_environment fun:ngx_worker_process_init } { Memcheck:Param sendmsg(msg.msg_iov[0]) fun:__sendmsg_nocancel fun:ngx_write_channel fun:ngx_pass_open_channel fun:ngx_start_worker_processes } { Memcheck:Param sendmsg(msg.msg_iov[0]) fun:__sendmsg_nocancel fun:ngx_write_channel fun:ngx_pass_open_channel fun:ngx_start_cache_manager_processes } { Memcheck:Param sendmsg(msg.msg_iov[0]) fun:__sendmsg_nocancel fun:ngx_write_channel fun:ngx_pass_open_channel fun:ngx_start_privileged_agent_processes } { Memcheck:Leak match-leak-kinds: definite fun:malloc ... fun:ssl_session_dup fun:tls_process_new_session_ticket ... fun:read_state_machine ... fun:ssl3_read_bytes ... fun:SSL_read fun:ngx_ssl_recv fun:ngx_http_upstream_process_header fun:ngx_http_upstream_handler ... fun:ngx_process_events_and_timers ... fun:main } { Memcheck:Leak match-leak-kinds: definite fun:malloc fun:CRYPTO_malloc fun:ssl_session_dup fun:tls_process_new_session_ticket ... fun:read_state_machine ... fun:ssl3_read_bytes ... fun:SSL_read fun:ngx_ssl_recv fun:ngx_http_upstream_process_header fun:ngx_http_upstream_handler ... fun:ngx_process_events_and_timers ... fun:main } { Memcheck:Leak match-leak-kinds: definite fun:malloc fun:CRYPTO_zalloc fun:SSL_SESSION_new fun:ssl_get_new_session fun:tls_construct_client_hello fun:write_state_machine ... fun:ngx_ssl_handshake fun:ngx_http_upstream_ssl_init_connection fun:ngx_http_upstream_send_request_handler fun:ngx_http_upstream_handler ... fun:ngx_process_events_and_timers ... fun:main } { Memcheck:Leak match-leak-kinds: definite fun:malloc fun:CRYPTO_malloc fun:CRYPTO_zalloc fun:SSL_SESSION_new fun:ssl_get_new_session fun:tls_construct_client_hello fun:write_state_machine ... fun:ngx_ssl_handshake fun:ngx_http_upstream_ssl_init_connection fun:ngx_http_upstream_send_request_handler fun:ngx_http_upstream_handler ... fun:ngx_process_events_and_timers ... fun:main }