Squashed 'src/deps/src/lua-nginx-module/' content from commit c47084b5d
git-subtree-dir: src/deps/src/lua-nginx-module git-subtree-split: c47084b5d719ce507d2419d8660f39544a9d1fea
This commit is contained in:
commit
36023392a6
|
@ -0,0 +1 @@
|
|||
*.t linguist-language=Text
|
|
@ -0,0 +1,23 @@
|
|||
This place is for bug reports and development discussions only. For general questions and
|
||||
discussions, please join the openresty-en mailing list instead: https://openresty.org/en/community.html
|
||||
|
||||
Ensure you have provided the following details while reporting a problem:
|
||||
|
||||
* The exact version of the related software, including but not limited to the OpenResty version
|
||||
(if any), the NGINX core version, the `ngx_lua` module version,
|
||||
and your operating system version.
|
||||
* A minimal and standalone test case that others can easily run on their side and
|
||||
reproduce the issue you are seeing.
|
||||
* Do not simply say "something is broken" or "something does not work". Always provide
|
||||
as much details as possible. Always describe the symptoms and your expected results.
|
||||
* You can (temporarily) enable the nginx debugging logs to see the internal workings
|
||||
of NGINX in your nginx''s `error.log` file. See http://nginx.org/en/docs/debugging_log.html
|
||||
The same instructions apply equally well to OpenResty.
|
||||
* If you are seeing crashes, please provide the full backtrace for the crash. See
|
||||
https://www.nginx.com/resources/wiki/start/topics/tutorials/debugging/#core-dump
|
||||
for more details.
|
||||
|
||||
Please, do not use Chinese here. This place is considered English only. If you
|
||||
really want to use Chinese, please join and post to the openresty (Chinese)
|
||||
mailing list instead. Please see https://openresty.org/en/community.html Thanks for
|
||||
your cooperation.
|
|
@ -0,0 +1,2 @@
|
|||
I hereby granted the copyright of the changes in this pull request
|
||||
to the authors of this lua-nginx-module project.
|
|
@ -0,0 +1,30 @@
|
|||
name: "Lint PR"
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
- edited
|
||||
- synchronize
|
||||
|
||||
jobs:
|
||||
main:
|
||||
name: Validate PR title
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: amannn/action-semantic-pull-request@v4
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
# Configure which types are allowed.
|
||||
# Default: https://github.com/commitizen/conventional-commit-types
|
||||
types: |
|
||||
bugfix # bug fixes
|
||||
change # backward incompatible changes
|
||||
doc # documentation changes including code comments
|
||||
editor # code editor related configurations
|
||||
feature # implementing a new feature
|
||||
optimize # performance optimizations
|
||||
refactor # code refactoring and other code rearrangement
|
||||
style # coding style changes
|
||||
tests # test suite changes
|
|
@ -0,0 +1,180 @@
|
|||
build/
|
||||
work/
|
||||
tags
|
||||
cscope.*
|
||||
*.mobi
|
||||
genmobi.sh
|
||||
.libs
|
||||
*.swp
|
||||
*.slo
|
||||
*.la
|
||||
*.swo
|
||||
*.lo
|
||||
*~
|
||||
*.o
|
||||
print.txt
|
||||
.rsync
|
||||
*.tar.gz
|
||||
dist
|
||||
build[789]
|
||||
build
|
||||
tags
|
||||
update-readme
|
||||
*.tmp
|
||||
test/Makefile
|
||||
test/blib
|
||||
test.sh
|
||||
t.sh
|
||||
t/t.sh
|
||||
t/servroot*
|
||||
test/t/servroot/
|
||||
releng
|
||||
reset
|
||||
*.t_
|
||||
src/handler.h
|
||||
src/util.c
|
||||
src/module.h
|
||||
src/module.c
|
||||
src/drizzle.c
|
||||
src/processor.h
|
||||
src/handler.c
|
||||
src/util.h
|
||||
src/drizzle.h
|
||||
src/processor.c
|
||||
src/output.c
|
||||
src/output.h
|
||||
libdrizzle
|
||||
ctags
|
||||
src/stream.h
|
||||
nginx
|
||||
keepalive
|
||||
reindex
|
||||
src/keepalive.c
|
||||
src/keepalive.h
|
||||
src/checker.h
|
||||
src/checker.c
|
||||
src/quoting.h
|
||||
src/quoting.c
|
||||
src/module.h
|
||||
src/module.c
|
||||
src/util.h
|
||||
src/util.c
|
||||
src/processor.h
|
||||
src/processor.c
|
||||
src/rds.h
|
||||
src/utils.h
|
||||
src/handler.c
|
||||
src/handler.h
|
||||
util/bench
|
||||
*.html
|
||||
trace.out*
|
||||
try.sh
|
||||
src/cache.c
|
||||
src/cache.h
|
||||
src/common.h
|
||||
src/directive.c
|
||||
src/directive.h
|
||||
src/consts.[ch]
|
||||
src/contentby.[ch]
|
||||
src/pcrefix.[ch]
|
||||
src/util.c
|
||||
src/clfactory.c
|
||||
src/directive.c
|
||||
src/conf.h
|
||||
src/setby.h
|
||||
src/cache.h
|
||||
src/hook.c
|
||||
src/util.h
|
||||
src/hook.h
|
||||
src/common.h
|
||||
src/directive.h
|
||||
src/conf.c
|
||||
src/setby.c
|
||||
src/cache.c
|
||||
src/module.c
|
||||
src/clfactory.h
|
||||
src/capturefilter.[ch]
|
||||
src/contentby.c
|
||||
pack
|
||||
b.sh
|
||||
src/in.[ch]
|
||||
src/out.[ch]
|
||||
go
|
||||
all.sh
|
||||
src/accessby.[ch]
|
||||
src/rewriteby.[ch]
|
||||
src/patch.[ch]
|
||||
src/ndk.[ch]
|
||||
src/control.[ch]
|
||||
src/output.[ch]
|
||||
src/variable.[ch]
|
||||
src/string.[ch]
|
||||
src/misc.[ch]
|
||||
src/log.[ch]
|
||||
src/exception.[ch]
|
||||
src/subrequest.[ch]
|
||||
src/time.[ch]
|
||||
src/regex.[ch]
|
||||
src/ctx.[ch]
|
||||
src/args.[ch]
|
||||
src/headers.[ch]
|
||||
src/script.[ch]
|
||||
src/filter.[ch]
|
||||
src/shdict.[ch]
|
||||
src/body.[ch]
|
||||
src/uri.[ch]
|
||||
src/api.[ch]
|
||||
src/coroutine.[ch]
|
||||
src/logby.[ch]
|
||||
src/sleep.[ch]
|
||||
a.patch
|
||||
all
|
||||
build1[0-9]
|
||||
g
|
||||
buildroot/
|
||||
src/headerfilterby.[ch]
|
||||
*.patch
|
||||
analyze
|
||||
tsock
|
||||
a.c
|
||||
test.lua
|
||||
build12
|
||||
ERRORS
|
||||
src/bodyfilterby.[ch]
|
||||
src/tcp.[ch]
|
||||
src/initby.[ch]
|
||||
src/initworkerby.[ch]
|
||||
src/socket.[ch]
|
||||
src/udp.[ch]
|
||||
src/method.[ch]
|
||||
tre
|
||||
src/phase.[ch]
|
||||
src/probe.h
|
||||
src/uthread.[ch]
|
||||
src/timer.[ch]
|
||||
src/config.[ch]
|
||||
src/worker.[ch]
|
||||
src/certby.[ch]
|
||||
src/storeby.[ch]
|
||||
src/fetchby.[ch]
|
||||
src/ssl.[ch]
|
||||
src/ocsp.c
|
||||
src/lex.[ch]
|
||||
src/balancer.[ch]
|
||||
src/semaphore.[ch]
|
||||
*.plist
|
||||
lua
|
||||
ttimer
|
||||
Makefile
|
||||
tsubreq
|
||||
tthread
|
||||
addr2line
|
||||
hup
|
||||
theaders
|
||||
src/ngx_http_lua_autoconf.h
|
||||
src/autoconf.h
|
||||
src/filters.c
|
||||
src/filters.h
|
||||
src/ringbuf.c
|
||||
src/ringbuf.h
|
||||
src/pipe.[ch]
|
|
@ -0,0 +1,43 @@
|
|||
---
|
||||
pull_request_rules:
|
||||
- name: warn on conflicts
|
||||
conditions:
|
||||
- conflict
|
||||
actions:
|
||||
comment:
|
||||
message: This pull request is now in conflict :(
|
||||
label:
|
||||
add:
|
||||
- conflict
|
||||
- name: remove conflict label if not needed
|
||||
conditions:
|
||||
- -conflict
|
||||
actions:
|
||||
label:
|
||||
remove:
|
||||
- conflict
|
||||
- name: add label needs-test-cases
|
||||
conditions:
|
||||
- files~=^src/
|
||||
- -files~=^t/
|
||||
actions:
|
||||
label:
|
||||
add:
|
||||
- needs-test-cases
|
||||
- name: remove label needs-test-cases
|
||||
conditions:
|
||||
- label=needs-test-cases
|
||||
- files~=^src/
|
||||
- files~=^t/
|
||||
actions:
|
||||
label:
|
||||
remove:
|
||||
- needs-test-cases
|
||||
- name: add label could-be-merged
|
||||
conditions:
|
||||
- "#approved-reviews-by>=2"
|
||||
- status-success=Travis CI - Pull Request
|
||||
actions:
|
||||
label:
|
||||
add:
|
||||
- could-be-merged
|
|
@ -0,0 +1,146 @@
|
|||
dist: bionic
|
||||
|
||||
branches:
|
||||
only:
|
||||
- "master"
|
||||
|
||||
os: linux
|
||||
|
||||
language: c
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- ack
|
||||
- axel
|
||||
- cpanminus
|
||||
- libtest-base-perl
|
||||
- libtext-diff-perl
|
||||
- liburi-perl
|
||||
- libwww-perl
|
||||
- libtest-longstring-perl
|
||||
- liblist-moreutils-perl
|
||||
- libgd-dev
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- download-cache
|
||||
|
||||
env:
|
||||
global:
|
||||
- JOBS=3
|
||||
- NGX_BUILD_JOBS=$JOBS
|
||||
- LUAJIT_PREFIX=/opt/luajit21
|
||||
- LUAJIT_LIB=$LUAJIT_PREFIX/lib
|
||||
- LUAJIT_INC=$LUAJIT_PREFIX/include/luajit-2.1
|
||||
- LUA_INCLUDE_DIR=$LUAJIT_INC
|
||||
- PCRE_VER=8.45
|
||||
- PCRE_PREFIX=/opt/pcre
|
||||
- PCRE_LIB=$PCRE_PREFIX/lib
|
||||
- PCRE_INC=$PCRE_PREFIX/include
|
||||
- OPENSSL_PREFIX=/opt/ssl
|
||||
- OPENSSL_LIB=$OPENSSL_PREFIX/lib
|
||||
- OPENSSL_INC=$OPENSSL_PREFIX/include
|
||||
- LIBDRIZZLE_PREFIX=/opt/drizzle
|
||||
- LIBDRIZZLE_INC=$LIBDRIZZLE_PREFIX/include/libdrizzle-1.0
|
||||
- LIBDRIZZLE_LIB=$LIBDRIZZLE_PREFIX/lib
|
||||
- LD_LIBRARY_PATH=$LUAJIT_LIB:$LD_LIBRARY_PATH
|
||||
- DRIZZLE_VER=2011.07.21
|
||||
- TEST_NGINX_SLEEP=0.006
|
||||
jobs:
|
||||
- NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.0l OPENSSL_PATCH_VER=1.1.0d
|
||||
- NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.1s OPENSSL_PATCH_VER=1.1.1f
|
||||
|
||||
services:
|
||||
- memcached
|
||||
- redis
|
||||
- mysql
|
||||
|
||||
before_install:
|
||||
- sudo apt update
|
||||
- sudo apt install --only-upgrade ca-certificates
|
||||
- '! grep -n -P ''(?<=.{80}).+'' --color `find src -name ''*.c''` `find . -name ''*.h''` || (echo "ERROR: Found C source lines exceeding 80 columns." > /dev/stderr; exit 1)'
|
||||
- '! grep -n -P ''\t+'' --color `find src -name ''*.c''` `find . -name ''*.h''` || (echo "ERROR: Cannot use tabs." > /dev/stderr; exit 1)'
|
||||
- /usr/bin/env perl $(command -v cpanm) --sudo --notest Test::Nginx IPC::Run > build.log 2>&1 || (cat build.log && exit 1)
|
||||
- pyenv global 2.7
|
||||
install:
|
||||
- if [ ! -f download-cache/drizzle7-$DRIZZLE_VER.tar.gz ]; then wget -P download-cache http://openresty.org/download/drizzle7-$DRIZZLE_VER.tar.gz; fi
|
||||
- if [ ! -f download-cache/pcre-$PCRE_VER.tar.gz ]; then wget -P download-cache https://downloads.sourceforge.net/project/pcre/pcre/${PCRE_VER}/pcre-${PCRE_VER}.tar.gz; 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
|
||||
- git clone https://github.com/openresty/test-nginx.git
|
||||
- git clone https://github.com/openresty/openresty.git ../openresty
|
||||
- git clone https://github.com/openresty/no-pool-nginx.git ../no-pool-nginx
|
||||
- git clone https://github.com/openresty/openresty-devel-utils.git
|
||||
- git clone https://github.com/openresty/mockeagain.git
|
||||
- git clone https://github.com/openresty/lua-cjson.git lua-cjson
|
||||
- git clone https://github.com/openresty/lua-upstream-nginx-module.git ../lua-upstream-nginx-module
|
||||
- git clone https://github.com/openresty/echo-nginx-module.git ../echo-nginx-module
|
||||
- git clone https://github.com/openresty/nginx-eval-module.git ../nginx-eval-module
|
||||
- git clone https://github.com/simpl/ngx_devel_kit.git ../ndk-nginx-module
|
||||
- git clone https://github.com/FRiCKLE/ngx_coolkit.git ../coolkit-nginx-module
|
||||
- git clone https://github.com/openresty/headers-more-nginx-module.git ../headers-more-nginx-module
|
||||
- git clone https://github.com/openresty/drizzle-nginx-module.git ../drizzle-nginx-module
|
||||
- git clone https://github.com/openresty/set-misc-nginx-module.git ../set-misc-nginx-module
|
||||
- git clone https://github.com/openresty/memc-nginx-module.git ../memc-nginx-module
|
||||
- git clone https://github.com/openresty/rds-json-nginx-module.git ../rds-json-nginx-module
|
||||
- git clone https://github.com/openresty/srcache-nginx-module.git ../srcache-nginx-module
|
||||
- git clone https://github.com/openresty/redis2-nginx-module.git ../redis2-nginx-module
|
||||
- git clone https://github.com/openresty/lua-resty-core.git ../lua-resty-core
|
||||
- git clone https://github.com/openresty/lua-resty-lrucache.git ../lua-resty-lrucache
|
||||
- git clone https://github.com/openresty/lua-resty-mysql.git ../lua-resty-mysql
|
||||
- git clone https://github.com/openresty/lua-resty-string.git ../lua-resty-string
|
||||
- git clone https://github.com/openresty/stream-lua-nginx-module.git ../stream-lua-nginx-module
|
||||
- git clone -b v2.1-agentzh https://github.com/openresty/luajit2.git luajit2
|
||||
|
||||
before_script:
|
||||
- mysql -uroot -e 'create database ngx_test; grant all on ngx_test.* to "ngx_test"@"%" identified by "ngx_test"; flush privileges;'
|
||||
|
||||
script:
|
||||
- export PATH=$PWD/work/nginx/sbin:$PWD/openresty-devel-utils:$PATH
|
||||
- ngx-releng > check.txt || true
|
||||
- lines=`wc -l check.txt | awk '{print $1}'`; if [ $lines -gt 5 ]; then cat check.txt; exit 1; fi
|
||||
- sudo iptables -I OUTPUT 1 -p udp --dport 10086 -j REJECT
|
||||
- sudo iptables -I OUTPUT -p tcp --dst 127.0.0.2 --dport 12345 -j DROP
|
||||
- sudo iptables -I OUTPUT -p udp --dst 127.0.0.2 --dport 12345 -j DROP
|
||||
- sudo ip route add prohibit 0.0.0.1/32
|
||||
- cd luajit2/
|
||||
- make -j$JOBS CCDEBUG=-g Q= PREFIX=$LUAJIT_PREFIX CC=$CC XCFLAGS='-DLUA_USE_APICHECK -DLUA_USE_ASSERT -msse4.2' > build.log 2>&1 || (cat build.log && exit 1)
|
||||
- sudo make install PREFIX=$LUAJIT_PREFIX > build.log 2>&1 || (cat build.log && exit 1)
|
||||
- cd ..
|
||||
- tar xzf download-cache/drizzle7-$DRIZZLE_VER.tar.gz && cd drizzle7-$DRIZZLE_VER
|
||||
- ./configure --prefix=$LIBDRIZZLE_PREFIX --without-server > build.log 2>&1 || (cat build.log && exit 1)
|
||||
- make libdrizzle-1.0 -j$JOBS > build.log 2>&1 || (cat build.log && exit 1)
|
||||
- sudo make install-libdrizzle-1.0 > build.log 2>&1 || (cat build.log && exit 1)
|
||||
- cd ../mockeagain/ && make CC=$CC -j$JOBS && cd ..
|
||||
- cd lua-cjson/ && make -j$JOBS && sudo make install && cd ..
|
||||
- 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 ..
|
||||
- tar zxf download-cache/openssl-$OPENSSL_VER.tar.gz
|
||||
- cd openssl-$OPENSSL_VER/
|
||||
- patch -p1 < ../../openresty/patches/openssl-$OPENSSL_PATCH_VER-sess_set_get_cb_yield.patch
|
||||
- ./config shared enable-ssl3 enable-ssl3-method -g --prefix=$OPENSSL_PREFIX -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 ..
|
||||
- export NGX_BUILD_CC=$CC
|
||||
- sh util/build-without-ssl.sh $NGINX_VERSION > build.log 2>&1 || (cat build.log && exit 1)
|
||||
- sh util/build-with-dd.sh $NGINX_VERSION > build.log 2>&1 || (cat build.log && exit 1)
|
||||
- rm -fr buildroot
|
||||
- sh util/build.sh $NGINX_VERSION > build.log 2>&1 || (cat build.log && exit 1)
|
||||
- nginx -V
|
||||
- python3 ./util/nc_server.py &
|
||||
- ldd `which nginx`|grep -E 'luajit|ssl|pcre'
|
||||
- export LD_PRELOAD=$PWD/mockeagain/mockeagain.so
|
||||
- export LD_LIBRARY_PATH=$PWD/mockeagain:$LD_LIBRARY_PATH
|
||||
- export TEST_NGINX_RESOLVER=8.8.4.4
|
||||
- dig +short myip.opendns.com @resolver1.opendns.com || exit 0
|
||||
- dig +short @$TEST_NGINX_RESOLVER openresty.org || exit 0
|
||||
- dig +short @$TEST_NGINX_RESOLVER agentzh.org || exit 0
|
||||
- /usr/bin/env perl $(command -v prove) -I. -Itest-nginx/lib -r t/
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,516 @@
|
|||
ngx_lua_opt_I=
|
||||
ngx_lua_opt_L=
|
||||
luajit_ld_opt=
|
||||
|
||||
ngx_feature_name=
|
||||
ngx_feature_run=no
|
||||
ngx_feature_incs=
|
||||
ngx_feature_test=
|
||||
|
||||
if [ -n "$LUAJIT_INC" -o -n "$LUAJIT_LIB" ]; then
|
||||
# explicitly set LuaJIT paths
|
||||
|
||||
if [ "$NGX_PLATFORM" = win32 ]; then
|
||||
ngx_feature="LuaJIT library in $LUAJIT_LIB and $LUAJIT_INC (win32)"
|
||||
ngx_feature_path="$LUAJIT_INC"
|
||||
ngx_lua_opt_I="-I$LUAJIT_INC"
|
||||
ngx_lua_opt_L="-L$LUAJIT_LIB"
|
||||
|
||||
# ensure that -I$LUAJIT_INC and -L$LUAJIT_LIB come first
|
||||
SAVED_CC_TEST_FLAGS="$CC_TEST_FLAGS"
|
||||
CC_TEST_FLAGS="$ngx_lua_opt_I $CC_TEST_FLAGS"
|
||||
SAVED_NGX_TEST_LD_OPT="$NGX_TEST_LD_OPT"
|
||||
NGX_TEST_LD_OPT="$ngx_lua_opt_L $NGX_TEST_LD_OPT"
|
||||
|
||||
# LuaJIT's win32 build uses the library file name lua51.dll.
|
||||
ngx_feature_libs="$ngx_lua_opt_L -llua51"
|
||||
|
||||
. auto/feature
|
||||
|
||||
# clean up
|
||||
CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS"
|
||||
NGX_TEST_LD_OPT="$SAVED_NGX_TEST_LD_OPT"
|
||||
else
|
||||
# attempt to link with -ldl, static linking on Linux requires it.
|
||||
ngx_feature="LuaJIT library in $LUAJIT_LIB and $LUAJIT_INC (specified by the LUAJIT_LIB and LUAJIT_INC env, with -ldl)"
|
||||
ngx_feature_path="$LUAJIT_INC"
|
||||
ngx_lua_opt_I="-I$LUAJIT_INC"
|
||||
ngx_lua_opt_L="-L$LUAJIT_LIB"
|
||||
luajit_ld_opt="-lm -ldl"
|
||||
|
||||
# ensure that -I$LUAJIT_INC and -L$LUAJIT_LIB come first
|
||||
SAVED_CC_TEST_FLAGS="$CC_TEST_FLAGS"
|
||||
CC_TEST_FLAGS="$ngx_lua_opt_I $CC_TEST_FLAGS"
|
||||
SAVED_NGX_TEST_LD_OPT="$NGX_TEST_LD_OPT"
|
||||
NGX_TEST_LD_OPT="$ngx_lua_opt_L $NGX_TEST_LD_OPT"
|
||||
|
||||
if [ $NGX_RPATH = YES ]; then
|
||||
ngx_feature_libs="-R$LUAJIT_LIB $ngx_lua_opt_L -lluajit-5.1 $luajit_ld_opt"
|
||||
else
|
||||
ngx_feature_libs="$ngx_lua_opt_L -lluajit-5.1 $luajit_ld_opt"
|
||||
fi
|
||||
|
||||
. auto/feature
|
||||
|
||||
# clean up
|
||||
CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS"
|
||||
NGX_TEST_LD_OPT="$SAVED_NGX_TEST_LD_OPT"
|
||||
|
||||
if [ $ngx_found = no ]; then
|
||||
# retry without -ldl
|
||||
ngx_feature="LuaJIT library in $LUAJIT_LIB and $LUAJIT_INC (specified by the LUAJIT_LIB and LUAJIT_INC env)"
|
||||
ngx_feature_path="$LUAJIT_INC"
|
||||
ngx_lua_opt_I="-I$LUAJIT_INC"
|
||||
ngx_lua_opt_L="-L$LUAJIT_LIB"
|
||||
luajit_ld_opt="-lm"
|
||||
|
||||
# ensure that -I$LUAJIT_INC and -L$LUAJIT_LIB come first
|
||||
SAVED_CC_TEST_FLAGS="$CC_TEST_FLAGS"
|
||||
CC_TEST_FLAGS="$ngx_lua_opt_I $CC_TEST_FLAGS"
|
||||
SAVED_NGX_TEST_LD_OPT="$NGX_TEST_LD_OPT"
|
||||
NGX_TEST_LD_OPT="$ngx_lua_opt_L $NGX_TEST_LD_OPT"
|
||||
|
||||
if [ $NGX_RPATH = YES ]; then
|
||||
ngx_feature_libs="-R$LUAJIT_LIB $ngx_lua_opt_L -lluajit-5.1 $luajit_ld_opt"
|
||||
else
|
||||
ngx_feature_libs="$ngx_lua_opt_L -lluajit-5.1 $luajit_ld_opt"
|
||||
fi
|
||||
|
||||
. auto/feature
|
||||
|
||||
# clean up
|
||||
CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS"
|
||||
NGX_TEST_LD_OPT="$SAVED_NGX_TEST_LD_OPT"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ $ngx_found = no ]; then
|
||||
cat << END
|
||||
$0: error: ngx_http_lua_module requires the LuaJIT library, but it could not be found where specified (LUAJIT_LIB=$LUAJIT_LIB, LUAJIT_INC=$LUAJIT_INC).
|
||||
END
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case "$NGX_PLATFORM" in
|
||||
Darwin:*)
|
||||
case "$NGX_MACHINE" in
|
||||
amd64 | x86_64 | i386)
|
||||
echo "adding extra linking options needed by LuaJIT on $NGX_MACHINE"
|
||||
luajit_ld_opt="$luajit_ld_opt -pagezero_size 10000 -image_base 100000000"
|
||||
ngx_feature_libs="$ngx_feature_libs -pagezero_size 10000 -image_base 100000000"
|
||||
;;
|
||||
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
else
|
||||
# auto-discovery
|
||||
if [ $ngx_found = no ]; then
|
||||
# FreeBSD with luajit-2.0 from ports collection
|
||||
ngx_feature="LuaJIT library in /usr/local/"
|
||||
ngx_feature_path="/usr/local/include/luajit-2.0"
|
||||
luajit_ld_opt="-lm"
|
||||
LUAJIT_LIB="/usr/local/lib"
|
||||
if [ $NGX_RPATH = YES ]; then
|
||||
ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -lluajit-5.1 -lm"
|
||||
else
|
||||
ngx_feature_libs="-L/usr/local/lib -lluajit-5.1 -lm"
|
||||
fi
|
||||
. auto/feature
|
||||
fi
|
||||
|
||||
if [ $ngx_found = no ]; then
|
||||
# Gentoo with LuaJIT-2.0, try with -ldl
|
||||
ngx_feature="LuaJIT library in /usr/"
|
||||
ngx_feature_path="/usr/include/luajit-2.0"
|
||||
luajit_ld_opt="-lm -ldl"
|
||||
LUAJIT_LIB="/usr/lib"
|
||||
if [ $NGX_RPATH = YES ]; then
|
||||
ngx_feature_libs="-R/usr/lib -L/usr/lib -lm -lluajit-5.1 -ldl"
|
||||
else
|
||||
ngx_feature_libs="-L/usr/lib -lm -lluajit-5.1 -ldl"
|
||||
fi
|
||||
. auto/feature
|
||||
fi
|
||||
|
||||
if [ $ngx_found = no ]; then
|
||||
# Gentoo with LuaJIT 2.0
|
||||
ngx_feature="LuaJIT library in /usr/"
|
||||
ngx_feature_path="/usr/include/luajit-2.0"
|
||||
luajit_ld_opt="-lm"
|
||||
LUAJIT_LIB="/usr/lib"
|
||||
if [ $NGX_RPATH = YES ]; then
|
||||
ngx_feature_libs="-R/usr/lib -L/usr/lib -lm -lluajit-5.1"
|
||||
else
|
||||
ngx_feature_libs="-L/usr/lib -lm -lluajit-5.1"
|
||||
fi
|
||||
. auto/feature
|
||||
fi
|
||||
fi
|
||||
|
||||
ngx_module_incs=
|
||||
ngx_module_libs=
|
||||
|
||||
if [ $ngx_found = yes ]; then
|
||||
# this is a hack to persuade nginx's build system to favor
|
||||
# the paths set by our user environment
|
||||
CFLAGS="$ngx_lua_opt_I $CFLAGS"
|
||||
NGX_LD_OPT="$ngx_lua_opt_L $NGX_LD_OPT"
|
||||
|
||||
ngx_module_incs="$ngx_module_incs $ngx_feature_path"
|
||||
ngx_module_libs="$ngx_module_libs $ngx_feature_libs"
|
||||
else
|
||||
cat << END
|
||||
$0: error: ngx_http_lua_module requires the LuaJIT library.
|
||||
END
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ----------------------------------------
|
||||
|
||||
ngx_feature="LuaJIT 2.x"
|
||||
ngx_feature_run=no
|
||||
ngx_feature_incs="#include <luajit.h>"
|
||||
ngx_feature_test="#if !defined(LUAJIT_VERSION_NUM) || LUAJIT_VERSION_NUM < 20000
|
||||
# error unsupported LuaJIT version
|
||||
#endif
|
||||
"
|
||||
|
||||
. auto/feature
|
||||
|
||||
if [ $ngx_found = no ]; then
|
||||
cat << END
|
||||
$0: error: unsupported LuaJIT version; ngx_http_lua_module requires LuaJIT 2.x.
|
||||
END
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ----------------------------------------
|
||||
|
||||
ngx_feature="Lua language 5.1"
|
||||
ngx_feature_run=no
|
||||
ngx_feature_incs="#include <lua.h>"
|
||||
ngx_feature_test="#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM != 501
|
||||
# error unsupported Lua language version
|
||||
#endif
|
||||
"
|
||||
|
||||
. auto/feature
|
||||
|
||||
if [ $ngx_found = no ]; then
|
||||
cat << END
|
||||
$0: error: unsupported Lua language version; ngx_http_lua_module requires Lua 5.1.
|
||||
END
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ----------------------------------------
|
||||
|
||||
ngx_feature="LuaJIT has FFI"
|
||||
ngx_feature_libs="$ngx_module_libs"
|
||||
ngx_feature_run=no
|
||||
ngx_feature_incs="#include <lualib.h>
|
||||
#include <lauxlib.h>
|
||||
#include <assert.h>
|
||||
"
|
||||
ngx_feature_test="lua_State *L = luaL_newstate();
|
||||
assert(L != NULL);
|
||||
luaopen_ffi(L);
|
||||
"
|
||||
|
||||
. auto/feature
|
||||
|
||||
if [ $ngx_found = no ]; then
|
||||
cat << END
|
||||
$0: error: unsupported LuaJIT build; ngx_http_lua_module requires LuaJIT with FFI enabled.
|
||||
END
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ----------------------------------------
|
||||
|
||||
ngx_addon_name=ngx_http_lua_module
|
||||
HTTP_LUA_SRCS=" \
|
||||
$ngx_addon_dir/src/ngx_http_lua_script.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_log.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_subrequest.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_ndk.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_control.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_time.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_misc.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_variable.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_string.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_output.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_headers.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_req_body.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_uri.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_args.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_ctx.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_regex.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_module.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_headers_out.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_headers_in.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_directive.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_consts.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_exception.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_util.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_cache.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_contentby.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_server_rewriteby.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_rewriteby.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_accessby.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_setby.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_capturefilter.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_clfactory.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_pcrefix.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_headerfilterby.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_shdict.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_socket_tcp.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_api.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_logby.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_sleep.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_semaphore.c\
|
||||
$ngx_addon_dir/src/ngx_http_lua_coroutine.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_bodyfilterby.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_initby.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_initworkerby.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_exitworkerby.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_socket_udp.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_req_method.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_phase.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_uthread.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_timer.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_config.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_worker.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_ssl_client_helloby.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_ssl_certby.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_ssl_ocsp.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_lex.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_balancer.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_ssl_session_storeby.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_ssl_session_fetchby.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_ssl.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_log_ringbuf.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_input_filters.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_pipe.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_worker_thread.c \
|
||||
"
|
||||
|
||||
HTTP_LUA_DEPS=" \
|
||||
$ngx_addon_dir/src/ddebug.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_autoconf.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_script.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_log.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_subrequest.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_ndk.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_control.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_string.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_misc.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_output.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_headers.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_uri.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_req_body.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_args.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_ctx.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_common.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_directive.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_headers_out.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_headers_in.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_consts.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_exception.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_util.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_cache.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_contentby.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_server_rewriteby.c \
|
||||
$ngx_addon_dir/src/ngx_http_lua_rewriteby.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_accessby.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_setby.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_capturefilter.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_clfactory.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_pcrefix.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_headerfilterby.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_shdict.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_socket_tcp.h \
|
||||
$ngx_addon_dir/src/api/ngx_http_lua_api.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_logby.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_sleep.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_semaphore.h\
|
||||
$ngx_addon_dir/src/ngx_http_lua_coroutine.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_bodyfilterby.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_initby.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_initworkerby.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_exitworkerby.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_socket_udp.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_probe.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_uthread.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_timer.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_config.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_ssl_client_helloby.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_ssl_certby.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_lex.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_balancer.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_ssl_session_storeby.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_ssl_session_fetchby.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_ssl.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_log_ringbuf.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_input_filters.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_pipe.h \
|
||||
$ngx_addon_dir/src/ngx_http_lua_worker_thread.h \
|
||||
"
|
||||
|
||||
# ----------------------------------------
|
||||
|
||||
ngx_feature="export symbols by default (-E)"
|
||||
ngx_feature_libs="-Wl,-E"
|
||||
ngx_feature_name=
|
||||
ngx_feature_run=no
|
||||
ngx_feature_incs="#include <stdio.h>"
|
||||
ngx_feature_path=
|
||||
ngx_feature_test='printf("hello");'
|
||||
|
||||
. auto/feature
|
||||
|
||||
if [ $ngx_found = yes ]; then
|
||||
CORE_LIBS="-Wl,-E $CORE_LIBS"
|
||||
fi
|
||||
|
||||
# ----------------------------------------
|
||||
|
||||
# for Cygwin
|
||||
ngx_feature="export symbols by default (--export-all-symbols)"
|
||||
ngx_feature_libs="-Wl,--export-all-symbols"
|
||||
ngx_feature_name=
|
||||
ngx_feature_run=no
|
||||
ngx_feature_incs="#include <stdio.h>"
|
||||
ngx_feature_path=
|
||||
ngx_feature_test='printf("hello");'
|
||||
|
||||
. auto/feature
|
||||
|
||||
if [ $ngx_found = yes ]; then
|
||||
CORE_LIBS="-Wl,--export-all-symbols $CORE_LIBS"
|
||||
fi
|
||||
|
||||
# ----------------------------------------
|
||||
|
||||
ngx_feature="SO_PASSCRED"
|
||||
ngx_feature_libs=
|
||||
ngx_feature_name="NGX_HTTP_LUA_HAVE_SO_PASSCRED"
|
||||
ngx_feature_run=no
|
||||
ngx_feature_incs="#include <sys/types.h>
|
||||
#include <sys/socket.h>"
|
||||
ngx_feature_path=
|
||||
ngx_feature_test='setsockopt(1, SOL_SOCKET, SO_PASSCRED, NULL, 0);'
|
||||
|
||||
. auto/feature
|
||||
|
||||
# ----------------------------------------
|
||||
|
||||
ngx_feature="SA_RESTART"
|
||||
ngx_feature_libs=
|
||||
ngx_feature_name="NGX_HTTP_LUA_HAVE_SA_RESTART"
|
||||
ngx_feature_run=no
|
||||
ngx_feature_incs="#include <signal.h>"
|
||||
ngx_feature_path=
|
||||
ngx_feature_test='struct sigaction act;
|
||||
act.sa_flags |= SA_RESTART;'
|
||||
|
||||
. auto/feature
|
||||
|
||||
# ----------------------------------------
|
||||
|
||||
ngx_feature="malloc_trim"
|
||||
ngx_feature_libs=
|
||||
ngx_feature_name="NGX_HTTP_LUA_HAVE_MALLOC_TRIM"
|
||||
ngx_feature_run=yes
|
||||
ngx_feature_incs="#include <malloc.h>
|
||||
#include <stdio.h>"
|
||||
ngx_feature_test="int rc = malloc_trim((size_t) 0); printf(\"%d\", rc);"
|
||||
SAVED_CC_TEST_FLAGS="$CC_TEST_FLAGS"
|
||||
CC_TEST_FLAGS="-Werror -Wall $CC_TEST_FLAGS"
|
||||
|
||||
. auto/feature
|
||||
|
||||
CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS"
|
||||
|
||||
# ----------------------------------------
|
||||
|
||||
ngx_feature="pipe2"
|
||||
ngx_feature_libs=
|
||||
ngx_feature_name="NGX_HTTP_LUA_HAVE_PIPE2"
|
||||
ngx_feature_run=no
|
||||
ngx_feature_incs="#include <fcntl.h>"
|
||||
ngx_feature_test="int fd[2]; pipe2(fd, O_CLOEXEC|O_NONBLOCK);"
|
||||
SAVED_CC_TEST_FLAGS="$CC_TEST_FLAGS"
|
||||
CC_TEST_FLAGS="-Werror -Wall $CC_TEST_FLAGS"
|
||||
|
||||
. auto/feature
|
||||
|
||||
CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS"
|
||||
|
||||
# ----------------------------------------
|
||||
|
||||
ngx_feature="signalfd"
|
||||
ngx_feature_libs=
|
||||
ngx_feature_name="NGX_HTTP_LUA_HAVE_SIGNALFD"
|
||||
ngx_feature_run=no
|
||||
ngx_feature_incs="#include <sys/signalfd.h>"
|
||||
ngx_feature_test="sigset_t set; signalfd(-1, &set, SFD_NONBLOCK|SFD_CLOEXEC);"
|
||||
SAVED_CC_TEST_FLAGS="$CC_TEST_FLAGS"
|
||||
CC_TEST_FLAGS="-Werror -Wall $CC_TEST_FLAGS"
|
||||
|
||||
. auto/feature
|
||||
|
||||
CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS"
|
||||
|
||||
# ----------------------------------------
|
||||
|
||||
ngx_feature="execvpe"
|
||||
ngx_feature_libs=
|
||||
ngx_feature_name="NGX_HTTP_LUA_HAVE_EXECVPE"
|
||||
ngx_feature_run=no
|
||||
ngx_feature_incs=
|
||||
ngx_feature_test='char* argv[] = {"/bin/sh"};execvpe("/bin/sh", argv, NULL);'
|
||||
SAVED_CC_TEST_FLAGS="$CC_TEST_FLAGS"
|
||||
CC_TEST_FLAGS="-Werror -Wall $CC_TEST_FLAGS"
|
||||
|
||||
. auto/feature
|
||||
|
||||
CC_TEST_FLAGS="$SAVED_CC_TEST_FLAGS"
|
||||
|
||||
# ----------------------------------------
|
||||
|
||||
if [ -n "$ngx_module_link" ]; then
|
||||
ngx_module_type=HTTP_AUX_FILTER
|
||||
ngx_module_name=$ngx_addon_name
|
||||
ngx_module_deps="$HTTP_LUA_DEPS"
|
||||
ngx_module_srcs="$HTTP_LUA_SRCS"
|
||||
|
||||
. auto/module
|
||||
else
|
||||
HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES $ngx_addon_name"
|
||||
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $HTTP_LUA_SRCS"
|
||||
NGX_ADDON_DEPS="$NGX_ADDON_DEPS $HTTP_LUA_DEPS"
|
||||
|
||||
CORE_INCS="$CORE_INCS $ngx_module_incs"
|
||||
CORE_LIBS="$CORE_LIBS $ngx_module_libs"
|
||||
fi
|
||||
|
||||
# ----------------------------------------
|
||||
|
||||
USE_MD5=YES
|
||||
USE_SHA1=YES
|
||||
|
||||
NGX_DTRACE_PROVIDERS="$NGX_DTRACE_PROVIDERS $ngx_addon_dir/dtrace/ngx_lua_provider.d"
|
||||
NGX_TAPSET_SRCS="$NGX_TAPSET_SRCS $ngx_addon_dir/tapset/ngx_lua.stp"
|
||||
|
||||
CORE_INCS="$CORE_INCS $ngx_addon_dir/src/api"
|
||||
|
||||
CFLAGS="$CFLAGS -DNDK_SET_VAR"
|
||||
|
||||
echo "/* DO NOT EDIT! This file was automatically generated by config */" > "$ngx_addon_dir/src/ngx_http_lua_autoconf.h"
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,61 @@
|
|||
provider nginx_lua {
|
||||
probe http__lua__info(char *s);
|
||||
|
||||
/* lua_State *L */
|
||||
probe http__lua__register__preload__package(void *L, u_char *pkg);
|
||||
|
||||
probe http__lua__req__socket__consume__preread(void *r,
|
||||
u_char *data, size_t len);
|
||||
|
||||
/* lua_State *parent, lua_State *child */
|
||||
probe http__lua__user__coroutine__create(void *r,
|
||||
void *parent, void *child);
|
||||
|
||||
/* lua_State *parent, lua_State *child */
|
||||
probe http__lua__user__coroutine__resume(void *r,
|
||||
void *parent, void *child);
|
||||
|
||||
/* lua_State *parent, lua_State *child */
|
||||
probe http__lua__user__coroutine__yield(void *r,
|
||||
void *parent, void *child);
|
||||
|
||||
/* lua_State *L */
|
||||
probe http__lua__thread__yield(void *r, void *L);
|
||||
|
||||
/* ngx_http_lua_socket_tcp_upstream_t *u */
|
||||
probe http__lua__socket__tcp__send__start(void *r,
|
||||
void *u, u_char *data, size_t len);
|
||||
|
||||
/* ngx_http_lua_socket_tcp_upstream_t *u */
|
||||
probe http__lua__socket__tcp__receive__done(void *r,
|
||||
void *u, u_char *data, size_t len);
|
||||
|
||||
/* ngx_http_lua_socket_tcp_upstream_t *u */
|
||||
probe http__lua__socket__tcp__setkeepalive__buf__unread(
|
||||
void *r, void *u, u_char *data, size_t len);
|
||||
|
||||
/* lua_State *creator, lua_State *newthread */
|
||||
probe http__lua__user__thread__spawn(void *r,
|
||||
void *creator, void *newthread);
|
||||
|
||||
/* lua_State *thread, ngx_http_lua_ctx_t *ctx */
|
||||
probe http__lua__thread__delete(void *r, void *thread, void *ctx);
|
||||
|
||||
/* lua_State *thread */
|
||||
probe http__lua__run__posted__thread(void *r, void *thread,
|
||||
int status);
|
||||
|
||||
probe http__lua__coroutine__done(void *r, void *co,
|
||||
int success);
|
||||
|
||||
/* lua_State *parent, lua_State *child */
|
||||
probe http__lua__user__thread__wait(void *parent, void *child);
|
||||
};
|
||||
|
||||
|
||||
#pragma D attributes Evolving/Evolving/Common provider nginx_lua provider
|
||||
#pragma D attributes Private/Private/Unknown provider nginx_lua module
|
||||
#pragma D attributes Private/Private/Unknown provider nginx_lua function
|
||||
#pragma D attributes Private/Private/Common provider nginx_lua name
|
||||
#pragma D attributes Evolving/Evolving/Common provider nginx_lua args
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
test:
|
||||
prove -Ilib -r t
|
||||
|
|
@ -0,0 +1,138 @@
|
|||
package RecvUntil;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
sub recv_until {
|
||||
my ($pat) = @_;
|
||||
|
||||
my $len = length $pat;
|
||||
my @backtracks;
|
||||
|
||||
for (my $i = 1; $i <= $len - 1; $i++) {
|
||||
my $matched_prefix_len = 1;
|
||||
while ($matched_prefix_len <= $len - $i - 1) {
|
||||
#while (1) {
|
||||
#my $left = $len - $i;
|
||||
#warn "left: $i: $len: ", $len - 1 - $i, "\n";
|
||||
#warn "matched_prefix_len: $matched_prefix_len\n";
|
||||
|
||||
#while (1) {
|
||||
my $prefix = substr($pat, 0, $matched_prefix_len);
|
||||
my $next = substr($pat, $matched_prefix_len, 1);
|
||||
|
||||
my $prefix2 = substr($pat, $i, $matched_prefix_len);
|
||||
my $next2 = substr($pat, $i + $matched_prefix_len, 1);
|
||||
|
||||
#warn "$i: global prefix $prefix $next\n";
|
||||
#warn "$i: local prefix $prefix2 $next2\n";
|
||||
|
||||
if ($prefix2 eq $prefix) {
|
||||
if ($next2 eq $next) {
|
||||
$matched_prefix_len++;
|
||||
next;
|
||||
}
|
||||
|
||||
#warn "$matched_prefix_len: $prefix: found match at $i (next $next, next2 $next2)\n";
|
||||
my $cur_state = $i + $matched_prefix_len;
|
||||
my $new_state = $matched_prefix_len + 1;
|
||||
|
||||
my $matched = substr($pat, 0, $cur_state);
|
||||
|
||||
my $chain = $backtracks[$cur_state - 2];
|
||||
if (!$chain) {
|
||||
$chain = [];
|
||||
$backtracks[$cur_state - 2] = $chain;
|
||||
}
|
||||
|
||||
my $found = 0;
|
||||
for my $rec (@$chain) {
|
||||
if ($rec->{char} eq $next) {
|
||||
$found = 1;
|
||||
|
||||
if ($rec->{new_state} < $new_state) {
|
||||
warn "overriding...\n";
|
||||
$rec->{new_state} = $new_state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$found) {
|
||||
warn "on state $cur_state ($matched), if next is '$next', ",
|
||||
"then backtrack to state $new_state ($prefix$next)\n";
|
||||
|
||||
push @$chain, { char => $next, new_state => $new_state };
|
||||
}
|
||||
|
||||
#if ($matched_prefix_len > 1) {
|
||||
#$i += $matched_prefix_len - 1;
|
||||
#}
|
||||
|
||||
last;
|
||||
}
|
||||
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
return sub {
|
||||
my ($txt) = @_;
|
||||
|
||||
my $max_state = length $pat;
|
||||
my $len = length $txt;
|
||||
my $state = 0;
|
||||
my $ret = '';
|
||||
|
||||
for (my $i = 0; $i < $len; $i++) {
|
||||
# read the char
|
||||
my $c = substr($txt, $i, 1);
|
||||
|
||||
#warn "$state: read char at $i: $c\n";
|
||||
#warn "matched: $ret\n";
|
||||
|
||||
my $expected = substr($pat, $state, 1);
|
||||
if ($expected eq $c) {
|
||||
#warn "matched the char in pattern.\n";
|
||||
$state++;
|
||||
|
||||
if ($state == $max_state) {
|
||||
last;
|
||||
}
|
||||
|
||||
next;
|
||||
}
|
||||
|
||||
if ($state == 0) {
|
||||
#warn "did not match the first char in pattern\n";
|
||||
$ret .= $c;
|
||||
next;
|
||||
}
|
||||
|
||||
my $old_state;
|
||||
my $matched;
|
||||
my $chain = $backtracks[$state - 2];
|
||||
for my $rec (@$chain) {
|
||||
if ($rec->{char} eq $c) {
|
||||
$old_state = $state;
|
||||
$state = $rec->{new_state};
|
||||
#warn "matched the char for backtracking to state $state\n";
|
||||
$matched = 1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$matched) {
|
||||
$ret .= substr($pat, 0, $state);
|
||||
$state = 0;
|
||||
redo;
|
||||
}
|
||||
|
||||
$ret .= substr($pat, 0, $old_state + 1 - $state);
|
||||
next;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
};
|
||||
}
|
||||
|
||||
1;
|
|
@ -0,0 +1,140 @@
|
|||
# vi:ft=
|
||||
|
||||
use 5.10.1;
|
||||
use Test::Base;
|
||||
use RecvUntil;
|
||||
|
||||
plan tests => 1 * blocks();
|
||||
|
||||
run {
|
||||
my $block = shift;
|
||||
my $name = $block->name;
|
||||
my $pat = $block->pat // die "$name: No --- pat found";
|
||||
my $txt = $block->txt // die "$name: No --- txt found";
|
||||
|
||||
my $expected = $block->out // die "$name: No --- out found";
|
||||
|
||||
my $it = RecvUntil::recv_until($pat);
|
||||
is $it->($txt), $expected, "$name: output ok";
|
||||
};
|
||||
|
||||
__DATA__
|
||||
|
||||
=== TEST 1:
|
||||
--- pat: abcabd
|
||||
--- txt: abcabcabd
|
||||
--- out: abc
|
||||
|
||||
|
||||
|
||||
=== TEST 2:
|
||||
--- pat: aa
|
||||
--- txt: abcabcaad
|
||||
--- out: abcabc
|
||||
|
||||
|
||||
|
||||
=== TEST 3:
|
||||
--- pat: ab
|
||||
--- txt: bbcabcaad
|
||||
--- out: bbc
|
||||
|
||||
|
||||
|
||||
=== TEST 4:
|
||||
--- pat: aaa
|
||||
--- txt: abaabcaaaef
|
||||
--- out: abaabc
|
||||
|
||||
|
||||
|
||||
=== TEST 5:
|
||||
--- pat: aaaaad
|
||||
--- txt: baaaaaaaaeaaaaaaadf
|
||||
--- out: baaaaaaaaeaa
|
||||
|
||||
|
||||
|
||||
=== TEST 6:
|
||||
--- pat: abacadae
|
||||
--- txt: a
|
||||
--- out:
|
||||
|
||||
|
||||
|
||||
=== TEST 7:
|
||||
--- pat: abacadae
|
||||
--- txt: ababacadae
|
||||
--- out: ab
|
||||
|
||||
|
||||
|
||||
=== TEST 8:
|
||||
--- pat: abacadae
|
||||
--- txt: abacabacadae
|
||||
--- out: abac
|
||||
|
||||
|
||||
|
||||
=== TEST 9:
|
||||
--- pat: abacadae
|
||||
--- txt: abaabacadae
|
||||
--- out: aba
|
||||
|
||||
|
||||
|
||||
=== TEST 10:
|
||||
--- pat: abacadae
|
||||
--- txt: abacadabacadae
|
||||
--- out: abacad
|
||||
|
||||
|
||||
|
||||
=== TEST 11:
|
||||
--- pat: abcabdabcabe
|
||||
--- txt: abcabdabcabdabcabe
|
||||
--- out: abcabd
|
||||
|
||||
|
||||
|
||||
=== TEST 12:
|
||||
--- pat: abcabdabcabe
|
||||
--- txt: abcabdabcabcabdabcabe
|
||||
--- out: abcabdabc
|
||||
|
||||
|
||||
|
||||
=== TEST 13:
|
||||
--- pat: abcabdabcabe
|
||||
--- txt: abcabcabdabcabe
|
||||
--- out: abc
|
||||
|
||||
|
||||
|
||||
=== TEST 14:
|
||||
--- pat: abcabdabcabe
|
||||
--- txt: ababcabdabcabe
|
||||
--- out: ab
|
||||
|
||||
|
||||
|
||||
=== TEST 15:
|
||||
--- pat: abcdef
|
||||
--- txt: abcabcdef
|
||||
--- out: abc
|
||||
|
||||
|
||||
|
||||
=== TEST 16:
|
||||
--- pat: -- abc
|
||||
--- txt: ---- abc
|
||||
--- out: --
|
||||
|
||||
|
||||
|
||||
=== TEST 17:
|
||||
--- pat: yz--ababyz
|
||||
--- txt:
|
||||
--- out: --
|
||||
--- SKIP
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_API_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_API_H_INCLUDED_
|
||||
|
||||
|
||||
#include <nginx.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_http.h>
|
||||
|
||||
#include <lua.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/* Public API for other Nginx modules */
|
||||
|
||||
|
||||
#define ngx_http_lua_version 10025
|
||||
|
||||
|
||||
typedef struct ngx_http_lua_co_ctx_s ngx_http_lua_co_ctx_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint8_t type;
|
||||
|
||||
union {
|
||||
int b; /* boolean */
|
||||
lua_Number n; /* number */
|
||||
ngx_str_t s; /* string */
|
||||
} value;
|
||||
|
||||
} ngx_http_lua_value_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
int len;
|
||||
/* this padding hole on 64-bit systems is expected */
|
||||
u_char *data;
|
||||
} ngx_http_lua_ffi_str_t;
|
||||
|
||||
|
||||
lua_State *ngx_http_lua_get_global_state(ngx_conf_t *cf);
|
||||
|
||||
ngx_http_request_t *ngx_http_lua_get_request(lua_State *L);
|
||||
|
||||
ngx_int_t ngx_http_lua_add_package_preload(ngx_conf_t *cf, const char *package,
|
||||
lua_CFunction func);
|
||||
|
||||
ngx_int_t ngx_http_lua_shared_dict_get(ngx_shm_zone_t *shm_zone,
|
||||
u_char *key_data, size_t key_len, ngx_http_lua_value_t *value);
|
||||
|
||||
ngx_shm_zone_t *ngx_http_lua_find_zone(u_char *name_data, size_t name_len);
|
||||
|
||||
ngx_shm_zone_t *ngx_http_lua_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name,
|
||||
size_t size, void *tag);
|
||||
|
||||
ngx_http_lua_co_ctx_t *ngx_http_lua_get_cur_co_ctx(ngx_http_request_t *r);
|
||||
|
||||
void ngx_http_lua_set_cur_co_ctx(ngx_http_request_t *r,
|
||||
ngx_http_lua_co_ctx_t *coctx);
|
||||
|
||||
lua_State *ngx_http_lua_get_co_ctx_vm(ngx_http_lua_co_ctx_t *coctx);
|
||||
|
||||
void ngx_http_lua_co_ctx_resume_helper(ngx_http_lua_co_ctx_t *coctx, int nrets);
|
||||
|
||||
int ngx_http_lua_get_lua_http10_buffering(ngx_http_request_t *r);
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_API_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,85 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _DDEBUG_H_INCLUDED_
|
||||
#define _DDEBUG_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <nginx.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
#if defined(DDEBUG) && (DDEBUG)
|
||||
|
||||
# if (NGX_HAVE_VARIADIC_MACROS)
|
||||
|
||||
# define dd(...) fprintf(stderr, "lua *** %s: ", __func__); \
|
||||
fprintf(stderr, __VA_ARGS__); \
|
||||
fprintf(stderr, " at %s line %d.\n", __FILE__, __LINE__)
|
||||
|
||||
# else
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
static ngx_inline void
|
||||
dd(const char *fmt, ...) {
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
#else
|
||||
|
||||
# if (NGX_HAVE_VARIADIC_MACROS)
|
||||
|
||||
# define dd(...)
|
||||
|
||||
# else
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
static ngx_inline void
|
||||
dd(const char *fmt, ...) {
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(DDEBUG) && (DDEBUG)
|
||||
|
||||
#define dd_check_read_event_handler(r) \
|
||||
dd("r->read_event_handler = %s", \
|
||||
r->read_event_handler == ngx_http_block_reading ? \
|
||||
"ngx_http_block_reading" : \
|
||||
r->read_event_handler == ngx_http_test_reading ? \
|
||||
"ngx_http_test_reading" : \
|
||||
r->read_event_handler == ngx_http_request_empty_handler ? \
|
||||
"ngx_http_request_empty_handler" : "UNKNOWN")
|
||||
|
||||
#define dd_check_write_event_handler(r) \
|
||||
dd("r->write_event_handler = %s", \
|
||||
r->write_event_handler == ngx_http_handler ? \
|
||||
"ngx_http_handler" : \
|
||||
r->write_event_handler == ngx_http_core_run_phases ? \
|
||||
"ngx_http_core_run_phases" : \
|
||||
r->write_event_handler == ngx_http_request_empty_handler ? \
|
||||
"ngx_http_request_empty_handler" : "UNKNOWN")
|
||||
|
||||
#else
|
||||
|
||||
#define dd_check_read_event_handler(r)
|
||||
#define dd_check_write_event_handler(r)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _DDEBUG_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,399 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include <nginx.h>
|
||||
#include "ngx_http_lua_accessby.h"
|
||||
#include "ngx_http_lua_util.h"
|
||||
#include "ngx_http_lua_exception.h"
|
||||
#include "ngx_http_lua_cache.h"
|
||||
|
||||
|
||||
static ngx_int_t ngx_http_lua_access_by_chunk(lua_State *L,
|
||||
ngx_http_request_t *r);
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_access_handler(ngx_http_request_t *r)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_http_lua_loc_conf_t *llcf;
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
ngx_http_phase_handler_t tmp, *ph, *cur_ph, *last_ph;
|
||||
ngx_http_core_main_conf_t *cmcf;
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua access handler, uri:\"%V\" c:%ud", &r->uri,
|
||||
r->main->count);
|
||||
|
||||
lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
|
||||
|
||||
if (!lmcf->postponed_to_access_phase_end) {
|
||||
|
||||
lmcf->postponed_to_access_phase_end = 1;
|
||||
|
||||
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
|
||||
|
||||
ph = cmcf->phase_engine.handlers;
|
||||
cur_ph = &ph[r->phase_handler];
|
||||
|
||||
/* we should skip the post_access phase handler here too */
|
||||
last_ph = &ph[cur_ph->next - 2];
|
||||
|
||||
dd("ph cur: %d, ph next: %d", (int) r->phase_handler,
|
||||
(int) (cur_ph->next - 2));
|
||||
|
||||
#if 0
|
||||
if (cur_ph == last_ph) {
|
||||
dd("XXX our handler is already the last access phase handler");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cur_ph < last_ph) {
|
||||
dd("swapping the contents of cur_ph and last_ph...");
|
||||
|
||||
tmp = *cur_ph;
|
||||
|
||||
memmove(cur_ph, cur_ph + 1,
|
||||
(last_ph - cur_ph) * sizeof (ngx_http_phase_handler_t));
|
||||
|
||||
*last_ph = tmp;
|
||||
|
||||
r->phase_handler--; /* redo the current ph */
|
||||
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
}
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
|
||||
if (llcf->access_handler == NULL) {
|
||||
dd("no access handler found");
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
|
||||
dd("ctx = %p", ctx);
|
||||
|
||||
if (ctx == NULL) {
|
||||
ctx = ngx_http_lua_create_ctx(r);
|
||||
if (ctx == NULL) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
dd("entered? %d", (int) ctx->entered_access_phase);
|
||||
|
||||
if (ctx->entered_access_phase) {
|
||||
dd("calling wev handler");
|
||||
rc = ctx->resume_handler(r);
|
||||
dd("wev handler returns %d", (int) rc);
|
||||
|
||||
if (rc == NGX_ERROR || rc == NGX_DONE || rc > NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (rc == NGX_OK) {
|
||||
if (r->header_sent) {
|
||||
dd("header already sent");
|
||||
|
||||
/* response header was already generated in access_by_lua*,
|
||||
* so it is no longer safe to proceed to later phases
|
||||
* which may generate responses again */
|
||||
|
||||
if (!ctx->eof) {
|
||||
dd("eof not yet sent");
|
||||
|
||||
rc = ngx_http_lua_send_chain_link(r, ctx, NULL
|
||||
/* indicate last_buf */);
|
||||
if (rc == NGX_ERROR || rc > NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_HTTP_OK;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
if (ctx->waiting_more_body) {
|
||||
dd("WAITING MORE BODY");
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
if (llcf->force_read_body && !ctx->read_body_done) {
|
||||
r->request_body_in_single_buf = 1;
|
||||
r->request_body_in_persistent_file = 1;
|
||||
r->request_body_in_clean_file = 1;
|
||||
|
||||
rc = ngx_http_read_client_request_body(r,
|
||||
ngx_http_lua_generic_phase_post_read);
|
||||
|
||||
if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (rc == NGX_AGAIN) {
|
||||
ctx->waiting_more_body = 1;
|
||||
return NGX_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
dd("calling access handler");
|
||||
return llcf->access_handler(r);
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_access_handler_inline(ngx_http_request_t *r)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
lua_State *L;
|
||||
ngx_http_lua_loc_conf_t *llcf;
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
|
||||
L = ngx_http_lua_get_lua_vm(r, NULL);
|
||||
|
||||
/* load Lua inline script (w/ cache) sp = 1 */
|
||||
rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L,
|
||||
llcf->access_src.value.data,
|
||||
llcf->access_src.value.len,
|
||||
&llcf->access_src_ref,
|
||||
llcf->access_src_key,
|
||||
(const char *) llcf->access_chunkname);
|
||||
|
||||
if (rc != NGX_OK) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
return ngx_http_lua_access_by_chunk(L, r);
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_access_handler_file(ngx_http_request_t *r)
|
||||
{
|
||||
u_char *script_path;
|
||||
ngx_int_t rc;
|
||||
ngx_str_t eval_src;
|
||||
lua_State *L;
|
||||
ngx_http_lua_loc_conf_t *llcf;
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
|
||||
/* Eval nginx variables in code path string first */
|
||||
if (ngx_http_complex_value(r, &llcf->access_src, &eval_src) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
script_path = ngx_http_lua_rebase_path(r->pool, eval_src.data,
|
||||
eval_src.len);
|
||||
|
||||
if (script_path == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
L = ngx_http_lua_get_lua_vm(r, NULL);
|
||||
|
||||
/* load Lua script file (w/ cache) sp = 1 */
|
||||
rc = ngx_http_lua_cache_loadfile(r->connection->log, L, script_path,
|
||||
&llcf->access_src_ref,
|
||||
llcf->access_src_key);
|
||||
if (rc != NGX_OK) {
|
||||
if (rc < NGX_HTTP_SPECIAL_RESPONSE) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* make sure we have a valid code chunk */
|
||||
ngx_http_lua_assert(lua_isfunction(L, -1));
|
||||
|
||||
return ngx_http_lua_access_by_chunk(L, r);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_lua_access_by_chunk(lua_State *L, ngx_http_request_t *r)
|
||||
{
|
||||
int co_ref;
|
||||
ngx_int_t rc;
|
||||
ngx_uint_t nreqs;
|
||||
lua_State *co;
|
||||
ngx_event_t *rev;
|
||||
ngx_connection_t *c;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_pool_cleanup_t *cln;
|
||||
|
||||
ngx_http_lua_loc_conf_t *llcf;
|
||||
|
||||
/* {{{ new coroutine to handle request */
|
||||
co = ngx_http_lua_new_thread(r, L, &co_ref);
|
||||
|
||||
if (co == NULL) {
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"lua: failed to create new coroutine "
|
||||
"to handle request");
|
||||
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
/* move code closure to new coroutine */
|
||||
lua_xmove(L, co, 1);
|
||||
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
/* set closure's env table to new coroutine's globals table */
|
||||
ngx_http_lua_get_globals_table(co);
|
||||
lua_setfenv(co, -2);
|
||||
#endif
|
||||
|
||||
/* save nginx request in coroutine globals table */
|
||||
ngx_http_lua_set_req(co, r);
|
||||
|
||||
/* {{{ initialize request context */
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
|
||||
dd("ctx = %p", ctx);
|
||||
|
||||
if (ctx == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_http_lua_reset_ctx(r, L, ctx);
|
||||
|
||||
ctx->entered_access_phase = 1;
|
||||
|
||||
ctx->cur_co_ctx = &ctx->entry_co_ctx;
|
||||
ctx->cur_co_ctx->co = co;
|
||||
ctx->cur_co_ctx->co_ref = co_ref;
|
||||
#ifdef NGX_LUA_USE_ASSERT
|
||||
ctx->cur_co_ctx->co_top = 1;
|
||||
#endif
|
||||
|
||||
ngx_http_lua_attach_co_ctx_to_L(co, ctx->cur_co_ctx);
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* {{{ register nginx pool cleanup hooks */
|
||||
if (ctx->cleanup == NULL) {
|
||||
cln = ngx_pool_cleanup_add(r->pool, 0);
|
||||
if (cln == NULL) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
cln->handler = ngx_http_lua_request_cleanup_handler;
|
||||
cln->data = ctx;
|
||||
ctx->cleanup = &cln->handler;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
ctx->context = NGX_HTTP_LUA_CONTEXT_ACCESS;
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
|
||||
if (llcf->check_client_abort) {
|
||||
r->read_event_handler = ngx_http_lua_rd_check_broken_connection;
|
||||
|
||||
#if (NGX_HTTP_V2)
|
||||
if (!r->stream) {
|
||||
#endif
|
||||
|
||||
rev = r->connection->read;
|
||||
|
||||
if (!rev->active) {
|
||||
if (ngx_add_event(rev, NGX_READ_EVENT, 0) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
#if (NGX_HTTP_V2)
|
||||
}
|
||||
#endif
|
||||
|
||||
} else {
|
||||
r->read_event_handler = ngx_http_block_reading;
|
||||
}
|
||||
|
||||
c = r->connection;
|
||||
nreqs = c->requests;
|
||||
|
||||
rc = ngx_http_lua_run_thread(L, r, ctx, 0);
|
||||
|
||||
dd("returned %d", (int) rc);
|
||||
|
||||
if (rc == NGX_ERROR || rc > NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (rc == NGX_AGAIN) {
|
||||
rc = ngx_http_lua_run_posted_threads(c, L, r, ctx, nreqs);
|
||||
|
||||
if (rc == NGX_ERROR || rc == NGX_DONE || rc > NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (rc != NGX_OK) {
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
} else if (rc == NGX_DONE) {
|
||||
ngx_http_lua_finalize_request(r, NGX_DONE);
|
||||
|
||||
rc = ngx_http_lua_run_posted_threads(c, L, r, ctx, nreqs);
|
||||
|
||||
if (rc == NGX_ERROR || rc == NGX_DONE || rc > NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (rc != NGX_OK) {
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
}
|
||||
|
||||
#if 1
|
||||
if (rc == NGX_OK) {
|
||||
if (r->header_sent) {
|
||||
dd("header already sent");
|
||||
|
||||
/* response header was already generated in access_by_lua*,
|
||||
* so it is no longer safe to proceed to later phases
|
||||
* which may generate responses again */
|
||||
|
||||
if (!ctx->eof) {
|
||||
dd("eof not yet sent");
|
||||
|
||||
rc = ngx_http_lua_send_chain_link(r, ctx, NULL
|
||||
/* indicate last_buf */);
|
||||
if (rc == NGX_ERROR || rc > NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_HTTP_OK;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_ACCESSBY_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_ACCESSBY_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
ngx_int_t ngx_http_lua_access_handler(ngx_http_request_t *r);
|
||||
ngx_int_t ngx_http_lua_access_handler_inline(ngx_http_request_t *r);
|
||||
ngx_int_t ngx_http_lua_access_handler_file(ngx_http_request_t *r);
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_ACCESSBY_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,344 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
#include "api/ngx_http_lua_api.h"
|
||||
#include "ngx_http_lua_shdict.h"
|
||||
#include "ngx_http_lua_util.h"
|
||||
|
||||
|
||||
lua_State *
|
||||
ngx_http_lua_get_global_state(ngx_conf_t *cf)
|
||||
{
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
|
||||
lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module);
|
||||
|
||||
return lmcf->lua;
|
||||
}
|
||||
|
||||
|
||||
ngx_http_request_t *
|
||||
ngx_http_lua_get_request(lua_State *L)
|
||||
{
|
||||
return ngx_http_lua_get_req(L);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t ngx_http_lua_shared_memory_init(ngx_shm_zone_t *shm_zone,
|
||||
void *data);
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_add_package_preload(ngx_conf_t *cf, const char *package,
|
||||
lua_CFunction func)
|
||||
{
|
||||
lua_State *L;
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
ngx_http_lua_preload_hook_t *hook;
|
||||
|
||||
lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module);
|
||||
|
||||
L = lmcf->lua;
|
||||
|
||||
if (L) {
|
||||
lua_getglobal(L, "package");
|
||||
lua_getfield(L, -1, "preload");
|
||||
lua_pushcfunction(L, func);
|
||||
lua_setfield(L, -2, package);
|
||||
lua_pop(L, 2);
|
||||
}
|
||||
|
||||
/* we always register preload_hooks since we always create new Lua VMs
|
||||
* when lua code cache is off. */
|
||||
|
||||
if (lmcf->preload_hooks == NULL) {
|
||||
lmcf->preload_hooks =
|
||||
ngx_array_create(cf->pool, 4,
|
||||
sizeof(ngx_http_lua_preload_hook_t));
|
||||
|
||||
if (lmcf->preload_hooks == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
hook = ngx_array_push(lmcf->preload_hooks);
|
||||
if (hook == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
hook->package = (u_char *) package;
|
||||
hook->loader = func;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_shm_zone_t *
|
||||
ngx_http_lua_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size,
|
||||
void *tag)
|
||||
{
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
ngx_shm_zone_t **zp;
|
||||
ngx_shm_zone_t *zone;
|
||||
ngx_http_lua_shm_zone_ctx_t *ctx;
|
||||
ngx_int_t n;
|
||||
|
||||
lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module);
|
||||
if (lmcf == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (lmcf->shm_zones == NULL) {
|
||||
lmcf->shm_zones = ngx_palloc(cf->pool, sizeof(ngx_array_t));
|
||||
if (lmcf->shm_zones == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ngx_array_init(lmcf->shm_zones, cf->pool, 2,
|
||||
sizeof(ngx_shm_zone_t *))
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
zone = ngx_shared_memory_add(cf, name, (size_t) size, tag);
|
||||
if (zone == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (zone->data) {
|
||||
ctx = (ngx_http_lua_shm_zone_ctx_t *) zone->data;
|
||||
return &ctx->zone;
|
||||
}
|
||||
|
||||
n = sizeof(ngx_http_lua_shm_zone_ctx_t);
|
||||
|
||||
ctx = ngx_pcalloc(cf->pool, n);
|
||||
if (ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx->lmcf = lmcf;
|
||||
ctx->log = &cf->cycle->new_log;
|
||||
ctx->cycle = cf->cycle;
|
||||
|
||||
ngx_memcpy(&ctx->zone, zone, sizeof(ngx_shm_zone_t));
|
||||
|
||||
zp = ngx_array_push(lmcf->shm_zones);
|
||||
if (zp == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*zp = zone;
|
||||
|
||||
/* set zone init */
|
||||
zone->init = ngx_http_lua_shared_memory_init;
|
||||
zone->data = ctx;
|
||||
|
||||
lmcf->requires_shm = 1;
|
||||
|
||||
return &ctx->zone;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_lua_shared_memory_init(ngx_shm_zone_t *shm_zone, void *data)
|
||||
{
|
||||
ngx_http_lua_shm_zone_ctx_t *octx = data;
|
||||
ngx_shm_zone_t *ozone;
|
||||
void *odata;
|
||||
|
||||
ngx_int_t rc;
|
||||
volatile ngx_cycle_t *saved_cycle;
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
ngx_http_lua_shm_zone_ctx_t *ctx;
|
||||
ngx_shm_zone_t *zone;
|
||||
|
||||
ctx = (ngx_http_lua_shm_zone_ctx_t *) shm_zone->data;
|
||||
zone = &ctx->zone;
|
||||
|
||||
odata = NULL;
|
||||
if (octx) {
|
||||
ozone = &octx->zone;
|
||||
odata = ozone->data;
|
||||
}
|
||||
|
||||
zone->shm = shm_zone->shm;
|
||||
#if (nginx_version >= 1009000)
|
||||
zone->noreuse = shm_zone->noreuse;
|
||||
#endif
|
||||
|
||||
if (zone->init(zone, odata) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
dd("get lmcf");
|
||||
|
||||
lmcf = ctx->lmcf;
|
||||
if (lmcf == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
dd("lmcf->lua: %p", lmcf->lua);
|
||||
|
||||
lmcf->shm_zones_inited++;
|
||||
|
||||
if (lmcf->shm_zones_inited == lmcf->shm_zones->nelts
|
||||
&& lmcf->init_handler && !ngx_test_config)
|
||||
{
|
||||
saved_cycle = ngx_cycle;
|
||||
ngx_cycle = ctx->cycle;
|
||||
|
||||
rc = lmcf->init_handler(ctx->log, lmcf, lmcf->lua);
|
||||
|
||||
ngx_cycle = saved_cycle;
|
||||
|
||||
if (rc != NGX_OK) {
|
||||
/* an error happened */
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_http_lua_co_ctx_t *
|
||||
ngx_http_lua_get_cur_co_ctx(ngx_http_request_t *r)
|
||||
{
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
|
||||
return ctx->cur_co_ctx;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_http_lua_set_cur_co_ctx(ngx_http_request_t *r, ngx_http_lua_co_ctx_t *coctx)
|
||||
{
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
|
||||
coctx->data = r;
|
||||
|
||||
ctx->cur_co_ctx = coctx;
|
||||
}
|
||||
|
||||
|
||||
lua_State *
|
||||
ngx_http_lua_get_co_ctx_vm(ngx_http_lua_co_ctx_t *coctx)
|
||||
{
|
||||
return coctx->co;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_lua_co_ctx_resume(ngx_http_request_t *r)
|
||||
{
|
||||
lua_State *vm;
|
||||
ngx_connection_t *c;
|
||||
ngx_int_t rc;
|
||||
ngx_uint_t nreqs;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ctx->resume_handler = ngx_http_lua_wev_handler;
|
||||
|
||||
c = r->connection;
|
||||
vm = ngx_http_lua_get_lua_vm(r, ctx);
|
||||
nreqs = c->requests;
|
||||
|
||||
rc = ngx_http_lua_run_thread(vm, r, ctx, ctx->cur_co_ctx->nrets);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua run thread returned %d", rc);
|
||||
|
||||
if (rc == NGX_AGAIN) {
|
||||
return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs);
|
||||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
ngx_http_lua_finalize_request(r, NGX_DONE);
|
||||
return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs);
|
||||
}
|
||||
|
||||
if (ctx->entered_content_phase) {
|
||||
ngx_http_lua_finalize_request(r, rc);
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_http_lua_co_ctx_resume_helper(ngx_http_lua_co_ctx_t *coctx, int nrets)
|
||||
{
|
||||
ngx_connection_t *c;
|
||||
ngx_http_request_t *r;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_http_log_ctx_t *log_ctx;
|
||||
|
||||
r = coctx->data;
|
||||
c = r->connection;
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
|
||||
if (ctx == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (c->fd != (ngx_socket_t) -1) { /* not a fake connection */
|
||||
log_ctx = c->log->data;
|
||||
log_ctx->current_request = r;
|
||||
}
|
||||
|
||||
coctx->nrets = nrets;
|
||||
coctx->cleanup = NULL;
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
||||
"lua coctx resume handler: \"%V?%V\"", &r->uri, &r->args);
|
||||
|
||||
ctx->cur_co_ctx = coctx;
|
||||
|
||||
if (ctx->entered_content_phase) {
|
||||
(void) ngx_http_lua_co_ctx_resume(r);
|
||||
|
||||
} else {
|
||||
ctx->resume_handler = ngx_http_lua_co_ctx_resume;
|
||||
ngx_http_core_run_phases(r);
|
||||
}
|
||||
|
||||
ngx_http_run_posted_requests(c);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_get_lua_http10_buffering(ngx_http_request_t *r)
|
||||
{
|
||||
ngx_http_lua_loc_conf_t *llcf;
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
|
||||
return llcf->http10_buffering;
|
||||
}
|
||||
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,576 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_http_lua_args.h"
|
||||
#include "ngx_http_lua_util.h"
|
||||
|
||||
|
||||
static int ngx_http_lua_ngx_req_set_uri_args(lua_State *L);
|
||||
static int ngx_http_lua_ngx_req_get_post_args(lua_State *L);
|
||||
|
||||
|
||||
uintptr_t
|
||||
ngx_http_lua_escape_args(u_char *dst, u_char *src, size_t size)
|
||||
{
|
||||
ngx_uint_t n;
|
||||
static u_char hex[] = "0123456789ABCDEF";
|
||||
|
||||
/* %00-%20 %7F*/
|
||||
|
||||
static uint32_t escape[] = {
|
||||
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
|
||||
|
||||
/* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
|
||||
0x00000001, /* 0000 0000 0000 0000 0000 0000 0000 0001 */
|
||||
|
||||
/* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
|
||||
0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
|
||||
|
||||
/* ~}| {zyx wvut srqp onml kjih gfed cba` */
|
||||
0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */
|
||||
|
||||
0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
|
||||
0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
|
||||
0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
|
||||
0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
|
||||
};
|
||||
|
||||
if (dst == NULL) {
|
||||
|
||||
/* find the number of the characters to be escaped */
|
||||
|
||||
n = 0;
|
||||
|
||||
while (size) {
|
||||
if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
|
||||
n++;
|
||||
}
|
||||
|
||||
src++;
|
||||
size--;
|
||||
}
|
||||
|
||||
return (uintptr_t) n;
|
||||
}
|
||||
|
||||
while (size) {
|
||||
if (escape[*src >> 5] & (1 << (*src & 0x1f))) {
|
||||
*dst++ = '%';
|
||||
*dst++ = hex[*src >> 4];
|
||||
*dst++ = hex[*src & 0xf];
|
||||
src++;
|
||||
|
||||
} else {
|
||||
*dst++ = *src++;
|
||||
}
|
||||
|
||||
size--;
|
||||
}
|
||||
|
||||
return (uintptr_t) dst;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_http_lua_ngx_req_set_uri_args(lua_State *L)
|
||||
{
|
||||
ngx_http_request_t *r;
|
||||
ngx_str_t args;
|
||||
const char *msg;
|
||||
size_t len;
|
||||
u_char *p;
|
||||
uintptr_t escape;
|
||||
|
||||
if (lua_gettop(L) != 1) {
|
||||
return luaL_error(L, "expecting 1 argument but seen %d",
|
||||
lua_gettop(L));
|
||||
}
|
||||
|
||||
r = ngx_http_lua_get_req(L);
|
||||
if (r == NULL) {
|
||||
return luaL_error(L, "no request object found");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_fake_request(L, r);
|
||||
|
||||
switch (lua_type(L, 1)) {
|
||||
case LUA_TNUMBER:
|
||||
p = (u_char *) lua_tolstring(L, 1, &len);
|
||||
|
||||
args.data = ngx_palloc(r->pool, len);
|
||||
if (args.data == NULL) {
|
||||
return luaL_error(L, "no memory");
|
||||
}
|
||||
|
||||
ngx_memcpy(args.data, p, len);
|
||||
|
||||
args.len = len;
|
||||
break;
|
||||
|
||||
case LUA_TSTRING:
|
||||
p = (u_char *) lua_tolstring(L, 1, &len);
|
||||
|
||||
escape = ngx_http_lua_escape_args(NULL, p, len);
|
||||
if (escape > 0) {
|
||||
args.len = len + 2 * escape;
|
||||
args.data = ngx_palloc(r->pool, args.len);
|
||||
if (args.data == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_http_lua_escape_args(args.data, p, len);
|
||||
|
||||
} else {
|
||||
args.data = ngx_palloc(r->pool, len);
|
||||
if (args.data == NULL) {
|
||||
return luaL_error(L, "no memory");
|
||||
}
|
||||
|
||||
ngx_memcpy(args.data, p, len);
|
||||
|
||||
args.len = len;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case LUA_TTABLE:
|
||||
ngx_http_lua_process_args_option(r, L, 1, &args);
|
||||
|
||||
dd("args: %.*s", (int) args.len, args.data);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
msg = lua_pushfstring(L, "string, number, or table expected, "
|
||||
"but got %s", luaL_typename(L, 1));
|
||||
return luaL_argerror(L, 1, msg);
|
||||
}
|
||||
|
||||
dd("args: %.*s", (int) args.len, args.data);
|
||||
|
||||
r->args.data = args.data;
|
||||
r->args.len = args.len;
|
||||
|
||||
r->valid_unparsed_uri = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_http_lua_ngx_req_get_post_args(lua_State *L)
|
||||
{
|
||||
ngx_http_request_t *r;
|
||||
u_char *buf;
|
||||
int retval;
|
||||
size_t len;
|
||||
ngx_chain_t *cl;
|
||||
u_char *p;
|
||||
u_char *last;
|
||||
int n;
|
||||
int max;
|
||||
|
||||
n = lua_gettop(L);
|
||||
|
||||
if (n != 0 && n != 1) {
|
||||
return luaL_error(L, "expecting 0 or 1 arguments but seen %d", n);
|
||||
}
|
||||
|
||||
if (n == 1) {
|
||||
max = luaL_checkinteger(L, 1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
} else {
|
||||
max = NGX_HTTP_LUA_MAX_ARGS;
|
||||
}
|
||||
|
||||
r = ngx_http_lua_get_req(L);
|
||||
if (r == NULL) {
|
||||
return luaL_error(L, "no request object found");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_fake_request(L, r);
|
||||
|
||||
if (r->discard_body) {
|
||||
lua_createtable(L, 0, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (r->request_body == NULL) {
|
||||
return luaL_error(L, "no request body found; "
|
||||
"maybe you should turn on lua_need_request_body?");
|
||||
}
|
||||
|
||||
if (r->request_body->temp_file) {
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "request body in temp file not supported");
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (r->request_body->bufs == NULL) {
|
||||
lua_createtable(L, 0, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* we copy r->request_body->bufs over to buf to simplify
|
||||
* unescaping query arg keys and values */
|
||||
|
||||
len = 0;
|
||||
for (cl = r->request_body->bufs; cl; cl = cl->next) {
|
||||
len += cl->buf->last - cl->buf->pos;
|
||||
}
|
||||
|
||||
dd("post body length: %d", (int) len);
|
||||
|
||||
if (len == 0) {
|
||||
lua_createtable(L, 0, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
buf = ngx_palloc(r->pool, len);
|
||||
if (buf == NULL) {
|
||||
return luaL_error(L, "no memory");
|
||||
}
|
||||
|
||||
lua_createtable(L, 0, 4);
|
||||
|
||||
p = buf;
|
||||
for (cl = r->request_body->bufs; cl; cl = cl->next) {
|
||||
p = ngx_copy(p, cl->buf->pos, cl->buf->last - cl->buf->pos);
|
||||
}
|
||||
|
||||
dd("post body: %.*s", (int) len, buf);
|
||||
|
||||
last = buf + len;
|
||||
|
||||
retval = ngx_http_lua_parse_args(L, buf, last, max);
|
||||
|
||||
ngx_pfree(r->pool, buf);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_parse_args(lua_State *L, u_char *buf, u_char *last, int max)
|
||||
{
|
||||
u_char *p, *q;
|
||||
u_char *src, *dst;
|
||||
unsigned parsing_value;
|
||||
size_t len;
|
||||
int count = 0;
|
||||
int top;
|
||||
|
||||
top = lua_gettop(L);
|
||||
|
||||
p = buf;
|
||||
|
||||
parsing_value = 0;
|
||||
q = p;
|
||||
|
||||
while (p != last) {
|
||||
if (*p == '=' && ! parsing_value) {
|
||||
/* key data is between p and q */
|
||||
|
||||
src = q; dst = q;
|
||||
|
||||
ngx_http_lua_unescape_uri(&dst, &src, p - q,
|
||||
NGX_UNESCAPE_URI_COMPONENT);
|
||||
|
||||
dd("pushing key %.*s", (int) (dst - q), q);
|
||||
|
||||
/* push the key */
|
||||
lua_pushlstring(L, (char *) q, dst - q);
|
||||
|
||||
/* skip the current '=' char */
|
||||
p++;
|
||||
|
||||
q = p;
|
||||
parsing_value = 1;
|
||||
|
||||
} else if (*p == '&') {
|
||||
/* reached the end of a key or a value, just save it */
|
||||
src = q; dst = q;
|
||||
|
||||
ngx_http_lua_unescape_uri(&dst, &src, p - q,
|
||||
NGX_UNESCAPE_URI_COMPONENT);
|
||||
|
||||
dd("pushing key or value %.*s", (int) (dst - q), q);
|
||||
|
||||
/* push the value or key */
|
||||
lua_pushlstring(L, (char *) q, dst - q);
|
||||
|
||||
/* skip the current '&' char */
|
||||
p++;
|
||||
|
||||
q = p;
|
||||
|
||||
if (parsing_value) {
|
||||
/* end of the current pair's value */
|
||||
parsing_value = 0;
|
||||
|
||||
} else {
|
||||
/* the current parsing pair takes no value,
|
||||
* just push the value "true" */
|
||||
dd("pushing boolean true");
|
||||
|
||||
lua_pushboolean(L, 1);
|
||||
}
|
||||
|
||||
(void) lua_tolstring(L, -2, &len);
|
||||
|
||||
if (len == 0) {
|
||||
/* ignore empty string key pairs */
|
||||
dd("popping key and value...");
|
||||
lua_pop(L, 2);
|
||||
|
||||
} else {
|
||||
dd("setting table...");
|
||||
ngx_http_lua_set_multi_value_table(L, top);
|
||||
}
|
||||
|
||||
if (max > 0 && ++count == max) {
|
||||
lua_pushliteral(L, "truncated");
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
|
||||
"lua hit query args limit %d", max);
|
||||
return 2;
|
||||
}
|
||||
|
||||
} else {
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
if (p != q || parsing_value) {
|
||||
src = q; dst = q;
|
||||
|
||||
ngx_http_lua_unescape_uri(&dst, &src, p - q,
|
||||
NGX_UNESCAPE_URI_COMPONENT);
|
||||
|
||||
dd("pushing key or value %.*s", (int) (dst - q), q);
|
||||
|
||||
lua_pushlstring(L, (char *) q, dst - q);
|
||||
|
||||
if (!parsing_value) {
|
||||
dd("pushing boolean true...");
|
||||
lua_pushboolean(L, 1);
|
||||
}
|
||||
|
||||
(void) lua_tolstring(L, -2, &len);
|
||||
|
||||
if (len == 0) {
|
||||
/* ignore empty string key pairs */
|
||||
dd("popping key and value...");
|
||||
lua_pop(L, 2);
|
||||
|
||||
} else {
|
||||
dd("setting table...");
|
||||
ngx_http_lua_set_multi_value_table(L, top);
|
||||
}
|
||||
}
|
||||
|
||||
dd("gettop: %d", lua_gettop(L));
|
||||
dd("type: %s", lua_typename(L, lua_type(L, 1)));
|
||||
|
||||
if (lua_gettop(L) != top) {
|
||||
return luaL_error(L, "internal error: stack in bad state");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_http_lua_inject_req_args_api(lua_State *L)
|
||||
{
|
||||
lua_pushcfunction(L, ngx_http_lua_ngx_req_set_uri_args);
|
||||
lua_setfield(L, -2, "set_uri_args");
|
||||
|
||||
lua_pushcfunction(L, ngx_http_lua_ngx_req_get_post_args);
|
||||
lua_setfield(L, -2, "get_post_args");
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
ngx_http_lua_ffi_req_get_querystring_len(ngx_http_request_t *r)
|
||||
{
|
||||
return r->args.len;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_req_get_uri_args_count(ngx_http_request_t *r, int max,
|
||||
int *truncated)
|
||||
{
|
||||
int count;
|
||||
u_char *p, *last;
|
||||
|
||||
if (r->connection->fd == (ngx_socket_t) -1) {
|
||||
return NGX_HTTP_LUA_FFI_BAD_CONTEXT;
|
||||
}
|
||||
|
||||
*truncated = 0;
|
||||
|
||||
if (max < 0) {
|
||||
max = NGX_HTTP_LUA_MAX_ARGS;
|
||||
}
|
||||
|
||||
last = r->args.data + r->args.len;
|
||||
count = 0;
|
||||
|
||||
for (p = r->args.data; p != last; p++) {
|
||||
if (*p == '&') {
|
||||
if (count == 0) {
|
||||
count += 2;
|
||||
|
||||
} else {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count) {
|
||||
if (max > 0 && count > max) {
|
||||
count = max;
|
||||
*truncated = 1;
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua hit query args limit %d", max);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
if (r->args.len) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_req_get_uri_args(ngx_http_request_t *r, u_char *buf,
|
||||
ngx_http_lua_ffi_table_elt_t *out, int count)
|
||||
{
|
||||
int i, parsing_value = 0;
|
||||
u_char *last, *p, *q;
|
||||
u_char *src, *dst;
|
||||
|
||||
if (count <= 0) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_memcpy(buf, r->args.data, r->args.len);
|
||||
|
||||
i = 0;
|
||||
last = buf + r->args.len;
|
||||
p = buf;
|
||||
q = p;
|
||||
|
||||
while (p != last) {
|
||||
if (*p == '=' && !parsing_value) {
|
||||
/* key data is between p and q */
|
||||
|
||||
src = q; dst = q;
|
||||
|
||||
ngx_http_lua_unescape_uri(&dst, &src, p - q,
|
||||
NGX_UNESCAPE_URI_COMPONENT);
|
||||
|
||||
dd("saving key %.*s", (int) (dst - q), q);
|
||||
|
||||
out[i].key.data = q;
|
||||
out[i].key.len = (int) (dst - q);
|
||||
|
||||
/* skip the current '=' char */
|
||||
p++;
|
||||
|
||||
q = p;
|
||||
parsing_value = 1;
|
||||
|
||||
} else if (*p == '&') {
|
||||
/* reached the end of a key or a value, just save it */
|
||||
src = q; dst = q;
|
||||
|
||||
ngx_http_lua_unescape_uri(&dst, &src, p - q,
|
||||
NGX_UNESCAPE_URI_COMPONENT);
|
||||
|
||||
dd("pushing key or value %.*s", (int) (dst - q), q);
|
||||
|
||||
if (parsing_value) {
|
||||
/* end of the current pair's value */
|
||||
parsing_value = 0;
|
||||
|
||||
if (out[i].key.len) {
|
||||
out[i].value.data = q;
|
||||
out[i].value.len = (int) (dst - q);
|
||||
i++;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* the current parsing pair takes no value,
|
||||
* just push the value "true" */
|
||||
dd("pushing boolean true");
|
||||
|
||||
if (dst - q) {
|
||||
out[i].key.data = q;
|
||||
out[i].key.len = (int) (dst - q);
|
||||
out[i].value.len = -1;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == count) {
|
||||
return i;
|
||||
}
|
||||
|
||||
/* skip the current '&' char */
|
||||
p++;
|
||||
|
||||
q = p;
|
||||
|
||||
} else {
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
if (p != q || parsing_value) {
|
||||
src = q; dst = q;
|
||||
|
||||
ngx_http_lua_unescape_uri(&dst, &src, p - q,
|
||||
NGX_UNESCAPE_URI_COMPONENT);
|
||||
|
||||
dd("pushing key or value %.*s", (int) (dst - q), q);
|
||||
|
||||
if (parsing_value) {
|
||||
if (out[i].key.len) {
|
||||
out[i].value.data = q;
|
||||
out[i].value.len = (int) (dst - q);
|
||||
i++;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (dst - q) {
|
||||
out[i].key.data = q;
|
||||
out[i].key.len = (int) (dst - q);
|
||||
out[i].value.len = (int) -1;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_ARGS_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_ARGS_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
void ngx_http_lua_inject_req_args_api(lua_State *L);
|
||||
int ngx_http_lua_parse_args(lua_State *L, u_char *buf, u_char *last, int max);
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_ARGS_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,812 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_http_lua_cache.h"
|
||||
#include "ngx_http_lua_balancer.h"
|
||||
#include "ngx_http_lua_util.h"
|
||||
#include "ngx_http_lua_directive.h"
|
||||
|
||||
|
||||
struct ngx_http_lua_balancer_peer_data_s {
|
||||
/* the round robin data must be first */
|
||||
ngx_http_upstream_rr_peer_data_t rrp;
|
||||
|
||||
ngx_http_lua_srv_conf_t *conf;
|
||||
ngx_http_request_t *request;
|
||||
|
||||
ngx_uint_t more_tries;
|
||||
ngx_uint_t total_tries;
|
||||
|
||||
struct sockaddr *sockaddr;
|
||||
socklen_t socklen;
|
||||
|
||||
ngx_str_t *host;
|
||||
in_port_t port;
|
||||
|
||||
int last_peer_state;
|
||||
|
||||
#if !(HAVE_NGX_UPSTREAM_TIMEOUT_FIELDS)
|
||||
unsigned cloned_upstream_conf; /* :1 */
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
#if (NGX_HTTP_SSL)
|
||||
static ngx_int_t ngx_http_lua_balancer_set_session(ngx_peer_connection_t *pc,
|
||||
void *data);
|
||||
static void ngx_http_lua_balancer_save_session(ngx_peer_connection_t *pc,
|
||||
void *data);
|
||||
#endif
|
||||
static ngx_int_t ngx_http_lua_balancer_init(ngx_conf_t *cf,
|
||||
ngx_http_upstream_srv_conf_t *us);
|
||||
static ngx_int_t ngx_http_lua_balancer_init_peer(ngx_http_request_t *r,
|
||||
ngx_http_upstream_srv_conf_t *us);
|
||||
static ngx_int_t ngx_http_lua_balancer_get_peer(ngx_peer_connection_t *pc,
|
||||
void *data);
|
||||
static ngx_int_t ngx_http_lua_balancer_by_chunk(lua_State *L,
|
||||
ngx_http_request_t *r);
|
||||
static void ngx_http_lua_balancer_free_peer(ngx_peer_connection_t *pc,
|
||||
void *data, ngx_uint_t state);
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_balancer_handler_file(ngx_http_request_t *r,
|
||||
ngx_http_lua_srv_conf_t *lscf, lua_State *L)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
|
||||
rc = ngx_http_lua_cache_loadfile(r->connection->log, L,
|
||||
lscf->balancer.src.data,
|
||||
&lscf->balancer.src_ref,
|
||||
lscf->balancer.src_key);
|
||||
if (rc != NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* make sure we have a valid code chunk */
|
||||
ngx_http_lua_assert(lua_isfunction(L, -1));
|
||||
|
||||
return ngx_http_lua_balancer_by_chunk(L, r);
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_balancer_handler_inline(ngx_http_request_t *r,
|
||||
ngx_http_lua_srv_conf_t *lscf, lua_State *L)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
|
||||
rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L,
|
||||
lscf->balancer.src.data,
|
||||
lscf->balancer.src.len,
|
||||
&lscf->balancer.src_ref,
|
||||
lscf->balancer.src_key,
|
||||
(const char *) lscf->balancer.chunkname);
|
||||
if (rc != NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* make sure we have a valid code chunk */
|
||||
ngx_http_lua_assert(lua_isfunction(L, -1));
|
||||
|
||||
return ngx_http_lua_balancer_by_chunk(L, r);
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
ngx_http_lua_balancer_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf)
|
||||
{
|
||||
char *rv;
|
||||
ngx_conf_t save;
|
||||
|
||||
save = *cf;
|
||||
cf->handler = ngx_http_lua_balancer_by_lua;
|
||||
cf->handler_conf = conf;
|
||||
|
||||
rv = ngx_http_lua_conf_lua_block_parse(cf, cmd);
|
||||
|
||||
*cf = save;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
ngx_http_lua_balancer_by_lua(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf)
|
||||
{
|
||||
size_t chunkname_len;
|
||||
u_char *chunkname;
|
||||
u_char *cache_key = NULL;
|
||||
u_char *name;
|
||||
ngx_str_t *value;
|
||||
ngx_http_lua_srv_conf_t *lscf = conf;
|
||||
|
||||
ngx_http_upstream_srv_conf_t *uscf;
|
||||
|
||||
dd("enter");
|
||||
|
||||
/* must specify a content handler */
|
||||
if (cmd->post == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
if (lscf->balancer.handler) {
|
||||
return "is duplicate";
|
||||
}
|
||||
|
||||
value = cf->args->elts;
|
||||
|
||||
lscf->balancer.handler = (ngx_http_lua_srv_conf_handler_pt) cmd->post;
|
||||
|
||||
if (cmd->post == ngx_http_lua_balancer_handler_file) {
|
||||
/* Lua code in an external file */
|
||||
name = ngx_http_lua_rebase_path(cf->pool, value[1].data,
|
||||
value[1].len);
|
||||
if (name == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
cache_key = ngx_http_lua_gen_file_cache_key(cf, value[1].data,
|
||||
value[1].len);
|
||||
if (cache_key == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
lscf->balancer.src.data = name;
|
||||
lscf->balancer.src.len = ngx_strlen(name);
|
||||
|
||||
} else {
|
||||
cache_key = ngx_http_lua_gen_chunk_cache_key(cf, "balancer_by_lua",
|
||||
value[1].data,
|
||||
value[1].len);
|
||||
if (cache_key == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
chunkname = ngx_http_lua_gen_chunk_name(cf, "balancer_by_lua",
|
||||
sizeof("balancer_by_lua") - 1,
|
||||
&chunkname_len);
|
||||
if (chunkname == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
/* Don't eval nginx variables for inline lua code */
|
||||
lscf->balancer.src = value[1];
|
||||
lscf->balancer.chunkname = chunkname;
|
||||
}
|
||||
|
||||
lscf->balancer.src_key = cache_key;
|
||||
|
||||
uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module);
|
||||
|
||||
if (uscf->peer.init_upstream) {
|
||||
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
|
||||
"load balancing method redefined");
|
||||
}
|
||||
|
||||
uscf->peer.init_upstream = ngx_http_lua_balancer_init;
|
||||
|
||||
uscf->flags = NGX_HTTP_UPSTREAM_CREATE
|
||||
|NGX_HTTP_UPSTREAM_WEIGHT
|
||||
|NGX_HTTP_UPSTREAM_MAX_FAILS
|
||||
|NGX_HTTP_UPSTREAM_FAIL_TIMEOUT
|
||||
|NGX_HTTP_UPSTREAM_DOWN;
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_lua_balancer_init(ngx_conf_t *cf,
|
||||
ngx_http_upstream_srv_conf_t *us)
|
||||
{
|
||||
if (ngx_http_upstream_init_round_robin(cf, us) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
/* this callback is called upon individual requests */
|
||||
us->peer.init = ngx_http_lua_balancer_init_peer;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_lua_balancer_init_peer(ngx_http_request_t *r,
|
||||
ngx_http_upstream_srv_conf_t *us)
|
||||
{
|
||||
ngx_http_lua_srv_conf_t *bcf;
|
||||
ngx_http_lua_balancer_peer_data_t *bp;
|
||||
|
||||
bp = ngx_pcalloc(r->pool, sizeof(ngx_http_lua_balancer_peer_data_t));
|
||||
if (bp == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
r->upstream->peer.data = &bp->rrp;
|
||||
|
||||
if (ngx_http_upstream_init_round_robin_peer(r, us) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
r->upstream->peer.get = ngx_http_lua_balancer_get_peer;
|
||||
r->upstream->peer.free = ngx_http_lua_balancer_free_peer;
|
||||
|
||||
#if (NGX_HTTP_SSL)
|
||||
r->upstream->peer.set_session = ngx_http_lua_balancer_set_session;
|
||||
r->upstream->peer.save_session = ngx_http_lua_balancer_save_session;
|
||||
#endif
|
||||
|
||||
bcf = ngx_http_conf_upstream_srv_conf(us, ngx_http_lua_module);
|
||||
|
||||
bp->conf = bcf;
|
||||
bp->request = r;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_lua_balancer_get_peer(ngx_peer_connection_t *pc, void *data)
|
||||
{
|
||||
lua_State *L;
|
||||
ngx_int_t rc;
|
||||
ngx_http_request_t *r;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_http_lua_srv_conf_t *lscf;
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
ngx_http_lua_balancer_peer_data_t *bp = data;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
|
||||
"lua balancer peer, tries: %ui", pc->tries);
|
||||
|
||||
lscf = bp->conf;
|
||||
|
||||
r = bp->request;
|
||||
|
||||
ngx_http_lua_assert(lscf->balancer.handler && r);
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
|
||||
if (ctx == NULL) {
|
||||
ctx = ngx_http_lua_create_ctx(r);
|
||||
if (ctx == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
L = ngx_http_lua_get_lua_vm(r, ctx);
|
||||
|
||||
} else {
|
||||
L = ngx_http_lua_get_lua_vm(r, ctx);
|
||||
|
||||
dd("reset ctx");
|
||||
ngx_http_lua_reset_ctx(r, L, ctx);
|
||||
}
|
||||
|
||||
ctx->context = NGX_HTTP_LUA_CONTEXT_BALANCER;
|
||||
|
||||
bp->sockaddr = NULL;
|
||||
bp->socklen = 0;
|
||||
bp->more_tries = 0;
|
||||
bp->total_tries++;
|
||||
|
||||
lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
|
||||
|
||||
/* balancer_by_lua does not support yielding and
|
||||
* there cannot be any conflicts among concurrent requests,
|
||||
* thus it is safe to store the peer data in the main conf.
|
||||
*/
|
||||
lmcf->balancer_peer_data = bp;
|
||||
|
||||
rc = lscf->balancer.handler(r, lscf, L);
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ctx->exited && ctx->exit_code != NGX_OK) {
|
||||
rc = ctx->exit_code;
|
||||
if (rc == NGX_ERROR
|
||||
|| rc == NGX_BUSY
|
||||
|| rc == NGX_DECLINED
|
||||
#ifdef HAVE_BALANCER_STATUS_CODE_PATCH
|
||||
|| rc >= NGX_HTTP_SPECIAL_RESPONSE
|
||||
#endif
|
||||
) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (rc > NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (bp->sockaddr && bp->socklen) {
|
||||
pc->sockaddr = bp->sockaddr;
|
||||
pc->socklen = bp->socklen;
|
||||
pc->cached = 0;
|
||||
pc->connection = NULL;
|
||||
pc->name = bp->host;
|
||||
|
||||
bp->rrp.peers->single = 0;
|
||||
|
||||
if (bp->more_tries) {
|
||||
r->upstream->peer.tries += bp->more_tries;
|
||||
}
|
||||
|
||||
dd("tries: %d", (int) r->upstream->peer.tries);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
return ngx_http_upstream_get_round_robin_peer(pc, &bp->rrp);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_lua_balancer_by_chunk(lua_State *L, ngx_http_request_t *r)
|
||||
{
|
||||
u_char *err_msg;
|
||||
size_t len;
|
||||
ngx_int_t rc;
|
||||
|
||||
/* init nginx context in Lua VM */
|
||||
ngx_http_lua_set_req(L, r);
|
||||
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
ngx_http_lua_create_new_globals_table(L, 0 /* narr */, 1 /* nrec */);
|
||||
|
||||
/* {{{ make new env inheriting main thread's globals table */
|
||||
lua_createtable(L, 0, 1 /* nrec */); /* the metatable for the new env */
|
||||
ngx_http_lua_get_globals_table(L);
|
||||
lua_setfield(L, -2, "__index");
|
||||
lua_setmetatable(L, -2); /* setmetatable({}, {__index = _G}) */
|
||||
/* }}} */
|
||||
|
||||
lua_setfenv(L, -2); /* set new running env for the code closure */
|
||||
#endif /* OPENRESTY_LUAJIT */
|
||||
|
||||
lua_pushcfunction(L, ngx_http_lua_traceback);
|
||||
lua_insert(L, 1); /* put it under chunk and args */
|
||||
|
||||
/* protected call user code */
|
||||
rc = lua_pcall(L, 0, 1, 1);
|
||||
|
||||
lua_remove(L, 1); /* remove traceback function */
|
||||
|
||||
dd("rc == %d", (int) rc);
|
||||
|
||||
if (rc != 0) {
|
||||
/* error occurred when running loaded code */
|
||||
err_msg = (u_char *) lua_tolstring(L, -1, &len);
|
||||
|
||||
if (err_msg == NULL) {
|
||||
err_msg = (u_char *) "unknown reason";
|
||||
len = sizeof("unknown reason") - 1;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"failed to run balancer_by_lua*: %*s", len, err_msg);
|
||||
|
||||
lua_settop(L, 0); /* clear remaining elems on stack */
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
lua_settop(L, 0); /* clear remaining elems on stack */
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_http_lua_balancer_free_peer(ngx_peer_connection_t *pc, void *data,
|
||||
ngx_uint_t state)
|
||||
{
|
||||
ngx_http_lua_balancer_peer_data_t *bp = data;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
|
||||
"lua balancer free peer, tries: %ui", pc->tries);
|
||||
|
||||
if (bp->sockaddr && bp->socklen) {
|
||||
bp->last_peer_state = (int) state;
|
||||
|
||||
if (pc->tries) {
|
||||
pc->tries--;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* fallback */
|
||||
|
||||
ngx_http_upstream_free_round_robin_peer(pc, data, state);
|
||||
}
|
||||
|
||||
|
||||
#if (NGX_HTTP_SSL)
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_lua_balancer_set_session(ngx_peer_connection_t *pc, void *data)
|
||||
{
|
||||
ngx_http_lua_balancer_peer_data_t *bp = data;
|
||||
|
||||
if (bp->sockaddr && bp->socklen) {
|
||||
/* TODO */
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
return ngx_http_upstream_set_round_robin_peer_session(pc, &bp->rrp);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_http_lua_balancer_save_session(ngx_peer_connection_t *pc, void *data)
|
||||
{
|
||||
ngx_http_lua_balancer_peer_data_t *bp = data;
|
||||
|
||||
if (bp->sockaddr && bp->socklen) {
|
||||
/* TODO */
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_http_upstream_save_round_robin_peer_session(pc, &bp->rrp);
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_balancer_set_current_peer(ngx_http_request_t *r,
|
||||
const u_char *addr, size_t addr_len, int port, char **err)
|
||||
{
|
||||
ngx_url_t url;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_http_upstream_t *u;
|
||||
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
ngx_http_lua_balancer_peer_data_t *bp;
|
||||
|
||||
if (r == NULL) {
|
||||
*err = "no request found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
u = r->upstream;
|
||||
|
||||
if (u == NULL) {
|
||||
*err = "no upstream found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
if (ctx == NULL) {
|
||||
*err = "no ctx found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if ((ctx->context & NGX_HTTP_LUA_CONTEXT_BALANCER) == 0) {
|
||||
*err = "API disabled in the current context";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
|
||||
|
||||
/* we cannot read r->upstream->peer.data here directly because
|
||||
* it could be overridden by other modules like
|
||||
* ngx_http_upstream_keepalive_module.
|
||||
*/
|
||||
bp = lmcf->balancer_peer_data;
|
||||
if (bp == NULL) {
|
||||
*err = "no upstream peer data found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_memzero(&url, sizeof(ngx_url_t));
|
||||
|
||||
url.url.data = ngx_palloc(r->pool, addr_len);
|
||||
if (url.url.data == NULL) {
|
||||
*err = "no memory";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_memcpy(url.url.data, addr, addr_len);
|
||||
|
||||
url.url.len = addr_len;
|
||||
url.default_port = (in_port_t) port;
|
||||
url.uri_part = 0;
|
||||
url.no_resolve = 1;
|
||||
|
||||
if (ngx_parse_url(r->pool, &url) != NGX_OK) {
|
||||
if (url.err) {
|
||||
*err = url.err;
|
||||
}
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (url.addrs && url.addrs[0].sockaddr) {
|
||||
bp->sockaddr = url.addrs[0].sockaddr;
|
||||
bp->socklen = url.addrs[0].socklen;
|
||||
bp->host = &url.addrs[0].name;
|
||||
|
||||
} else {
|
||||
*err = "no host allowed";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_balancer_set_timeouts(ngx_http_request_t *r,
|
||||
long connect_timeout, long send_timeout, long read_timeout,
|
||||
char **err)
|
||||
{
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_http_upstream_t *u;
|
||||
|
||||
#if !(HAVE_NGX_UPSTREAM_TIMEOUT_FIELDS)
|
||||
ngx_http_upstream_conf_t *ucf;
|
||||
#endif
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
ngx_http_lua_balancer_peer_data_t *bp;
|
||||
|
||||
if (r == NULL) {
|
||||
*err = "no request found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
u = r->upstream;
|
||||
|
||||
if (u == NULL) {
|
||||
*err = "no upstream found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
if (ctx == NULL) {
|
||||
*err = "no ctx found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if ((ctx->context & NGX_HTTP_LUA_CONTEXT_BALANCER) == 0) {
|
||||
*err = "API disabled in the current context";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
|
||||
|
||||
bp = lmcf->balancer_peer_data;
|
||||
if (bp == NULL) {
|
||||
*err = "no upstream peer data found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
#if !(HAVE_NGX_UPSTREAM_TIMEOUT_FIELDS)
|
||||
if (!bp->cloned_upstream_conf) {
|
||||
/* we clone the upstream conf for the current request so that
|
||||
* we do not affect other requests at all. */
|
||||
|
||||
ucf = ngx_palloc(r->pool, sizeof(ngx_http_upstream_conf_t));
|
||||
|
||||
if (ucf == NULL) {
|
||||
*err = "no memory";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_memcpy(ucf, u->conf, sizeof(ngx_http_upstream_conf_t));
|
||||
|
||||
u->conf = ucf;
|
||||
bp->cloned_upstream_conf = 1;
|
||||
|
||||
} else {
|
||||
ucf = u->conf;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (connect_timeout > 0) {
|
||||
#if (HAVE_NGX_UPSTREAM_TIMEOUT_FIELDS)
|
||||
u->connect_timeout = (ngx_msec_t) connect_timeout;
|
||||
#else
|
||||
ucf->connect_timeout = (ngx_msec_t) connect_timeout;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (send_timeout > 0) {
|
||||
#if (HAVE_NGX_UPSTREAM_TIMEOUT_FIELDS)
|
||||
u->send_timeout = (ngx_msec_t) send_timeout;
|
||||
#else
|
||||
ucf->send_timeout = (ngx_msec_t) send_timeout;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (read_timeout > 0) {
|
||||
#if (HAVE_NGX_UPSTREAM_TIMEOUT_FIELDS)
|
||||
u->read_timeout = (ngx_msec_t) read_timeout;
|
||||
#else
|
||||
ucf->read_timeout = (ngx_msec_t) read_timeout;
|
||||
#endif
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_balancer_set_more_tries(ngx_http_request_t *r,
|
||||
int count, char **err)
|
||||
{
|
||||
#if (nginx_version >= 1007005)
|
||||
ngx_uint_t max_tries, total;
|
||||
#endif
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_http_upstream_t *u;
|
||||
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
ngx_http_lua_balancer_peer_data_t *bp;
|
||||
|
||||
if (r == NULL) {
|
||||
*err = "no request found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
u = r->upstream;
|
||||
|
||||
if (u == NULL) {
|
||||
*err = "no upstream found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
if (ctx == NULL) {
|
||||
*err = "no ctx found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if ((ctx->context & NGX_HTTP_LUA_CONTEXT_BALANCER) == 0) {
|
||||
*err = "API disabled in the current context";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
|
||||
|
||||
bp = lmcf->balancer_peer_data;
|
||||
if (bp == NULL) {
|
||||
*err = "no upstream peer data found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
#if (nginx_version >= 1007005)
|
||||
max_tries = r->upstream->conf->next_upstream_tries;
|
||||
total = bp->total_tries + r->upstream->peer.tries - 1;
|
||||
|
||||
if (max_tries && total + count > max_tries) {
|
||||
count = max_tries - total;
|
||||
*err = "reduced tries due to limit";
|
||||
|
||||
} else {
|
||||
*err = NULL;
|
||||
}
|
||||
#else
|
||||
*err = NULL;
|
||||
#endif
|
||||
|
||||
bp->more_tries = count;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_balancer_get_last_failure(ngx_http_request_t *r,
|
||||
int *status, char **err)
|
||||
{
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_http_upstream_t *u;
|
||||
ngx_http_upstream_state_t *state;
|
||||
|
||||
ngx_http_lua_balancer_peer_data_t *bp;
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
|
||||
if (r == NULL) {
|
||||
*err = "no request found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
u = r->upstream;
|
||||
|
||||
if (u == NULL) {
|
||||
*err = "no upstream found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
if (ctx == NULL) {
|
||||
*err = "no ctx found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if ((ctx->context & NGX_HTTP_LUA_CONTEXT_BALANCER) == 0) {
|
||||
*err = "API disabled in the current context";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
|
||||
|
||||
bp = lmcf->balancer_peer_data;
|
||||
if (bp == NULL) {
|
||||
*err = "no upstream peer data found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (r->upstream_states && r->upstream_states->nelts > 1) {
|
||||
state = r->upstream_states->elts;
|
||||
*status = (int) state[r->upstream_states->nelts - 2].status;
|
||||
|
||||
} else {
|
||||
*status = 0;
|
||||
}
|
||||
|
||||
return bp->last_peer_state;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_balancer_recreate_request(ngx_http_request_t *r,
|
||||
char **err)
|
||||
{
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_http_upstream_t *u;
|
||||
|
||||
if (r == NULL) {
|
||||
*err = "no request found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
u = r->upstream;
|
||||
|
||||
if (u == NULL) {
|
||||
*err = "no upstream found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
if (ctx == NULL) {
|
||||
*err = "no ctx found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if ((ctx->context & NGX_HTTP_LUA_CONTEXT_BALANCER) == 0) {
|
||||
*err = "API disabled in the current context";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
/* u->create_request can not be NULL since we are in balancer phase */
|
||||
ngx_http_lua_assert(u->create_request != NULL);
|
||||
|
||||
*err = NULL;
|
||||
|
||||
if (u->request_bufs != NULL && u->request_bufs != r->request_body->bufs) {
|
||||
/* u->request_bufs already contains a valid request buffer
|
||||
* remove it from chain first
|
||||
*/
|
||||
u->request_bufs = u->request_bufs->next;
|
||||
}
|
||||
|
||||
return u->create_request(r);
|
||||
}
|
||||
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,27 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_BALANCER_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_BALANCER_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
ngx_int_t ngx_http_lua_balancer_handler_inline(ngx_http_request_t *r,
|
||||
ngx_http_lua_srv_conf_t *lscf, lua_State *L);
|
||||
|
||||
ngx_int_t ngx_http_lua_balancer_handler_file(ngx_http_request_t *r,
|
||||
ngx_http_lua_srv_conf_t *lscf, lua_State *L);
|
||||
|
||||
char *ngx_http_lua_balancer_by_lua(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
|
||||
char *ngx_http_lua_balancer_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_BALANCER_H_INCLUDED_ */
|
|
@ -0,0 +1,703 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_http_lua_bodyfilterby.h"
|
||||
#include "ngx_http_lua_exception.h"
|
||||
#include "ngx_http_lua_util.h"
|
||||
#include "ngx_http_lua_pcrefix.h"
|
||||
#include "ngx_http_lua_log.h"
|
||||
#include "ngx_http_lua_cache.h"
|
||||
#include "ngx_http_lua_headers.h"
|
||||
#include "ngx_http_lua_string.h"
|
||||
#include "ngx_http_lua_misc.h"
|
||||
#include "ngx_http_lua_consts.h"
|
||||
#include "ngx_http_lua_output.h"
|
||||
|
||||
|
||||
static void ngx_http_lua_body_filter_by_lua_env(lua_State *L,
|
||||
ngx_http_request_t *r, ngx_chain_t *in);
|
||||
static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
|
||||
|
||||
|
||||
/**
|
||||
* Set environment table for the given code closure.
|
||||
*
|
||||
* Before:
|
||||
* | code closure | <- top
|
||||
* | ... |
|
||||
*
|
||||
* After:
|
||||
* | code closure | <- top
|
||||
* | ... |
|
||||
* */
|
||||
static void
|
||||
ngx_http_lua_body_filter_by_lua_env(lua_State *L, ngx_http_request_t *r,
|
||||
ngx_chain_t *in)
|
||||
{
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
|
||||
ngx_http_lua_set_req(L, r);
|
||||
|
||||
lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
|
||||
lmcf->body_filter_chain = in;
|
||||
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
/**
|
||||
* we want to create empty environment for current script
|
||||
*
|
||||
* setmetatable({}, {__index = _G})
|
||||
*
|
||||
* if a function or symbol is not defined in our env, __index will lookup
|
||||
* in the global env.
|
||||
*
|
||||
* all variables created in the script-env will be thrown away at the end
|
||||
* of the script run.
|
||||
* */
|
||||
ngx_http_lua_create_new_globals_table(L, 0 /* narr */, 1 /* nrec */);
|
||||
|
||||
/* {{{ make new env inheriting main thread's globals table */
|
||||
lua_createtable(L, 0, 1 /* nrec */); /* the metatable for the new
|
||||
env */
|
||||
ngx_http_lua_get_globals_table(L);
|
||||
lua_setfield(L, -2, "__index");
|
||||
lua_setmetatable(L, -2); /* setmetatable({}, {__index = _G}) */
|
||||
/* }}} */
|
||||
|
||||
lua_setfenv(L, -2); /* set new running env for the code closure */
|
||||
#endif /* OPENRESTY_LUAJIT */
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_body_filter_by_chunk(lua_State *L, ngx_http_request_t *r,
|
||||
ngx_chain_t *in)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
u_char *err_msg;
|
||||
size_t len;
|
||||
#if (NGX_PCRE)
|
||||
ngx_pool_t *old_pool;
|
||||
#endif
|
||||
|
||||
dd("initialize nginx context in Lua VM, code chunk at stack top sp = 1");
|
||||
ngx_http_lua_body_filter_by_lua_env(L, r, in);
|
||||
|
||||
#if (NGX_PCRE)
|
||||
/* XXX: work-around to nginx regex subsystem */
|
||||
old_pool = ngx_http_lua_pcre_malloc_init(r->pool);
|
||||
#endif
|
||||
|
||||
lua_pushcfunction(L, ngx_http_lua_traceback);
|
||||
lua_insert(L, 1); /* put it under chunk and args */
|
||||
|
||||
dd("protected call user code");
|
||||
rc = lua_pcall(L, 0, 1, 1);
|
||||
|
||||
lua_remove(L, 1); /* remove traceback function */
|
||||
|
||||
#if (NGX_PCRE)
|
||||
/* XXX: work-around to nginx regex subsystem */
|
||||
ngx_http_lua_pcre_malloc_done(old_pool);
|
||||
#endif
|
||||
|
||||
if (rc != 0) {
|
||||
|
||||
/* error occurred */
|
||||
err_msg = (u_char *) lua_tolstring(L, -1, &len);
|
||||
|
||||
if (err_msg == NULL) {
|
||||
err_msg = (u_char *) "unknown reason";
|
||||
len = sizeof("unknown reason") - 1;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"failed to run body_filter_by_lua*: %*s", len, err_msg);
|
||||
|
||||
lua_settop(L, 0); /* clear remaining elems on stack */
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
/* rc == 0 */
|
||||
|
||||
rc = (ngx_int_t) lua_tointeger(L, -1);
|
||||
|
||||
dd("got return value: %d", (int) rc);
|
||||
|
||||
lua_settop(L, 0);
|
||||
|
||||
if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_body_filter_inline(ngx_http_request_t *r, ngx_chain_t *in)
|
||||
{
|
||||
lua_State *L;
|
||||
ngx_int_t rc;
|
||||
ngx_http_lua_loc_conf_t *llcf;
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
|
||||
L = ngx_http_lua_get_lua_vm(r, NULL);
|
||||
|
||||
/* load Lua inline script (w/ cache) sp = 1 */
|
||||
rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L,
|
||||
llcf->body_filter_src.value.data,
|
||||
llcf->body_filter_src.value.len,
|
||||
&llcf->body_filter_src_ref,
|
||||
llcf->body_filter_src_key,
|
||||
(const char *)
|
||||
llcf->body_filter_chunkname);
|
||||
if (rc != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
rc = ngx_http_lua_body_filter_by_chunk(L, r, in);
|
||||
|
||||
dd("body filter by chunk returns %d", (int) rc);
|
||||
|
||||
if (rc != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_body_filter_file(ngx_http_request_t *r, ngx_chain_t *in)
|
||||
{
|
||||
lua_State *L;
|
||||
ngx_int_t rc;
|
||||
u_char *script_path;
|
||||
ngx_http_lua_loc_conf_t *llcf;
|
||||
ngx_str_t eval_src;
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
|
||||
/* Eval nginx variables in code path string first */
|
||||
if (ngx_http_complex_value(r, &llcf->body_filter_src, &eval_src)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
script_path = ngx_http_lua_rebase_path(r->pool, eval_src.data,
|
||||
eval_src.len);
|
||||
|
||||
if (script_path == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
L = ngx_http_lua_get_lua_vm(r, NULL);
|
||||
|
||||
/* load Lua script file (w/ cache) sp = 1 */
|
||||
rc = ngx_http_lua_cache_loadfile(r->connection->log, L, script_path,
|
||||
&llcf->body_filter_src_ref,
|
||||
llcf->body_filter_src_key);
|
||||
if (rc != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
/* make sure we have a valid code chunk */
|
||||
ngx_http_lua_assert(lua_isfunction(L, -1));
|
||||
|
||||
rc = ngx_http_lua_body_filter_by_chunk(L, r, in);
|
||||
|
||||
if (rc != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
|
||||
{
|
||||
ngx_http_lua_loc_conf_t *llcf;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_int_t rc;
|
||||
uint16_t old_context;
|
||||
ngx_pool_cleanup_t *cln;
|
||||
ngx_chain_t *out;
|
||||
ngx_chain_t *cl, *ln;
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua body filter for user lua code, uri \"%V\"", &r->uri);
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
|
||||
if (llcf->body_filter_handler == NULL || r->header_only) {
|
||||
dd("no body filter handler found");
|
||||
return ngx_http_next_body_filter(r, in);
|
||||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
|
||||
dd("ctx = %p", ctx);
|
||||
|
||||
if (ctx == NULL) {
|
||||
ctx = ngx_http_lua_create_ctx(r);
|
||||
if (ctx == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->seen_last_in_filter) {
|
||||
for (/* void */; in; in = in->next) {
|
||||
dd("mark the buf as consumed: %d", (int) ngx_buf_size(in->buf));
|
||||
in->buf->pos = in->buf->last;
|
||||
in->buf->file_pos = in->buf->file_last;
|
||||
}
|
||||
|
||||
in = NULL;
|
||||
|
||||
/* continue to call ngx_http_next_body_filter to process cached data */
|
||||
}
|
||||
|
||||
if (in != NULL
|
||||
&& ngx_chain_add_copy(r->pool, &ctx->filter_in_bufs, in) != NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ctx->filter_busy_bufs != NULL
|
||||
&& (r->connection->buffered
|
||||
& (NGX_HTTP_LOWLEVEL_BUFFERED | NGX_LOWLEVEL_BUFFERED)))
|
||||
{
|
||||
/* Socket write buffer was full on last write.
|
||||
* Try to write the remain data, if still can not write
|
||||
* do not execute body_filter_by_lua otherwise the `in` chain will be
|
||||
* replaced by new content from lua and buf of `in` mark as consumed.
|
||||
* And then ngx_output_chain will call the filter chain again which
|
||||
* make all the data cached in the memory and long ngx_chain_t link
|
||||
* cause CPU 100%.
|
||||
*/
|
||||
rc = ngx_http_next_body_filter(r, NULL);
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
out = NULL;
|
||||
ngx_chain_update_chains(r->pool,
|
||||
&ctx->free_bufs, &ctx->filter_busy_bufs, &out,
|
||||
(ngx_buf_tag_t) &ngx_http_lua_body_filter);
|
||||
if (rc != NGX_OK
|
||||
&& ctx->filter_busy_bufs != NULL
|
||||
&& (r->connection->buffered
|
||||
& (NGX_HTTP_LOWLEVEL_BUFFERED | NGX_LOWLEVEL_BUFFERED)))
|
||||
{
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"waiting body filter busy buffer to be sent");
|
||||
return NGX_AGAIN;
|
||||
}
|
||||
|
||||
/* continue to process bufs in ctx->filter_in_bufs */
|
||||
}
|
||||
|
||||
if (ctx->cleanup == NULL) {
|
||||
cln = ngx_pool_cleanup_add(r->pool, 0);
|
||||
if (cln == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
cln->handler = ngx_http_lua_request_cleanup_handler;
|
||||
cln->data = ctx;
|
||||
ctx->cleanup = &cln->handler;
|
||||
}
|
||||
|
||||
old_context = ctx->context;
|
||||
ctx->context = NGX_HTTP_LUA_CONTEXT_BODY_FILTER;
|
||||
|
||||
in = ctx->filter_in_bufs;
|
||||
ctx->filter_in_bufs = NULL;
|
||||
|
||||
if (in != NULL) {
|
||||
dd("calling body filter handler");
|
||||
rc = llcf->body_filter_handler(r, in);
|
||||
|
||||
dd("calling body filter handler returned %d", (int) rc);
|
||||
|
||||
ctx->context = old_context;
|
||||
|
||||
if (rc != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
|
||||
|
||||
/* lmcf->body_filter_chain is the new buffer chain if
|
||||
* body_filter_by_lua set new body content via ngx.arg[1] = new_content
|
||||
* otherwise it is the original `in` buffer chain.
|
||||
*/
|
||||
out = lmcf->body_filter_chain;
|
||||
|
||||
if (in != out) {
|
||||
/* content of body was replaced in
|
||||
* ngx_http_lua_body_filter_param_set and the buffers was marked
|
||||
* as consumed.
|
||||
*/
|
||||
for (cl = in; cl != NULL; cl = ln) {
|
||||
ln = cl->next;
|
||||
ngx_free_chain(r->pool, cl);
|
||||
}
|
||||
|
||||
if (out == NULL) {
|
||||
/* do not forward NULL to the next filters because the input is
|
||||
* not NULL */
|
||||
return NGX_OK;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
out = NULL;
|
||||
}
|
||||
|
||||
rc = ngx_http_next_body_filter(r, out);
|
||||
if (rc == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_chain_update_chains(r->pool,
|
||||
&ctx->free_bufs, &ctx->filter_busy_bufs, &out,
|
||||
(ngx_buf_tag_t) &ngx_http_lua_body_filter);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_body_filter_init(void)
|
||||
{
|
||||
dd("calling body filter init");
|
||||
ngx_http_next_body_filter = ngx_http_top_body_filter;
|
||||
ngx_http_top_body_filter = ngx_http_lua_body_filter;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_get_body_filter_param_eof(ngx_http_request_t *r)
|
||||
{
|
||||
ngx_chain_t *cl;
|
||||
ngx_chain_t *in;
|
||||
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
|
||||
lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
|
||||
in = lmcf->body_filter_chain;
|
||||
|
||||
/* asking for the eof argument */
|
||||
|
||||
for (cl = in; cl; cl = cl->next) {
|
||||
if (cl->buf->last_buf || cl->buf->last_in_chain) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_get_body_filter_param_body(ngx_http_request_t *r,
|
||||
u_char **data_p, size_t *len_p)
|
||||
{
|
||||
size_t size;
|
||||
ngx_chain_t *cl;
|
||||
ngx_buf_t *b;
|
||||
ngx_chain_t *in;
|
||||
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
|
||||
lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
|
||||
in = lmcf->body_filter_chain;
|
||||
|
||||
size = 0;
|
||||
|
||||
if (in == NULL) {
|
||||
/* being a cleared chain on the Lua land */
|
||||
*len_p = 0;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (in->next == NULL) {
|
||||
|
||||
dd("seen only single buffer");
|
||||
|
||||
b = in->buf;
|
||||
*data_p = b->pos;
|
||||
*len_p = b->last - b->pos;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
dd("seen multiple buffers");
|
||||
|
||||
for (cl = in; cl; cl = cl->next) {
|
||||
b = cl->buf;
|
||||
|
||||
size += b->last - b->pos;
|
||||
|
||||
if (b->last_buf || b->last_in_chain) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* the buf is need and is not allocated from Lua land yet, return with
|
||||
* the actual size */
|
||||
*len_p = size;
|
||||
return NGX_AGAIN;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_copy_body_filter_param_body(ngx_http_request_t *r,
|
||||
u_char *data)
|
||||
{
|
||||
u_char *p;
|
||||
ngx_chain_t *cl;
|
||||
ngx_buf_t *b;
|
||||
ngx_chain_t *in;
|
||||
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
|
||||
lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
|
||||
in = lmcf->body_filter_chain;
|
||||
|
||||
for (p = data, cl = in; cl; cl = cl->next) {
|
||||
b = cl->buf;
|
||||
p = ngx_copy(p, b->pos, b->last - b->pos);
|
||||
|
||||
if (b->last_buf || b->last_in_chain) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r,
|
||||
ngx_http_lua_ctx_t *ctx)
|
||||
{
|
||||
int type;
|
||||
int idx;
|
||||
int found;
|
||||
u_char *data;
|
||||
size_t size;
|
||||
unsigned last;
|
||||
unsigned flush = 0;
|
||||
ngx_buf_t *b;
|
||||
ngx_chain_t *cl;
|
||||
ngx_chain_t *in;
|
||||
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
|
||||
idx = luaL_checkint(L, 2);
|
||||
|
||||
dd("index: %d", idx);
|
||||
|
||||
if (idx != 1 && idx != 2) {
|
||||
return luaL_error(L, "bad index: %d", idx);
|
||||
}
|
||||
|
||||
lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
|
||||
|
||||
if (idx == 2) {
|
||||
/* overwriting the eof flag */
|
||||
last = lua_toboolean(L, 3);
|
||||
|
||||
in = lmcf->body_filter_chain;
|
||||
|
||||
if (last) {
|
||||
ctx->seen_last_in_filter = 1;
|
||||
|
||||
/* the "in" chain cannot be NULL and we set the "last_buf" or
|
||||
* "last_in_chain" flag in the last buf of "in" */
|
||||
|
||||
for (cl = in; cl; cl = cl->next) {
|
||||
if (cl->next == NULL) {
|
||||
if (r == r->main) {
|
||||
cl->buf->last_buf = 1;
|
||||
|
||||
} else {
|
||||
cl->buf->last_in_chain = 1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
/* last == 0 */
|
||||
|
||||
found = 0;
|
||||
|
||||
for (cl = in; cl; cl = cl->next) {
|
||||
b = cl->buf;
|
||||
|
||||
if (b->last_buf) {
|
||||
b->last_buf = 0;
|
||||
found = 1;
|
||||
}
|
||||
|
||||
if (b->last_in_chain) {
|
||||
b->last_in_chain = 0;
|
||||
found = 1;
|
||||
}
|
||||
|
||||
if (found && b->last == b->pos && !ngx_buf_in_memory(b)) {
|
||||
/* make it a special sync buf to make
|
||||
* ngx_http_write_filter_module happy. */
|
||||
b->sync = 1;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->seen_last_in_filter = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* idx == 1, overwriting the chunk data */
|
||||
|
||||
type = lua_type(L, 3);
|
||||
|
||||
switch (type) {
|
||||
case LUA_TSTRING:
|
||||
case LUA_TNUMBER:
|
||||
data = (u_char *) lua_tolstring(L, 3, &size);
|
||||
break;
|
||||
|
||||
case LUA_TNIL:
|
||||
/* discard the buffers */
|
||||
|
||||
in = lmcf->body_filter_chain;
|
||||
|
||||
last = 0;
|
||||
|
||||
for (cl = in; cl; cl = cl->next) {
|
||||
b = cl->buf;
|
||||
|
||||
if (b->flush) {
|
||||
flush = 1;
|
||||
}
|
||||
|
||||
if (b->last_in_chain || b->last_buf) {
|
||||
last = 1;
|
||||
}
|
||||
|
||||
dd("mark the buf as consumed: %d", (int) ngx_buf_size(b));
|
||||
b->pos = b->last;
|
||||
}
|
||||
|
||||
/* cl == NULL */
|
||||
|
||||
goto done;
|
||||
|
||||
case LUA_TTABLE:
|
||||
size = ngx_http_lua_calc_strlen_in_table(L, 3 /* index */, 3 /* arg */,
|
||||
1 /* strict */);
|
||||
data = NULL;
|
||||
break;
|
||||
|
||||
default:
|
||||
return luaL_error(L, "bad chunk data type: %s",
|
||||
lua_typename(L, type));
|
||||
}
|
||||
|
||||
in = lmcf->body_filter_chain;
|
||||
|
||||
last = 0;
|
||||
|
||||
for (cl = in; cl; cl = cl->next) {
|
||||
b = cl->buf;
|
||||
|
||||
if (b->flush) {
|
||||
flush = 1;
|
||||
}
|
||||
|
||||
if (b->last_buf || b->last_in_chain) {
|
||||
last = 1;
|
||||
}
|
||||
|
||||
dd("mark the buf as consumed: %d", (int) ngx_buf_size(cl->buf));
|
||||
cl->buf->pos = cl->buf->last;
|
||||
}
|
||||
|
||||
/* cl == NULL */
|
||||
|
||||
if (size == 0) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
cl = ngx_http_lua_chain_get_free_buf(r->connection->log, r->pool,
|
||||
&ctx->free_bufs, size);
|
||||
if (cl == NULL) {
|
||||
return luaL_error(L, "no memory");
|
||||
}
|
||||
|
||||
cl->buf->tag = (ngx_buf_tag_t) &ngx_http_lua_body_filter;
|
||||
if (type == LUA_TTABLE) {
|
||||
cl->buf->last = ngx_http_lua_copy_str_in_table(L, 3, cl->buf->last);
|
||||
|
||||
} else {
|
||||
cl->buf->last = ngx_copy(cl->buf->pos, data, size);
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
if (last || flush) {
|
||||
if (cl == NULL) {
|
||||
cl = ngx_http_lua_chain_get_free_buf(r->connection->log,
|
||||
r->pool,
|
||||
&ctx->free_bufs, 0);
|
||||
if (cl == NULL) {
|
||||
return luaL_error(L, "no memory");
|
||||
}
|
||||
|
||||
cl->buf->tag = (ngx_buf_tag_t) &ngx_http_lua_body_filter;
|
||||
}
|
||||
|
||||
if (last) {
|
||||
ctx->seen_last_in_filter = 1;
|
||||
|
||||
if (r == r->main) {
|
||||
cl->buf->last_buf = 1;
|
||||
|
||||
} else {
|
||||
cl->buf->last_in_chain = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (flush) {
|
||||
cl->buf->flush = 1;
|
||||
}
|
||||
}
|
||||
|
||||
lmcf->body_filter_chain = cl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,30 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_BODYFILTERBY_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_BODYFILTERBY_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
extern ngx_http_output_body_filter_pt ngx_http_lua_next_filter_body_filter;
|
||||
|
||||
|
||||
ngx_int_t ngx_http_lua_body_filter_init(void);
|
||||
ngx_int_t ngx_http_lua_body_filter_by_chunk(lua_State *L,
|
||||
ngx_http_request_t *r, ngx_chain_t *in);
|
||||
ngx_int_t ngx_http_lua_body_filter_inline(ngx_http_request_t *r,
|
||||
ngx_chain_t *in);
|
||||
ngx_int_t ngx_http_lua_body_filter_file(ngx_http_request_t *r,
|
||||
ngx_chain_t *in);
|
||||
int ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r,
|
||||
ngx_http_lua_ctx_t *ctx);
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_BODYFILTERBY_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,410 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include <nginx.h>
|
||||
#include <ngx_md5.h>
|
||||
#include "ngx_http_lua_common.h"
|
||||
#include "ngx_http_lua_cache.h"
|
||||
#include "ngx_http_lua_clfactory.h"
|
||||
#include "ngx_http_lua_util.h"
|
||||
|
||||
|
||||
static u_char *ngx_http_lua_gen_file_cache_key_helper(u_char *out,
|
||||
const u_char *src, size_t src_len);
|
||||
|
||||
|
||||
/**
|
||||
* Find code chunk associated with the given key in code cache,
|
||||
* and push it to the top of Lua stack if found.
|
||||
*
|
||||
* Stack layout before call:
|
||||
* | ... | <- top
|
||||
*
|
||||
* Stack layout after call:
|
||||
* | code chunk | <- top
|
||||
* | ... |
|
||||
*
|
||||
* */
|
||||
static ngx_int_t
|
||||
ngx_http_lua_cache_load_code(ngx_log_t *log, lua_State *L,
|
||||
int *ref, const char *key)
|
||||
{
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
int rc;
|
||||
u_char *err;
|
||||
#endif
|
||||
|
||||
/* get code cache table */
|
||||
lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask(
|
||||
code_cache_key));
|
||||
lua_rawget(L, LUA_REGISTRYINDEX); /* sp++ */
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0,
|
||||
"code cache lookup (key='%s', ref=%d)", key, *ref);
|
||||
|
||||
dd("code cache table to load: %p", lua_topointer(L, -1));
|
||||
|
||||
if (!lua_istable(L, -1)) {
|
||||
dd("Error: code cache table to load did not exist!!");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_http_lua_assert(key != NULL);
|
||||
|
||||
if (*ref == LUA_NOREF) {
|
||||
lua_getfield(L, -1, key); /* cache closure */
|
||||
|
||||
} else {
|
||||
if (*ref == LUA_REFNIL) {
|
||||
lua_getfield(L, -1, key); /* cache ref */
|
||||
|
||||
if (!lua_isnumber(L, -1)) {
|
||||
goto not_found;
|
||||
}
|
||||
|
||||
*ref = lua_tonumber(L, -1);
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0,
|
||||
"code cache setting ref (key='%s', ref=%d)",
|
||||
key, *ref);
|
||||
|
||||
lua_pop(L, 1); /* cache */
|
||||
}
|
||||
|
||||
lua_rawgeti(L, -1, *ref); /* cache closure */
|
||||
}
|
||||
|
||||
if (lua_isfunction(L, -1)) {
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0,
|
||||
"code cache hit (key='%s', ref=%d)", key, *ref);
|
||||
|
||||
#ifdef OPENRESTY_LUAJIT
|
||||
lua_remove(L, -2); /* sp-- */
|
||||
return NGX_OK;
|
||||
#else
|
||||
/* call closure factory to gen new closure */
|
||||
rc = lua_pcall(L, 0, 1, 0);
|
||||
if (rc == 0) {
|
||||
/* remove cache table from stack, leave code chunk at
|
||||
* top of stack */
|
||||
lua_remove(L, -2); /* sp-- */
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (lua_isstring(L, -1)) {
|
||||
err = (u_char *) lua_tostring(L, -1);
|
||||
|
||||
} else {
|
||||
err = (u_char *) "unknown error";
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, log, 0,
|
||||
"lua: failed to run factory at key \"%s\": %s",
|
||||
key, err);
|
||||
lua_pop(L, 2);
|
||||
return NGX_ERROR;
|
||||
#endif /* OPENRESTY_LUAJIT */
|
||||
}
|
||||
|
||||
not_found:
|
||||
|
||||
dd("Value associated with given key in code cache table is not code "
|
||||
"chunk: stack top=%d, top value type=%s\n",
|
||||
lua_gettop(L), luaL_typename(L, -1));
|
||||
|
||||
/* remove cache table and value from stack */
|
||||
lua_pop(L, 2); /* sp-=2 */
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0,
|
||||
"code cache miss (key='%s', ref=%d)", key, *ref);
|
||||
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Store the closure factory at the top of Lua stack to code cache, and
|
||||
* associate it with the given key. Then generate new closure.
|
||||
*
|
||||
* Stack layout before call:
|
||||
* | code factory | <- top
|
||||
* | ... |
|
||||
*
|
||||
* Stack layout after call:
|
||||
* | code chunk | <- top
|
||||
* | ... |
|
||||
*
|
||||
* */
|
||||
static ngx_int_t
|
||||
ngx_http_lua_cache_store_code(lua_State *L, int *ref, const char *key)
|
||||
{
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
int rc;
|
||||
#endif
|
||||
|
||||
/* get code cache table */
|
||||
lua_pushlightuserdata(L, ngx_http_lua_lightudata_mask(
|
||||
code_cache_key));
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
|
||||
dd("Code cache table to store: %p", lua_topointer(L, -1));
|
||||
|
||||
if (!lua_istable(L, -1)) {
|
||||
dd("Error: code cache table to load did not exist!!");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_http_lua_assert(key != NULL);
|
||||
|
||||
lua_pushvalue(L, -2); /* closure cache closure */
|
||||
|
||||
if (*ref == LUA_NOREF) {
|
||||
/* cache closure by cache key */
|
||||
lua_setfield(L, -2, key); /* closure cache */
|
||||
|
||||
} else {
|
||||
/* cache closure with reference */
|
||||
*ref = luaL_ref(L, -2); /* closure cache */
|
||||
|
||||
/* cache reference by cache key */
|
||||
lua_pushnumber(L, *ref); /* closure cache ref */
|
||||
lua_setfield(L, -2, key); /* closure cache */
|
||||
}
|
||||
|
||||
/* remove cache table, leave closure factory at top of stack */
|
||||
lua_pop(L, 1); /* closure */
|
||||
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
/* call closure factory to generate new closure */
|
||||
rc = lua_pcall(L, 0, 1, 0);
|
||||
if (rc != 0) {
|
||||
dd("Error: failed to call closure factory!!");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_cache_loadbuffer(ngx_log_t *log, lua_State *L,
|
||||
const u_char *src, size_t src_len, int *cache_ref, const u_char *cache_key,
|
||||
const char *name)
|
||||
{
|
||||
int n;
|
||||
ngx_int_t rc;
|
||||
const char *err = NULL;
|
||||
|
||||
n = lua_gettop(L);
|
||||
|
||||
rc = ngx_http_lua_cache_load_code(log, L, cache_ref, (char *) cache_key);
|
||||
if (rc == NGX_OK) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
/* rc == NGX_DECLINED */
|
||||
|
||||
/* load closure factory of inline script to the top of lua stack, sp++ */
|
||||
rc = ngx_http_lua_clfactory_loadbuffer(L, (char *) src, src_len, name);
|
||||
|
||||
if (rc != 0) {
|
||||
/* Oops! error occurred when loading Lua script */
|
||||
if (rc == LUA_ERRMEM) {
|
||||
err = "memory allocation error";
|
||||
|
||||
} else {
|
||||
if (lua_isstring(L, -1)) {
|
||||
err = lua_tostring(L, -1);
|
||||
|
||||
} else {
|
||||
err = "unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* store closure factory and gen new closure at the top of lua stack to
|
||||
* code cache */
|
||||
rc = ngx_http_lua_cache_store_code(L, cache_ref, (char *) cache_key);
|
||||
if (rc != NGX_OK) {
|
||||
err = "fail to generate new closure from the closure factory";
|
||||
goto error;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
|
||||
error:
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, log, 0,
|
||||
"failed to load inlined Lua code: %s", err);
|
||||
lua_settop(L, n);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_cache_loadfile(ngx_log_t *log, lua_State *L,
|
||||
const u_char *script, int *cache_ref, const u_char *cache_key)
|
||||
{
|
||||
int n;
|
||||
ngx_int_t rc, errcode = NGX_ERROR;
|
||||
u_char buf[NGX_HTTP_LUA_FILE_KEY_LEN + 1];
|
||||
const char *err = NULL;
|
||||
|
||||
n = lua_gettop(L);
|
||||
|
||||
/* calculate digest of script file path */
|
||||
if (cache_key == NULL) {
|
||||
dd("CACHE file key not pre-calculated...calculating");
|
||||
|
||||
cache_key = ngx_http_lua_gen_file_cache_key_helper(buf, script,
|
||||
ngx_strlen(script));
|
||||
*cache_ref = LUA_NOREF;
|
||||
|
||||
} else {
|
||||
dd("CACHE file key already pre-calculated");
|
||||
|
||||
ngx_http_lua_assert(cache_ref != NULL && *cache_ref != LUA_NOREF);
|
||||
}
|
||||
|
||||
rc = ngx_http_lua_cache_load_code(log, L, cache_ref, (char *) cache_key);
|
||||
if (rc == NGX_OK) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
/* rc == NGX_DECLINED */
|
||||
|
||||
/* load closure factory of script file to the top of lua stack, sp++ */
|
||||
rc = ngx_http_lua_clfactory_loadfile(L, (char *) script);
|
||||
|
||||
dd("loadfile returns %d (%d)", (int) rc, LUA_ERRFILE);
|
||||
|
||||
if (rc != 0) {
|
||||
/* Oops! error occurred when loading Lua script */
|
||||
switch (rc) {
|
||||
case LUA_ERRMEM:
|
||||
err = "memory allocation error";
|
||||
break;
|
||||
|
||||
case LUA_ERRFILE:
|
||||
if (errno == ENOENT) {
|
||||
errcode = NGX_HTTP_NOT_FOUND;
|
||||
|
||||
} else {
|
||||
errcode = NGX_HTTP_SERVICE_UNAVAILABLE;
|
||||
}
|
||||
|
||||
/* fall through */
|
||||
|
||||
default:
|
||||
if (lua_isstring(L, -1)) {
|
||||
err = lua_tostring(L, -1);
|
||||
|
||||
} else {
|
||||
err = "unknown error";
|
||||
}
|
||||
}
|
||||
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* store closure factory and gen new closure at the top of lua stack
|
||||
* to code cache */
|
||||
rc = ngx_http_lua_cache_store_code(L, cache_ref, (char *) cache_key);
|
||||
if (rc != NGX_OK) {
|
||||
err = "fail to generate new closure from the closure factory";
|
||||
goto error;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
|
||||
error:
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, log, 0,
|
||||
"failed to load external Lua file \"%s\": %s", script, err);
|
||||
|
||||
lua_settop(L, n);
|
||||
return errcode;
|
||||
}
|
||||
|
||||
|
||||
u_char *
|
||||
ngx_http_lua_gen_chunk_cache_key(ngx_conf_t *cf, const char *tag,
|
||||
const u_char *src, size_t src_len)
|
||||
{
|
||||
u_char *p, *out;
|
||||
size_t tag_len;
|
||||
|
||||
tag_len = ngx_strlen(tag);
|
||||
|
||||
out = ngx_palloc(cf->pool, tag_len + NGX_HTTP_LUA_INLINE_KEY_LEN + 2);
|
||||
if (out == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = ngx_copy(out, tag, tag_len);
|
||||
p = ngx_copy(p, "_", 1);
|
||||
p = ngx_copy(p, NGX_HTTP_LUA_INLINE_TAG, NGX_HTTP_LUA_INLINE_TAG_LEN);
|
||||
p = ngx_http_lua_digest_hex(p, src, src_len);
|
||||
*p = '\0';
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
static u_char *
|
||||
ngx_http_lua_gen_file_cache_key_helper(u_char *out, const u_char *src,
|
||||
size_t src_len)
|
||||
{
|
||||
u_char *p;
|
||||
|
||||
ngx_http_lua_assert(out != NULL);
|
||||
|
||||
if (out == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p = ngx_copy(out, NGX_HTTP_LUA_FILE_TAG, NGX_HTTP_LUA_FILE_TAG_LEN);
|
||||
p = ngx_http_lua_digest_hex(p, src, src_len);
|
||||
*p = '\0';
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
u_char *
|
||||
ngx_http_lua_gen_file_cache_key(ngx_conf_t *cf, const u_char *src,
|
||||
size_t src_len)
|
||||
{
|
||||
u_char *out;
|
||||
|
||||
out = ngx_palloc(cf->pool, NGX_HTTP_LUA_FILE_KEY_LEN + 1);
|
||||
if (out == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ngx_http_lua_gen_file_cache_key_helper(out, src, src_len);
|
||||
}
|
||||
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_CACHE_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_CACHE_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
ngx_int_t ngx_http_lua_cache_loadbuffer(ngx_log_t *log, lua_State *L,
|
||||
const u_char *src, size_t src_len, int *cache_ref, const u_char *cache_key,
|
||||
const char *name);
|
||||
ngx_int_t ngx_http_lua_cache_loadfile(ngx_log_t *log, lua_State *L,
|
||||
const u_char *script, int *cache_ref, const u_char *cache_key);
|
||||
u_char *ngx_http_lua_gen_chunk_cache_key(ngx_conf_t *cf, const char *tag,
|
||||
const u_char *src, size_t src_len);
|
||||
u_char *ngx_http_lua_gen_file_cache_key(ngx_conf_t *cf, const u_char *src,
|
||||
size_t src_len);
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_CACHE_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,176 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include <nginx.h>
|
||||
#include "ngx_http_lua_capturefilter.h"
|
||||
#include "ngx_http_lua_util.h"
|
||||
#include "ngx_http_lua_exception.h"
|
||||
#include "ngx_http_lua_subrequest.h"
|
||||
|
||||
|
||||
ngx_http_output_header_filter_pt ngx_http_lua_next_header_filter;
|
||||
ngx_http_output_body_filter_pt ngx_http_lua_next_body_filter;
|
||||
|
||||
|
||||
static ngx_int_t ngx_http_lua_capture_header_filter(ngx_http_request_t *r);
|
||||
static ngx_int_t ngx_http_lua_capture_body_filter(ngx_http_request_t *r,
|
||||
ngx_chain_t *in);
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_capture_filter_init(ngx_conf_t *cf)
|
||||
{
|
||||
/* setting up output filters to intercept subrequest responses */
|
||||
ngx_http_lua_next_header_filter = ngx_http_top_header_filter;
|
||||
ngx_http_top_header_filter = ngx_http_lua_capture_header_filter;
|
||||
|
||||
ngx_http_lua_next_body_filter = ngx_http_top_body_filter;
|
||||
ngx_http_top_body_filter = ngx_http_lua_capture_body_filter;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_lua_capture_header_filter(ngx_http_request_t *r)
|
||||
{
|
||||
ngx_http_post_subrequest_t *psr;
|
||||
ngx_http_lua_ctx_t *old_ctx;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
|
||||
ngx_http_lua_post_subrequest_data_t *psr_data;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua capture header filter, uri \"%V\"", &r->uri);
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
|
||||
dd("old ctx: %p", ctx);
|
||||
|
||||
if (ctx == NULL || ! ctx->capture) {
|
||||
|
||||
psr = r->post_subrequest;
|
||||
|
||||
if (psr != NULL
|
||||
&& psr->handler == ngx_http_lua_post_subrequest
|
||||
&& psr->data != NULL)
|
||||
{
|
||||
/* the lua ctx has been cleared by ngx_http_internal_redirect,
|
||||
* resume it from the post_subrequest data
|
||||
*/
|
||||
psr_data = psr->data;
|
||||
|
||||
old_ctx = psr_data->ctx;
|
||||
|
||||
if (ctx == NULL) {
|
||||
ctx = old_ctx;
|
||||
ngx_http_set_ctx(r, ctx, ngx_http_lua_module);
|
||||
|
||||
} else {
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua restoring ctx with capture %d, index %d",
|
||||
old_ctx->capture, old_ctx->index);
|
||||
|
||||
ctx->capture = old_ctx->capture;
|
||||
ctx->index = old_ctx->index;
|
||||
ctx->body = NULL;
|
||||
ctx->last_body = &ctx->body;
|
||||
psr_data->ctx = ctx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx && ctx->capture) {
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua capturing response body");
|
||||
|
||||
/* force subrequest response body buffer in memory */
|
||||
r->filter_need_in_memory = 1;
|
||||
r->header_sent = 1;
|
||||
ctx->header_sent = 1;
|
||||
|
||||
if (r->method == NGX_HTTP_HEAD) {
|
||||
r->header_only = 1;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
return ngx_http_lua_next_header_filter(r);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_lua_capture_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
|
||||
{
|
||||
int rc;
|
||||
ngx_int_t eof;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_http_lua_ctx_t *pr_ctx;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua capture body filter, uri \"%V\"", &r->uri);
|
||||
|
||||
if (in == NULL) {
|
||||
return ngx_http_lua_next_body_filter(r, NULL);
|
||||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
|
||||
if (!ctx || !ctx->capture) {
|
||||
dd("no ctx or no capture %.*s", (int) r->uri.len, r->uri.data);
|
||||
|
||||
return ngx_http_lua_next_body_filter(r, in);
|
||||
}
|
||||
|
||||
if (ctx->run_post_subrequest) {
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua body filter skipped because post subrequest "
|
||||
"already run");
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (r->parent == NULL) {
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua body filter skipped because no parent request "
|
||||
"found");
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
pr_ctx = ngx_http_get_module_ctx(r->parent, ngx_http_lua_module);
|
||||
if (pr_ctx == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua capture body filter capturing response body, uri "
|
||||
"\"%V\"", &r->uri);
|
||||
|
||||
rc = ngx_http_lua_add_copy_chain(r, pr_ctx, &ctx->last_body, in, &eof);
|
||||
if (rc != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
dd("add copy chain eof: %d, sr: %d", (int) eof, r != r->main);
|
||||
|
||||
if (eof) {
|
||||
ctx->seen_last_for_subreq = 1;
|
||||
}
|
||||
|
||||
ngx_http_lua_discard_bufs(r->pool, in);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_CAPTUREFILTER_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_CAPTUREFILTER_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
ngx_int_t ngx_http_lua_capture_filter_init(ngx_conf_t *cf);
|
||||
|
||||
|
||||
#endif /* NGX_HTTP_LUA_CAPTUREFILTER_H */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,928 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include <nginx.h>
|
||||
#include "ngx_http_lua_clfactory.h"
|
||||
|
||||
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
#define CLFACTORY_BEGIN_CODE "return function() "
|
||||
#define CLFACTORY_BEGIN_SIZE (sizeof(CLFACTORY_BEGIN_CODE) - 1)
|
||||
|
||||
#define CLFACTORY_END_CODE "\nend"
|
||||
#define CLFACTORY_END_SIZE (sizeof(CLFACTORY_END_CODE) - 1)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* taken from chaoslawful:
|
||||
* Lua bytecode header Luajit bytecode header
|
||||
* -------------- --------------
|
||||
* | \033Lua | 0-3 | \033LJ | 0-2
|
||||
* -------------- --------------
|
||||
* | LuaC | 4 | bytecode | 3
|
||||
* | Version | | version |
|
||||
* -------------- --------------
|
||||
* | LuaC | 5 | misc flag | 4 [F|S|B]
|
||||
* | Format | --------------
|
||||
* -------------- | chunkname | ULEB128 var-len
|
||||
* | Endian | 6 | len | encoded uint32
|
||||
* -------------- --------------
|
||||
* | size of | 7 | chunkname |
|
||||
* | int | | str no \0 |
|
||||
* -------------- --------------
|
||||
* | size of | 8
|
||||
* | size_t |
|
||||
* --------------
|
||||
* | size of | 9
|
||||
* | instruction|
|
||||
* --------------
|
||||
* | size of | 10
|
||||
* | number |
|
||||
* --------------
|
||||
* | number | 11
|
||||
* | is int? |
|
||||
* --------------
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* CLOSURE 0 0 RETURN 0 2 RETURN 0 1
|
||||
* length(Instruction) = 4 or 8
|
||||
* little endian or big endian
|
||||
*/
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
#define LUA_LITTLE_ENDIAN_4BYTES_CODE \
|
||||
"\x24\x00\x00\x00\x1e\x00\x00\x01\x1e\x00\x80\x00"
|
||||
#define LUA_LITTLE_ENDIAN_8BYTES_CODE \
|
||||
"\x24\x00\x00\x00\x00\x00\x00\x00\x1e\x00\x00\x01" \
|
||||
"\x00\x00\x00\x00\x1e\x00\x80\x00\x00\x00\x00\x00"
|
||||
#define LUA_BIG_ENDIAN_4BYTES_CODE \
|
||||
"\x00\x00\x00\x24\x01\x00\x00\x1e\x00\x08\x00\x1e"
|
||||
#define LUA_BIG_ENDIAN_8BYTES_CODE \
|
||||
"\x00\x00\x00\x00\x00\x00\x00\x24\x00\x00\x00\x00" \
|
||||
"\x01\x00\x00\x1e\x00\x00\x00\x00\x00\x08\x00\x1e"
|
||||
#define LUA_LITTLE_ENDIAN_4BYTES_CODE_LEN (4 + 4 + 4)
|
||||
#define LUA_LITTLE_ENDIAN_8BYTES_CODE_LEN (8 + 8 + 8)
|
||||
#define LUA_BIG_ENDIAN_4BYTES_CODE_LEN (4 + 4 + 4)
|
||||
#define LUA_BIG_ENDIAN_8BYTES_CODE_LEN (8 + 8 + 8)
|
||||
#define LUAC_HEADERSIZE 12
|
||||
#define LUAC_VERSION 0x51
|
||||
#endif /* OPENRESTY_LUAJIT */
|
||||
|
||||
|
||||
/*
|
||||
* taken from chaoslawful:
|
||||
* Lua Proto
|
||||
* ---------------------
|
||||
* | String | Can be empty string
|
||||
* | [source] | (stripped or internal function)
|
||||
* ---------------------
|
||||
* | Int | At which line this function is defined
|
||||
* | [linedefined] |
|
||||
* ---------------------
|
||||
* | Int | At while line this function definition ended
|
||||
* | [lastlinedefined] |
|
||||
* ---------------------
|
||||
* | Char | Number of upvalues referenced by this function
|
||||
* | [nups] |
|
||||
* ---------------------
|
||||
* | Char | Number of parameters of this function
|
||||
* | [numparams] |
|
||||
* ---------------------
|
||||
* | Char | Does this function has variable number of arguments?
|
||||
* | [is_var_arg] | main function always set to VARARG_ISVARARG (2)
|
||||
* ---------------------
|
||||
* | Char | Maximum stack size this function used
|
||||
* | [maxstacksize] | Initially set to 2
|
||||
* ---------------------
|
||||
* | Vector(instr) | Code instructions of this function
|
||||
* | [code] |
|
||||
* ---------------------
|
||||
* | Int | Number of constants referenced by this function
|
||||
* | [sizek] |
|
||||
* ---------------------
|
||||
* | Char | ------------------------------------
|
||||
* | type of [k[i]] | The type and content of constants |
|
||||
* --------------------- |-> repeat for i in
|
||||
* | Char if boolean | No content part if type is NIL | [1..sizek]
|
||||
* | Number if number | ------------------------------------
|
||||
* | String if string |
|
||||
* ---------------------
|
||||
* | Int | Number of internal functions
|
||||
* | [sizep] |
|
||||
* ---------------------
|
||||
* | Function | -> repeat for i in [1..sizep]
|
||||
* | at [p[i]] |
|
||||
* ---------------------
|
||||
* | Vector | Debug lineinfo vector
|
||||
* | [lineinfo] | Empty vector here if debug info is stripped
|
||||
* ---------------------
|
||||
* | Int | Number of local variable in this function
|
||||
* | [sizelocvars] | 0 if debug info is stripped
|
||||
* ---------------------
|
||||
* | String | ------------------------------------
|
||||
* | [locvars[i]] | Name of local var i |
|
||||
* | .varname] | |
|
||||
* --------------------- |
|
||||
* | Int | instruction counter |
|
||||
* | [locvars[i]] | where local var i start to be |-> repeat for i in
|
||||
* | .startpc] | referenced | [0..sizelocvars]
|
||||
* --------------------- |
|
||||
* | Int | instruction counter, where local |
|
||||
* | [locvars[i]] | var i ceased to be referenced |
|
||||
* | .endpc] | ------------------------------------
|
||||
* ---------------------
|
||||
* | Int | Number of upvalues referenced by this function,
|
||||
* | [sizeupvalues] | 0 if stripped
|
||||
* ---------------------
|
||||
* | String | -> repeat for i in[0..sizeupvalues]
|
||||
* | [upvalues[i]] |
|
||||
* ---------------------
|
||||
*/
|
||||
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
#define POS_SOURCE_STR_LEN LUAC_HEADERSIZE
|
||||
#define POS_START_LINE (POS_SOURCE_STR_LEN + sizeof(size_t))
|
||||
#define POS_LAST_LINE (POS_START_LINE + sizeof(int))
|
||||
#define POS_NUM_OF_UPVS (POS_LAST_LINE + sizeof(int))
|
||||
#define POS_NUM_OF_PARA (POS_NUM_OF_UPVS + sizeof(char))
|
||||
#define POS_IS_VAR_ARG (POS_NUM_OF_PARA + sizeof(char))
|
||||
#define POS_MAX_STACK_SIZE (POS_IS_VAR_ARG + sizeof(char))
|
||||
#define POS_NUM_OF_INST (POS_MAX_STACK_SIZE +sizeof(char))
|
||||
#define POS_BYTECODE (POS_NUM_OF_INST + sizeof(int))
|
||||
#define MAX_BEGIN_CODE_SIZE \
|
||||
(POS_BYTECODE + LUA_LITTLE_ENDIAN_8BYTES_CODE_LEN \
|
||||
+ sizeof(int) + sizeof(int))
|
||||
#define MAX_END_CODE_SIZE (sizeof(int) + sizeof(int) + sizeof(int))
|
||||
#endif /* OPENRESTY_LUAJIT */
|
||||
|
||||
/*
|
||||
* taken from chaoslawful:
|
||||
* Luajit bytecode format
|
||||
* ---------------------
|
||||
* | HEAD | Luajit bytecode head
|
||||
* ---------------------
|
||||
* | Internal | All internal functions
|
||||
* | functions |
|
||||
* ---------------------
|
||||
* | ULEB128 | Rest data total length of this function
|
||||
* | [Date len of | (not include itself)
|
||||
* | this function] |
|
||||
* ---------------------
|
||||
* | Char | F(ffi) | V(vararg)| C(has internal funcs)
|
||||
* | [func flag] |
|
||||
* ---------------------
|
||||
* | Char | Number of parameters of this function
|
||||
* | [numparams] |
|
||||
* ---------------------
|
||||
* | Char |
|
||||
* | [framesize] |
|
||||
* ---------------------
|
||||
* | Char | Number of upvalues referenced by this function
|
||||
* | [sizeupvalues] |
|
||||
* ---------------------
|
||||
* | ULEB128 | Number of collectable constants referenced
|
||||
* | [sizekgc] | by this function
|
||||
* ---------------------
|
||||
* | ULEB128 | Number of lua number constants referenced
|
||||
* | [sizekn] | by this function
|
||||
* ---------------------
|
||||
* | ULEB128 | Number of bytecode instructions of this function
|
||||
* | [sizebc]m1 | minus 1 to omit the BC_FUNCV/BC_FUNCF header bytecode
|
||||
* ---------------------
|
||||
* | ULEB128 |
|
||||
* | [size of dbg | Size of debug lineinfo map, available when not stripped
|
||||
* | lineinfo] |
|
||||
* ---------------------
|
||||
* | ULEB128 | Available when not stripped
|
||||
* | [firstline] | The first line of this function's definition
|
||||
* ---------------------
|
||||
* | ULEB128 | Available when not stripped
|
||||
* | [numline] | The number of lines of this function's definition
|
||||
* ---------------------
|
||||
* | [bytecode] | Bytecode instructions of this function
|
||||
* ---------------------
|
||||
* |[upvalue ref slots]| [sizeupvalues] * 2
|
||||
* ---------------------
|
||||
* | [collectable | [sizekgc] elems, variable length
|
||||
* | constants] |
|
||||
* ---------------------
|
||||
* | [lua number | [sizekn] elems, variable length
|
||||
* | constants] |
|
||||
* ---------------------
|
||||
* | [debug lineinfo | Length is the calculated size of debug lineinfo above
|
||||
* | | Only available if not stripped
|
||||
* ---------------------
|
||||
* | Char |
|
||||
* | [\x00] | Footer
|
||||
* ---------------------
|
||||
*/
|
||||
|
||||
/* bytecode for luajit 2.0 */
|
||||
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
#define LJ20_LITTLE_ENDIAN_CODE_STRIPPED \
|
||||
"\x14\x03\x00\x01\x00\x01\x00\x03" \
|
||||
"\x31\x00\x00\x00\x30\x00\x00\x80\x48\x00\x02\x00" \
|
||||
"\x00\x00"
|
||||
|
||||
#define LJ20_BIG_ENDIAN_CODE_STRIPPED \
|
||||
"\x14\x03\x00\x01\x00\x01\x00\x03" \
|
||||
"\x00\x00\x00\x31\x80\x00\x00\x30\x00\x02\x00\x48" \
|
||||
"\x00\x00"
|
||||
|
||||
#define LJ20_LITTLE_ENDIAN_CODE \
|
||||
"\x15\x03\x00\x01\x00\x01\x00\x03\x00" \
|
||||
"\x31\x00\x00\x00\x30\x00\x00\x80\x48\x00\x02\x00" \
|
||||
"\x00\x00"
|
||||
|
||||
#define LJ20_BIG_ENDIAN_CODE \
|
||||
"\x15\x03\x00\x01\x00\x01\x00\x03\x00" \
|
||||
"\x00\x00\x00\x31\x80\x00\x00\x30\x00\x02\x00\x48" \
|
||||
"\x00\x00"
|
||||
|
||||
/* bytecode for luajit 2.1 */
|
||||
|
||||
#define LJ21_LITTLE_ENDIAN_CODE_STRIPPED \
|
||||
"\x14\x03\x00\x01\x00\x01\x00\x03" \
|
||||
"\x33\x00\x00\x00\x32\x00\x00\x80\x4c\x00\x02\x00" \
|
||||
"\x00\x00"
|
||||
|
||||
#define LJ21_BIG_ENDIAN_CODE_STRIPPED \
|
||||
"\x14\x03\x00\x01\x00\x01\x00\x03" \
|
||||
"\x00\x00\x00\x33\x80\x00\x00\x32\x00\x02\x00\x4c" \
|
||||
"\x00\x00"
|
||||
|
||||
#define LJ21_LITTLE_ENDIAN_CODE \
|
||||
"\x15\x03\x00\x01\x00\x01\x00\x03\x00" \
|
||||
"\x33\x00\x00\x00\x32\x00\x00\x80\x4c\x00\x02\x00" \
|
||||
"\x00\x00"
|
||||
|
||||
#define LJ21_BIG_ENDIAN_CODE \
|
||||
"\x15\x03\x00\x01\x00\x01\x00\x03\x00" \
|
||||
"\x00\x00\x00\x33\x80\x00\x00\x32\x00\x02\x00\x4c" \
|
||||
"\x00\x00"
|
||||
|
||||
#define LJ_CODE_LEN 23
|
||||
#define LJ_CODE_LEN_STRIPPED 22
|
||||
#define LJ_HEADERSIZE 5
|
||||
#define LJ_BCDUMP_F_BE 0x01
|
||||
#define LJ_BCDUMP_F_STRIP 0x02
|
||||
#define LJ21_BCDUMP_VERSION 2
|
||||
#define LJ20_BCDUMP_VERSION 1
|
||||
#define LJ_SIGNATURE "\x1b\x4c\x4a"
|
||||
#endif /* OPENRESTY_LUAJIT */
|
||||
|
||||
|
||||
typedef enum {
|
||||
NGX_LUA_TEXT_FILE,
|
||||
NGX_LUA_BT_LUA,
|
||||
NGX_LUA_BT_LJ,
|
||||
} ngx_http_lua_clfactory_file_type_e;
|
||||
|
||||
|
||||
enum {
|
||||
NGX_LUA_READER_BUFSIZE = 4096,
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_http_lua_clfactory_file_type_e file_type;
|
||||
|
||||
int extraline;
|
||||
FILE *f;
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
int sent_begin;
|
||||
int sent_end;
|
||||
size_t begin_code_len;
|
||||
size_t end_code_len;
|
||||
size_t rest_len;
|
||||
union {
|
||||
char *ptr;
|
||||
char str[MAX_BEGIN_CODE_SIZE];
|
||||
} begin_code;
|
||||
union {
|
||||
char *ptr;
|
||||
char str[MAX_END_CODE_SIZE];
|
||||
} end_code;
|
||||
#endif /* OPENRESTY_LUAJIT */
|
||||
char buff[NGX_LUA_READER_BUFSIZE];
|
||||
} ngx_http_lua_clfactory_file_ctx_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
int sent_begin;
|
||||
int sent_end;
|
||||
#endif
|
||||
const char *s;
|
||||
size_t size;
|
||||
} ngx_http_lua_clfactory_buffer_ctx_t;
|
||||
|
||||
|
||||
static const char *ngx_http_lua_clfactory_getF(lua_State *L, void *ud,
|
||||
size_t *size);
|
||||
static int ngx_http_lua_clfactory_errfile(lua_State *L, const char *what,
|
||||
int fname_index);
|
||||
static const char *ngx_http_lua_clfactory_getS(lua_State *L, void *ud,
|
||||
size_t *size);
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
static long ngx_http_lua_clfactory_file_size(FILE *f);
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
int
|
||||
ngx_http_lua_clfactory_bytecode_prepare(lua_State *L,
|
||||
ngx_http_lua_clfactory_file_ctx_t *lf, int fname_index)
|
||||
{
|
||||
int x = 1, size_of_int, size_of_size_t, little_endian,
|
||||
size_of_inst, version, stripped;
|
||||
static int num_of_inst = 3, num_of_inter_func = 1;
|
||||
const char *emsg, *serr, *bytecode;
|
||||
size_t size, bytecode_len;
|
||||
long fsize;
|
||||
|
||||
serr = NULL;
|
||||
|
||||
*lf->begin_code.str = LUA_SIGNATURE[0];
|
||||
|
||||
if (lf->file_type == NGX_LUA_BT_LJ) {
|
||||
size = fread(lf->begin_code.str + 1, 1, LJ_HEADERSIZE - 1, lf->f);
|
||||
|
||||
if (size != LJ_HEADERSIZE - 1) {
|
||||
serr = strerror(errno);
|
||||
emsg = "cannot read header";
|
||||
goto error;
|
||||
}
|
||||
|
||||
version = *(lf->begin_code.str + 3);
|
||||
|
||||
dd("version: %d", (int) version);
|
||||
|
||||
if (ngx_memcmp(lf->begin_code.str, LJ_SIGNATURE,
|
||||
sizeof(LJ_SIGNATURE) - 1))
|
||||
{
|
||||
emsg = "bad byte-code header";
|
||||
goto error;
|
||||
}
|
||||
|
||||
#if defined(DDEBUG) && (DDEBUG)
|
||||
{
|
||||
dd("==LJ_BT_HEADER==");
|
||||
size_t i;
|
||||
for (i = 0; i < LJ_HEADERSIZE; i++) {
|
||||
dd("%ld: 0x%02X", i, (unsigned)(u_char) lf->begin_code.str[i]);
|
||||
}
|
||||
dd("==LJ_BT_HEADER_END==");
|
||||
}
|
||||
#endif
|
||||
|
||||
lf->begin_code_len = LJ_HEADERSIZE;
|
||||
little_endian = !((*(lf->begin_code.str + 4)) & LJ_BCDUMP_F_BE);
|
||||
stripped = (*(lf->begin_code.str + 4)) & LJ_BCDUMP_F_STRIP;
|
||||
|
||||
dd("stripped: %d", (int) stripped);
|
||||
|
||||
if (version == LJ21_BCDUMP_VERSION) {
|
||||
if (stripped) {
|
||||
if (little_endian) {
|
||||
lf->end_code.ptr = LJ21_LITTLE_ENDIAN_CODE_STRIPPED;
|
||||
|
||||
} else {
|
||||
lf->end_code.ptr = LJ21_BIG_ENDIAN_CODE_STRIPPED;
|
||||
}
|
||||
|
||||
lf->end_code_len = LJ_CODE_LEN_STRIPPED;
|
||||
|
||||
} else {
|
||||
if (little_endian) {
|
||||
lf->end_code.ptr = LJ21_LITTLE_ENDIAN_CODE;
|
||||
|
||||
} else {
|
||||
lf->end_code.ptr = LJ21_BIG_ENDIAN_CODE;
|
||||
}
|
||||
|
||||
lf->end_code_len = LJ_CODE_LEN;
|
||||
}
|
||||
|
||||
} else if (version == LJ20_BCDUMP_VERSION) {
|
||||
if (stripped) {
|
||||
if (little_endian) {
|
||||
lf->end_code.ptr = LJ20_LITTLE_ENDIAN_CODE_STRIPPED;
|
||||
|
||||
} else {
|
||||
lf->end_code.ptr = LJ20_BIG_ENDIAN_CODE_STRIPPED;
|
||||
}
|
||||
|
||||
lf->end_code_len = LJ_CODE_LEN_STRIPPED;
|
||||
|
||||
} else {
|
||||
if (little_endian) {
|
||||
lf->end_code.ptr = LJ20_LITTLE_ENDIAN_CODE;
|
||||
|
||||
} else {
|
||||
lf->end_code.ptr = LJ20_BIG_ENDIAN_CODE;
|
||||
}
|
||||
|
||||
lf->end_code_len = LJ_CODE_LEN;
|
||||
}
|
||||
|
||||
} else {
|
||||
emsg = "bytecode format version unsupported";
|
||||
goto error;
|
||||
}
|
||||
|
||||
fsize = ngx_http_lua_clfactory_file_size(lf->f);
|
||||
if (fsize < 0) {
|
||||
serr = strerror(errno);
|
||||
emsg = "cannot fseek/ftell";
|
||||
goto error;
|
||||
}
|
||||
|
||||
lf->rest_len = fsize - LJ_HEADERSIZE;
|
||||
|
||||
#if defined(DDEBUG) && (DDEBUG)
|
||||
{
|
||||
size_t i = 0;
|
||||
dd("==LJ_END_CODE: %ld rest_len: %ld==", lf->end_code_len,
|
||||
lf->rest_len);
|
||||
|
||||
for (i = 0; i < lf->end_code_len; i++) {
|
||||
dd("%ld: 0x%02X", i, (unsigned) ((u_char) lf->end_code.ptr[i]));
|
||||
}
|
||||
dd("==LJ_END_CODE_END==");
|
||||
}
|
||||
#endif
|
||||
|
||||
} else {
|
||||
size = fread(lf->begin_code.str + 1, 1, LUAC_HEADERSIZE - 1, lf->f);
|
||||
|
||||
if (size != LUAC_HEADERSIZE - 1) {
|
||||
serr = strerror(errno);
|
||||
emsg = "cannot read header";
|
||||
goto error;
|
||||
}
|
||||
|
||||
version = *(lf->begin_code.str + 4);
|
||||
little_endian = *(lf->begin_code.str + 6);
|
||||
size_of_int = *(lf->begin_code.str + 7);
|
||||
size_of_size_t = *(lf->begin_code.str + 8);
|
||||
size_of_inst = *(lf->begin_code.str + 9);
|
||||
|
||||
#if defined(DDEBUG) && (DDEBUG)
|
||||
{
|
||||
dd("==LUA_BT_HEADER==");
|
||||
size_t i;
|
||||
for (i = 0; i < LUAC_HEADERSIZE; i++) {
|
||||
dd("%ld, 0x%02X", i, (unsigned)(u_char) lf->begin_code.str[i]);
|
||||
}
|
||||
dd("==LUA_BT_HEADER_END==");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ngx_memcmp(lf->begin_code.str, LUA_SIGNATURE,
|
||||
sizeof(LUA_SIGNATURE) -1)
|
||||
|| version != LUAC_VERSION
|
||||
|| little_endian != (int) (*(char *) &x)
|
||||
|| size_of_int != sizeof(int)
|
||||
|| size_of_size_t != sizeof(size_t)
|
||||
|| (size_of_inst != 4 && size_of_inst != 8))
|
||||
{
|
||||
emsg = "bad byte-code header";
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* clear the following fields to zero:
|
||||
* - source string length
|
||||
* - start line
|
||||
* - last line
|
||||
*/
|
||||
ngx_memzero(lf->begin_code.str + POS_SOURCE_STR_LEN,
|
||||
sizeof(size_t) + sizeof(int) * 2);
|
||||
/* number of upvalues */
|
||||
*(lf->begin_code.str + POS_NUM_OF_UPVS) = 0;
|
||||
/* number of parameters */
|
||||
*(lf->begin_code.str + POS_NUM_OF_PARA) = 0;
|
||||
/* is var-argument function? */
|
||||
*(lf->begin_code.str + POS_IS_VAR_ARG) = 2;
|
||||
/* max stack size */
|
||||
*(lf->begin_code.str + POS_MAX_STACK_SIZE) = 2;
|
||||
/* number of bytecode instructions */
|
||||
ngx_memcpy(lf->begin_code.str + POS_NUM_OF_INST, &num_of_inst,
|
||||
sizeof(int));
|
||||
|
||||
lf->begin_code_len = POS_BYTECODE;
|
||||
|
||||
if (little_endian) {
|
||||
if (size_of_inst == 4) {
|
||||
bytecode = LUA_LITTLE_ENDIAN_4BYTES_CODE;
|
||||
bytecode_len = LUA_LITTLE_ENDIAN_4BYTES_CODE_LEN;
|
||||
|
||||
} else {
|
||||
bytecode = LUA_LITTLE_ENDIAN_8BYTES_CODE;
|
||||
bytecode_len = LUA_LITTLE_ENDIAN_8BYTES_CODE_LEN;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (size_of_inst == 4) {
|
||||
bytecode = LUA_BIG_ENDIAN_4BYTES_CODE;
|
||||
bytecode_len = LUA_BIG_ENDIAN_4BYTES_CODE_LEN;
|
||||
|
||||
} else {
|
||||
bytecode = LUA_BIG_ENDIAN_8BYTES_CODE;
|
||||
bytecode_len = LUA_BIG_ENDIAN_8BYTES_CODE_LEN;
|
||||
}
|
||||
}
|
||||
|
||||
/* bytecode */
|
||||
ngx_memcpy(lf->begin_code.str + POS_BYTECODE, bytecode, bytecode_len);
|
||||
|
||||
/* number of consts */
|
||||
ngx_memzero(lf->begin_code.str + POS_BYTECODE + bytecode_len,
|
||||
sizeof(int));
|
||||
/* number of internal functions */
|
||||
ngx_memcpy(lf->begin_code.str + POS_BYTECODE + bytecode_len
|
||||
+ sizeof(int), &num_of_inter_func, sizeof(int));
|
||||
|
||||
lf->begin_code_len += bytecode_len + sizeof(int) + sizeof(int);
|
||||
|
||||
#if defined(DDEBUG) && (DDEBUG)
|
||||
{
|
||||
size_t i = 0;
|
||||
dd("==LUA_BEGIN_CODE: %ld==", lf->begin_code_len);
|
||||
for (i = 0; i < lf->begin_code_len; i++) {
|
||||
dd("%ld: 0x%02X", i, (unsigned) ((u_char) lf->begin_code.str[i]));
|
||||
}
|
||||
dd("==LUA_BEGIN_CODE_END==");
|
||||
}
|
||||
#endif
|
||||
|
||||
/* clear the following fields to zero:
|
||||
* - lineinfo vector size
|
||||
* - number of local vars
|
||||
* - number of upvalues
|
||||
*/
|
||||
ngx_memzero(lf->end_code.str, sizeof(int) * 3);
|
||||
|
||||
lf->end_code_len = sizeof(int) + sizeof(int) + sizeof(int);
|
||||
|
||||
#if defined(DDEBUG) && (DDEBUG)
|
||||
{
|
||||
size_t i = 0;
|
||||
dd("==LUA_END_CODE: %ld==", lf->end_code_len);
|
||||
for (i = 0; i < lf->end_code_len; i++) {
|
||||
dd("%ld: 0x%02X", i, (unsigned) ((u_char) lf->end_code.str[i]));
|
||||
}
|
||||
dd("==LUA_END_CODE_END==");
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
|
||||
fclose(lf->f); /* close file (even in case of errors) */
|
||||
|
||||
if (serr) {
|
||||
lua_pushfstring(L, "%s: %s", emsg, serr);
|
||||
|
||||
} else {
|
||||
lua_pushstring(L, emsg);
|
||||
}
|
||||
|
||||
lua_remove(L, fname_index);
|
||||
|
||||
return LUA_ERRFILE;
|
||||
}
|
||||
#endif /* OPENRESTY_LUAJIT */
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_clfactory_loadfile(lua_State *L, const char *filename)
|
||||
{
|
||||
int c, status, readstatus;
|
||||
ngx_flag_t sharp;
|
||||
|
||||
ngx_http_lua_clfactory_file_ctx_t lf;
|
||||
|
||||
/* index of filename on the stack */
|
||||
int fname_index;
|
||||
|
||||
sharp = 0;
|
||||
fname_index = lua_gettop(L) + 1;
|
||||
|
||||
lf.extraline = 0;
|
||||
lf.file_type = NGX_LUA_TEXT_FILE;
|
||||
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
lf.begin_code.ptr = CLFACTORY_BEGIN_CODE;
|
||||
lf.begin_code_len = CLFACTORY_BEGIN_SIZE;
|
||||
lf.end_code.ptr = CLFACTORY_END_CODE;
|
||||
lf.end_code_len = CLFACTORY_END_SIZE;
|
||||
#endif
|
||||
|
||||
lua_pushfstring(L, "@%s", filename);
|
||||
|
||||
lf.f = fopen(filename, "r");
|
||||
if (lf.f == NULL) {
|
||||
return ngx_http_lua_clfactory_errfile(L, "open", fname_index);
|
||||
}
|
||||
|
||||
c = getc(lf.f);
|
||||
|
||||
if (c == '#') { /* Unix exec. file? */
|
||||
lf.extraline = 1;
|
||||
|
||||
while ((c = getc(lf.f)) != EOF && c != '\n') {
|
||||
/* skip first line */
|
||||
}
|
||||
|
||||
if (c == '\n') {
|
||||
c = getc(lf.f);
|
||||
}
|
||||
|
||||
sharp = 1;
|
||||
}
|
||||
|
||||
if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */
|
||||
lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
|
||||
|
||||
if (lf.f == NULL) {
|
||||
return ngx_http_lua_clfactory_errfile(L, "reopen", fname_index);
|
||||
}
|
||||
|
||||
/* check whether lib jit exists */
|
||||
luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1);
|
||||
lua_getfield(L, -1, "jit"); /* get _LOADED["jit"] */
|
||||
|
||||
if (lua_istable(L, -1)) {
|
||||
lf.file_type = NGX_LUA_BT_LJ;
|
||||
|
||||
} else {
|
||||
lf.file_type = NGX_LUA_BT_LUA;
|
||||
}
|
||||
|
||||
lua_pop(L, 2);
|
||||
|
||||
/*
|
||||
* Loading bytecode with an extra header is disabled for security
|
||||
* reasons. This may circumvent the usual check for bytecode vs.
|
||||
* Lua code by looking at the first char. Since this is a potential
|
||||
* security violation no attempt is made to echo the chunkname either.
|
||||
*/
|
||||
if (lf.file_type == NGX_LUA_BT_LJ && sharp) {
|
||||
|
||||
if (filename) {
|
||||
fclose(lf.f); /* close file (even in case of errors) */
|
||||
}
|
||||
|
||||
filename = lua_tostring(L, fname_index) + 1;
|
||||
lua_pushfstring(L, "bad byte-code header in %s", filename);
|
||||
lua_remove(L, fname_index);
|
||||
|
||||
return LUA_ERRFILE;
|
||||
}
|
||||
|
||||
while ((c = getc(lf.f)) != EOF && c != LUA_SIGNATURE[0]) {
|
||||
/* skip eventual `#!...' */
|
||||
}
|
||||
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
status = ngx_http_lua_clfactory_bytecode_prepare(L, &lf, fname_index);
|
||||
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
lf.extraline = 0;
|
||||
}
|
||||
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
if (lf.file_type == NGX_LUA_TEXT_FILE) {
|
||||
ungetc(c, lf.f);
|
||||
}
|
||||
|
||||
lf.sent_begin = lf.sent_end = 0;
|
||||
|
||||
#else
|
||||
ungetc(c, lf.f);
|
||||
#endif
|
||||
status = lua_load(L, ngx_http_lua_clfactory_getF, &lf,
|
||||
lua_tostring(L, -1));
|
||||
|
||||
readstatus = ferror(lf.f);
|
||||
|
||||
if (filename) {
|
||||
fclose(lf.f); /* close file (even in case of errors) */
|
||||
}
|
||||
|
||||
if (readstatus) {
|
||||
lua_settop(L, fname_index); /* ignore results from `lua_load' */
|
||||
return ngx_http_lua_clfactory_errfile(L, "read", fname_index);
|
||||
}
|
||||
|
||||
lua_remove(L, fname_index);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_clfactory_loadbuffer(lua_State *L, const char *buff,
|
||||
size_t size, const char *name)
|
||||
{
|
||||
ngx_http_lua_clfactory_buffer_ctx_t ls;
|
||||
|
||||
ls.s = buff;
|
||||
ls.size = size;
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
ls.sent_begin = 0;
|
||||
ls.sent_end = 0;
|
||||
#endif
|
||||
|
||||
return lua_load(L, ngx_http_lua_clfactory_getS, &ls, name);
|
||||
}
|
||||
|
||||
|
||||
static const char *
|
||||
ngx_http_lua_clfactory_getF(lua_State *L, void *ud, size_t *size)
|
||||
{
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
char *buf;
|
||||
#endif
|
||||
size_t num;
|
||||
|
||||
ngx_http_lua_clfactory_file_ctx_t *lf;
|
||||
|
||||
lf = (ngx_http_lua_clfactory_file_ctx_t *) ud;
|
||||
|
||||
if (lf->extraline) {
|
||||
lf->extraline = 0;
|
||||
*size = 1;
|
||||
return "\n";
|
||||
}
|
||||
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
if (lf->sent_begin == 0) {
|
||||
lf->sent_begin = 1;
|
||||
*size = lf->begin_code_len;
|
||||
|
||||
if (lf->file_type == NGX_LUA_TEXT_FILE) {
|
||||
buf = lf->begin_code.ptr;
|
||||
|
||||
} else {
|
||||
buf = lf->begin_code.str;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
#endif /* OPENRESTY_LUAJIT */
|
||||
|
||||
num = fread(lf->buff, 1, sizeof(lf->buff), lf->f);
|
||||
|
||||
dd("fread returned %d", (int) num);
|
||||
|
||||
if (num == 0) {
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
if (lf->sent_end == 0) {
|
||||
lf->sent_end = 1;
|
||||
*size = lf->end_code_len;
|
||||
|
||||
if (lf->file_type == NGX_LUA_BT_LUA) {
|
||||
buf = lf->end_code.str;
|
||||
|
||||
} else {
|
||||
buf = lf->end_code.ptr;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
#endif /* OPENRESTY_LUAJIT */
|
||||
|
||||
*size = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
if (lf->file_type == NGX_LUA_BT_LJ) {
|
||||
/* skip the footer(\x00) in luajit */
|
||||
|
||||
lf->rest_len -= num;
|
||||
|
||||
if (lf->rest_len == 0) {
|
||||
if (--num == 0 && lf->sent_end == 0) {
|
||||
lf->sent_end = 1;
|
||||
buf = lf->end_code.ptr;
|
||||
*size = lf->end_code_len;
|
||||
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* OPENRESTY_LUAJIT */
|
||||
|
||||
*size = num;
|
||||
return lf->buff;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_http_lua_clfactory_errfile(lua_State *L, const char *what, int fname_index)
|
||||
{
|
||||
const char *serr;
|
||||
const char *filename;
|
||||
|
||||
filename = lua_tostring(L, fname_index) + 1;
|
||||
|
||||
if (errno) {
|
||||
serr = strerror(errno);
|
||||
lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr);
|
||||
|
||||
} else {
|
||||
lua_pushfstring(L, "cannot %s %s", what, filename);
|
||||
}
|
||||
|
||||
lua_remove(L, fname_index);
|
||||
|
||||
return LUA_ERRFILE;
|
||||
}
|
||||
|
||||
|
||||
static const char *
|
||||
ngx_http_lua_clfactory_getS(lua_State *L, void *ud, size_t *size)
|
||||
{
|
||||
ngx_http_lua_clfactory_buffer_ctx_t *ls = ud;
|
||||
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
if (ls->sent_begin == 0) {
|
||||
ls->sent_begin = 1;
|
||||
*size = CLFACTORY_BEGIN_SIZE;
|
||||
|
||||
return CLFACTORY_BEGIN_CODE;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ls->size == 0) {
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
if (ls->sent_end == 0) {
|
||||
ls->sent_end = 1;
|
||||
*size = CLFACTORY_END_SIZE;
|
||||
return CLFACTORY_END_CODE;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*size = ls->size;
|
||||
ls->size = 0;
|
||||
|
||||
return ls->s;
|
||||
}
|
||||
|
||||
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
static long
|
||||
ngx_http_lua_clfactory_file_size(FILE *f)
|
||||
{
|
||||
long cur_pos, len;
|
||||
|
||||
cur_pos = ftell(f);
|
||||
if (cur_pos == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fseek(f, 0, SEEK_END) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = ftell(f);
|
||||
if (len == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fseek(f, cur_pos, SEEK_SET) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
#endif /* OPENRESTY_LUAJIT */
|
||||
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_CLFACTORY_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_CLFACTORY_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
ngx_int_t ngx_http_lua_clfactory_loadfile(lua_State *L, const char *filename);
|
||||
ngx_int_t ngx_http_lua_clfactory_loadbuffer(lua_State *L, const char *buff,
|
||||
size_t size, const char *name);
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_CLFACTORY_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,700 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_COMMON_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_COMMON_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_autoconf.h"
|
||||
|
||||
#include <nginx.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_http.h>
|
||||
#include <ngx_md5.h>
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <luajit.h>
|
||||
#include <lualib.h>
|
||||
#include <lauxlib.h>
|
||||
|
||||
|
||||
#if defined(NDK) && NDK
|
||||
#include <ndk.h>
|
||||
|
||||
typedef struct {
|
||||
size_t size;
|
||||
int ref;
|
||||
u_char *key;
|
||||
u_char *chunkname;
|
||||
ngx_str_t script;
|
||||
} ngx_http_lua_set_var_data_t;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef NGX_LUA_USE_ASSERT
|
||||
#include <assert.h>
|
||||
# define ngx_http_lua_assert(a) assert(a)
|
||||
#else
|
||||
# define ngx_http_lua_assert(a)
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* max positive +1.7976931348623158e+308
|
||||
* min positive +2.2250738585072014e-308
|
||||
*/
|
||||
#ifndef NGX_DOUBLE_LEN
|
||||
#define NGX_DOUBLE_LEN 25
|
||||
#endif
|
||||
|
||||
|
||||
#if (NGX_PCRE)
|
||||
#include <pcre.h>
|
||||
# if (PCRE_MAJOR > 8) || (PCRE_MAJOR == 8 && PCRE_MINOR >= 21)
|
||||
# define LUA_HAVE_PCRE_JIT 1
|
||||
# else
|
||||
# define LUA_HAVE_PCRE_JIT 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#if (nginx_version < 1006000)
|
||||
# error at least nginx 1.6.0 is required but found an older version
|
||||
#endif
|
||||
|
||||
#if LUA_VERSION_NUM != 501
|
||||
# error unsupported Lua language version
|
||||
#endif
|
||||
|
||||
#if !defined(LUAJIT_VERSION_NUM) || (LUAJIT_VERSION_NUM < 20000)
|
||||
# error unsupported LuaJIT version
|
||||
#endif
|
||||
|
||||
|
||||
#if (!defined OPENSSL_NO_OCSP && defined SSL_CTRL_SET_TLSEXT_STATUS_REQ_CB)
|
||||
# define NGX_HTTP_LUA_USE_OCSP 1
|
||||
#endif
|
||||
|
||||
#ifndef NGX_HTTP_PERMANENT_REDIRECT
|
||||
# define NGX_HTTP_PERMANENT_REDIRECT 308
|
||||
#endif
|
||||
|
||||
#ifndef NGX_HAVE_SHA1
|
||||
# if (nginx_version >= 1011002)
|
||||
# define NGX_HAVE_SHA1 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef MD5_DIGEST_LENGTH
|
||||
# define MD5_DIGEST_LENGTH 16
|
||||
#endif
|
||||
|
||||
#ifndef NGX_HTTP_LUA_MAX_ARGS
|
||||
# define NGX_HTTP_LUA_MAX_ARGS 100
|
||||
#endif
|
||||
|
||||
#ifndef NGX_HTTP_LUA_MAX_HEADERS
|
||||
# define NGX_HTTP_LUA_MAX_HEADERS 100
|
||||
#endif
|
||||
|
||||
|
||||
/* Nginx HTTP Lua Inline tag prefix */
|
||||
|
||||
#define NGX_HTTP_LUA_INLINE_TAG "nhli_"
|
||||
|
||||
#define NGX_HTTP_LUA_INLINE_TAG_LEN \
|
||||
(sizeof(NGX_HTTP_LUA_INLINE_TAG) - 1)
|
||||
|
||||
#define NGX_HTTP_LUA_INLINE_KEY_LEN \
|
||||
(NGX_HTTP_LUA_INLINE_TAG_LEN + 2 * MD5_DIGEST_LENGTH)
|
||||
|
||||
/* Nginx HTTP Lua File tag prefix */
|
||||
|
||||
#define NGX_HTTP_LUA_FILE_TAG "nhlf_"
|
||||
|
||||
#define NGX_HTTP_LUA_FILE_TAG_LEN \
|
||||
(sizeof(NGX_HTTP_LUA_FILE_TAG) - 1)
|
||||
|
||||
#define NGX_HTTP_LUA_FILE_KEY_LEN \
|
||||
(NGX_HTTP_LUA_FILE_TAG_LEN + 2 * MD5_DIGEST_LENGTH)
|
||||
|
||||
|
||||
/* must be within 16 bit */
|
||||
#define NGX_HTTP_LUA_CONTEXT_SET 0x0001
|
||||
#define NGX_HTTP_LUA_CONTEXT_REWRITE 0x0002
|
||||
#define NGX_HTTP_LUA_CONTEXT_ACCESS 0x0004
|
||||
#define NGX_HTTP_LUA_CONTEXT_CONTENT 0x0008
|
||||
#define NGX_HTTP_LUA_CONTEXT_LOG 0x0010
|
||||
#define NGX_HTTP_LUA_CONTEXT_HEADER_FILTER 0x0020
|
||||
#define NGX_HTTP_LUA_CONTEXT_BODY_FILTER 0x0040
|
||||
#define NGX_HTTP_LUA_CONTEXT_TIMER 0x0080
|
||||
#define NGX_HTTP_LUA_CONTEXT_INIT_WORKER 0x0100
|
||||
#define NGX_HTTP_LUA_CONTEXT_BALANCER 0x0200
|
||||
#define NGX_HTTP_LUA_CONTEXT_SSL_CERT 0x0400
|
||||
#define NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE 0x0800
|
||||
#define NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH 0x1000
|
||||
#define NGX_HTTP_LUA_CONTEXT_EXIT_WORKER 0x2000
|
||||
#define NGX_HTTP_LUA_CONTEXT_SSL_CLIENT_HELLO 0x4000
|
||||
#define NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE 0x8000
|
||||
|
||||
|
||||
#define NGX_HTTP_LUA_FFI_NO_REQ_CTX -100
|
||||
#define NGX_HTTP_LUA_FFI_BAD_CONTEXT -101
|
||||
|
||||
|
||||
#if (NGX_PTR_SIZE >= 8 && !defined(_WIN64))
|
||||
# define ngx_http_lua_lightudata_mask(ludata) \
|
||||
((void *) ((uintptr_t) (&ngx_http_lua_##ludata) & ((1UL << 47) - 1)))
|
||||
#else
|
||||
# define ngx_http_lua_lightudata_mask(ludata) \
|
||||
(&ngx_http_lua_##ludata)
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct ngx_http_lua_co_ctx_s ngx_http_lua_co_ctx_t;
|
||||
|
||||
typedef struct ngx_http_lua_sema_mm_s ngx_http_lua_sema_mm_t;
|
||||
|
||||
typedef union ngx_http_lua_srv_conf_u ngx_http_lua_srv_conf_t;
|
||||
|
||||
typedef struct ngx_http_lua_main_conf_s ngx_http_lua_main_conf_t;
|
||||
|
||||
typedef struct ngx_http_lua_header_val_s ngx_http_lua_header_val_t;
|
||||
|
||||
typedef struct ngx_http_lua_posted_thread_s ngx_http_lua_posted_thread_t;
|
||||
|
||||
typedef struct ngx_http_lua_balancer_peer_data_s
|
||||
ngx_http_lua_balancer_peer_data_t;
|
||||
|
||||
typedef ngx_int_t (*ngx_http_lua_main_conf_handler_pt)(ngx_log_t *log,
|
||||
ngx_http_lua_main_conf_t *lmcf, lua_State *L);
|
||||
|
||||
typedef ngx_int_t (*ngx_http_lua_srv_conf_handler_pt)(ngx_http_request_t *r,
|
||||
ngx_http_lua_srv_conf_t *lscf, lua_State *L);
|
||||
|
||||
typedef ngx_int_t (*ngx_http_lua_set_header_pt)(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value);
|
||||
|
||||
|
||||
typedef struct {
|
||||
u_char *package;
|
||||
lua_CFunction loader;
|
||||
} ngx_http_lua_preload_hook_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
int ref;
|
||||
lua_State *co;
|
||||
ngx_queue_t queue;
|
||||
} ngx_http_lua_thread_ref_t;
|
||||
|
||||
|
||||
struct ngx_http_lua_main_conf_s {
|
||||
lua_State *lua;
|
||||
ngx_pool_cleanup_t *vm_cleanup;
|
||||
|
||||
ngx_str_t lua_path;
|
||||
ngx_str_t lua_cpath;
|
||||
|
||||
ngx_cycle_t *cycle;
|
||||
ngx_pool_t *pool;
|
||||
|
||||
ngx_int_t max_pending_timers;
|
||||
ngx_int_t pending_timers;
|
||||
|
||||
ngx_int_t max_running_timers;
|
||||
ngx_int_t running_timers;
|
||||
|
||||
ngx_connection_t *watcher; /* for watching the process exit event */
|
||||
|
||||
ngx_int_t lua_thread_cache_max_entries;
|
||||
|
||||
ngx_hash_t builtin_headers_out;
|
||||
|
||||
#if (NGX_PCRE)
|
||||
ngx_int_t regex_cache_entries;
|
||||
ngx_int_t regex_cache_max_entries;
|
||||
ngx_int_t regex_match_limit;
|
||||
# if (LUA_HAVE_PCRE_JIT)
|
||||
pcre_jit_stack *jit_stack;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
ngx_array_t *shm_zones; /* of ngx_shm_zone_t* */
|
||||
|
||||
ngx_array_t *shdict_zones; /* shm zones of "shdict" */
|
||||
|
||||
ngx_array_t *preload_hooks; /* of ngx_http_lua_preload_hook_t */
|
||||
|
||||
ngx_flag_t postponed_to_rewrite_phase_end;
|
||||
ngx_flag_t postponed_to_access_phase_end;
|
||||
|
||||
ngx_http_lua_main_conf_handler_pt init_handler;
|
||||
ngx_str_t init_src;
|
||||
u_char *init_chunkname;
|
||||
|
||||
ngx_http_lua_main_conf_handler_pt init_worker_handler;
|
||||
ngx_str_t init_worker_src;
|
||||
u_char *init_worker_chunkname;
|
||||
|
||||
ngx_http_lua_main_conf_handler_pt exit_worker_handler;
|
||||
ngx_str_t exit_worker_src;
|
||||
u_char *exit_worker_chunkname;
|
||||
|
||||
ngx_http_lua_balancer_peer_data_t *balancer_peer_data;
|
||||
/* neither yielding nor recursion is possible in
|
||||
* balancer_by_lua*, so there cannot be any races among
|
||||
* concurrent requests and it is safe to store the peer
|
||||
* data pointer in the main conf.
|
||||
*/
|
||||
|
||||
ngx_chain_t *body_filter_chain;
|
||||
/* neither yielding nor recursion is possible in
|
||||
* body_filter_by_lua*, so there cannot be any races among
|
||||
* concurrent requests when storing the chain
|
||||
* data pointer in the main conf.
|
||||
*/
|
||||
|
||||
ngx_http_variable_value_t *setby_args;
|
||||
/* neither yielding nor recursion is possible in
|
||||
* set_by_lua*, so there cannot be any races among
|
||||
* concurrent requests when storing the args pointer
|
||||
* in the main conf.
|
||||
*/
|
||||
|
||||
size_t setby_nargs;
|
||||
/* neither yielding nor recursion is possible in
|
||||
* set_by_lua*, so there cannot be any races among
|
||||
* concurrent requests when storing the nargs in the
|
||||
* main conf.
|
||||
*/
|
||||
|
||||
ngx_uint_t shm_zones_inited;
|
||||
|
||||
ngx_http_lua_sema_mm_t *sema_mm;
|
||||
|
||||
ngx_uint_t malloc_trim_cycle; /* a cycle is defined as the number
|
||||
of requests */
|
||||
ngx_uint_t malloc_trim_req_count;
|
||||
|
||||
ngx_uint_t directive_line;
|
||||
|
||||
#if (nginx_version >= 1011011)
|
||||
/* the following 2 fields are only used by ngx.req.raw_headers() for now */
|
||||
ngx_buf_t **busy_buf_ptrs;
|
||||
ngx_int_t busy_buf_ptr_count;
|
||||
#endif
|
||||
|
||||
ngx_int_t host_var_index;
|
||||
|
||||
ngx_flag_t set_sa_restart;
|
||||
|
||||
ngx_queue_t free_lua_threads; /* of ngx_http_lua_thread_ref_t */
|
||||
ngx_queue_t cached_lua_threads; /* of ngx_http_lua_thread_ref_t */
|
||||
|
||||
ngx_uint_t worker_thread_vm_pool_size;
|
||||
|
||||
unsigned requires_header_filter:1;
|
||||
unsigned requires_body_filter:1;
|
||||
unsigned requires_capture_filter:1;
|
||||
unsigned requires_rewrite:1;
|
||||
unsigned requires_access:1;
|
||||
unsigned requires_log:1;
|
||||
unsigned requires_shm:1;
|
||||
unsigned requires_capture_log:1;
|
||||
unsigned requires_server_rewrite:1;
|
||||
};
|
||||
|
||||
|
||||
union ngx_http_lua_srv_conf_u {
|
||||
struct {
|
||||
#if (NGX_HTTP_SSL)
|
||||
ngx_http_lua_srv_conf_handler_pt ssl_cert_handler;
|
||||
ngx_str_t ssl_cert_src;
|
||||
u_char *ssl_cert_src_key;
|
||||
u_char *ssl_cert_chunkname;
|
||||
int ssl_cert_src_ref;
|
||||
|
||||
ngx_http_lua_srv_conf_handler_pt ssl_sess_store_handler;
|
||||
ngx_str_t ssl_sess_store_src;
|
||||
u_char *ssl_sess_store_src_key;
|
||||
u_char *ssl_sess_store_chunkname;
|
||||
int ssl_sess_store_src_ref;
|
||||
|
||||
ngx_http_lua_srv_conf_handler_pt ssl_sess_fetch_handler;
|
||||
ngx_str_t ssl_sess_fetch_src;
|
||||
u_char *ssl_sess_fetch_src_key;
|
||||
u_char *ssl_sess_fetch_chunkname;
|
||||
int ssl_sess_fetch_src_ref;
|
||||
|
||||
ngx_http_lua_srv_conf_handler_pt ssl_client_hello_handler;
|
||||
ngx_str_t ssl_client_hello_src;
|
||||
u_char *ssl_client_hello_src_key;
|
||||
u_char *ssl_client_hello_chunkname;
|
||||
int ssl_client_hello_src_ref;
|
||||
#endif
|
||||
|
||||
ngx_http_lua_srv_conf_handler_pt server_rewrite_handler;
|
||||
ngx_http_complex_value_t server_rewrite_src;
|
||||
u_char *server_rewrite_src_key;
|
||||
u_char *server_rewrite_chunkname;
|
||||
int server_rewrite_src_ref;
|
||||
} srv;
|
||||
|
||||
struct {
|
||||
ngx_http_lua_srv_conf_handler_pt handler;
|
||||
ngx_str_t src;
|
||||
u_char *src_key;
|
||||
u_char *chunkname;
|
||||
int src_ref;
|
||||
} balancer;
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
#if (NGX_HTTP_SSL)
|
||||
ngx_ssl_t *ssl; /* shared by SSL cosockets */
|
||||
ngx_uint_t ssl_protocols;
|
||||
ngx_str_t ssl_ciphers;
|
||||
ngx_uint_t ssl_verify_depth;
|
||||
ngx_str_t ssl_trusted_certificate;
|
||||
ngx_str_t ssl_crl;
|
||||
#if (nginx_version >= 1019004)
|
||||
ngx_array_t *ssl_conf_commands;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
ngx_flag_t force_read_body; /* whether force request body to
|
||||
be read */
|
||||
|
||||
ngx_flag_t enable_code_cache; /* whether to enable
|
||||
code cache */
|
||||
|
||||
ngx_flag_t http10_buffering;
|
||||
|
||||
ngx_http_handler_pt rewrite_handler;
|
||||
ngx_http_handler_pt access_handler;
|
||||
ngx_http_handler_pt content_handler;
|
||||
ngx_http_handler_pt log_handler;
|
||||
ngx_http_handler_pt header_filter_handler;
|
||||
|
||||
ngx_http_output_body_filter_pt body_filter_handler;
|
||||
|
||||
|
||||
|
||||
u_char *rewrite_chunkname;
|
||||
ngx_http_complex_value_t rewrite_src; /* rewrite_by_lua
|
||||
inline script/script
|
||||
file path */
|
||||
|
||||
u_char *rewrite_src_key; /* cached key for rewrite_src */
|
||||
int rewrite_src_ref;
|
||||
|
||||
u_char *access_chunkname;
|
||||
ngx_http_complex_value_t access_src; /* access_by_lua
|
||||
inline script/script
|
||||
file path */
|
||||
|
||||
u_char *access_src_key; /* cached key for access_src */
|
||||
int access_src_ref;
|
||||
|
||||
u_char *content_chunkname;
|
||||
ngx_http_complex_value_t content_src; /* content_by_lua
|
||||
inline script/script
|
||||
file path */
|
||||
|
||||
u_char *content_src_key; /* cached key for content_src */
|
||||
int content_src_ref;
|
||||
|
||||
|
||||
u_char *log_chunkname;
|
||||
ngx_http_complex_value_t log_src; /* log_by_lua inline script/script
|
||||
file path */
|
||||
|
||||
u_char *log_src_key; /* cached key for log_src */
|
||||
int log_src_ref;
|
||||
|
||||
ngx_http_complex_value_t header_filter_src; /* header_filter_by_lua
|
||||
inline script/script
|
||||
file path */
|
||||
|
||||
u_char *header_filter_chunkname;
|
||||
u_char *header_filter_src_key;
|
||||
/* cached key for header_filter_src */
|
||||
int header_filter_src_ref;
|
||||
|
||||
|
||||
ngx_http_complex_value_t body_filter_src;
|
||||
u_char *body_filter_src_key;
|
||||
u_char *body_filter_chunkname;
|
||||
int body_filter_src_ref;
|
||||
|
||||
ngx_msec_t keepalive_timeout;
|
||||
ngx_msec_t connect_timeout;
|
||||
ngx_msec_t send_timeout;
|
||||
ngx_msec_t read_timeout;
|
||||
|
||||
size_t send_lowat;
|
||||
size_t buffer_size;
|
||||
|
||||
ngx_uint_t pool_size;
|
||||
|
||||
ngx_flag_t transform_underscores_in_resp_headers;
|
||||
ngx_flag_t log_socket_errors;
|
||||
ngx_flag_t check_client_abort;
|
||||
ngx_flag_t use_default_type;
|
||||
} ngx_http_lua_loc_conf_t;
|
||||
|
||||
|
||||
typedef enum {
|
||||
NGX_HTTP_LUA_USER_CORO_NOP = 0,
|
||||
NGX_HTTP_LUA_USER_CORO_RESUME = 1,
|
||||
NGX_HTTP_LUA_USER_CORO_YIELD = 2,
|
||||
NGX_HTTP_LUA_USER_THREAD_RESUME = 3,
|
||||
} ngx_http_lua_user_coro_op_t;
|
||||
|
||||
|
||||
typedef enum {
|
||||
NGX_HTTP_LUA_CO_RUNNING = 0, /* coroutine running */
|
||||
NGX_HTTP_LUA_CO_SUSPENDED = 1, /* coroutine suspended */
|
||||
NGX_HTTP_LUA_CO_NORMAL = 2, /* coroutine normal */
|
||||
NGX_HTTP_LUA_CO_DEAD = 3, /* coroutine dead */
|
||||
NGX_HTTP_LUA_CO_ZOMBIE = 4, /* coroutine zombie */
|
||||
} ngx_http_lua_co_status_t;
|
||||
|
||||
|
||||
struct ngx_http_lua_posted_thread_s {
|
||||
ngx_http_lua_co_ctx_t *co_ctx;
|
||||
ngx_http_lua_posted_thread_t *next;
|
||||
};
|
||||
|
||||
|
||||
struct ngx_http_lua_co_ctx_s {
|
||||
void *data; /* user state for cosockets */
|
||||
|
||||
lua_State *co;
|
||||
ngx_http_lua_co_ctx_t *parent_co_ctx;
|
||||
|
||||
ngx_http_lua_posted_thread_t *zombie_child_threads;
|
||||
ngx_http_lua_posted_thread_t **next_zombie_child_thread;
|
||||
|
||||
ngx_http_cleanup_pt cleanup;
|
||||
|
||||
ngx_int_t *sr_statuses; /* all capture subrequest statuses */
|
||||
|
||||
ngx_http_headers_out_t **sr_headers;
|
||||
|
||||
ngx_str_t *sr_bodies; /* all captured subrequest bodies */
|
||||
|
||||
uint8_t *sr_flags;
|
||||
|
||||
unsigned nresults_from_worker_thread; /* number of results
|
||||
* from worker
|
||||
* thread callback */
|
||||
unsigned nrets; /* ngx_http_lua_run_thread nrets arg. */
|
||||
|
||||
unsigned nsubreqs; /* number of subrequests of the
|
||||
* current request */
|
||||
|
||||
unsigned pending_subreqs; /* number of subrequests being
|
||||
waited */
|
||||
|
||||
ngx_event_t sleep; /* used for ngx.sleep */
|
||||
|
||||
ngx_queue_t sem_wait_queue;
|
||||
|
||||
#ifdef NGX_LUA_USE_ASSERT
|
||||
int co_top; /* stack top after yielding/creation,
|
||||
only for sanity checks */
|
||||
#endif
|
||||
|
||||
int co_ref; /* reference to anchor the thread
|
||||
coroutines (entry coroutine and user
|
||||
threads) in the Lua registry,
|
||||
preventing the thread coroutine
|
||||
from beging collected by the
|
||||
Lua GC */
|
||||
|
||||
unsigned waited_by_parent:1; /* whether being waited by
|
||||
a parent coroutine */
|
||||
|
||||
unsigned co_status:3; /* the current coroutine's status */
|
||||
|
||||
unsigned flushing:1; /* indicates whether the current
|
||||
coroutine is waiting for
|
||||
ngx.flush(true) */
|
||||
|
||||
unsigned is_uthread:1; /* whether the current coroutine is
|
||||
a user thread */
|
||||
|
||||
unsigned thread_spawn_yielded:1; /* yielded from
|
||||
the ngx.thread.spawn()
|
||||
call */
|
||||
unsigned sem_resume_status:1;
|
||||
|
||||
unsigned is_wrap:1; /* set when creating coroutines via
|
||||
coroutine.wrap */
|
||||
|
||||
unsigned propagate_error:1; /* set when propagating an error
|
||||
from a coroutine to its
|
||||
parent */
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
lua_State *vm;
|
||||
ngx_int_t count;
|
||||
} ngx_http_lua_vm_state_t;
|
||||
|
||||
|
||||
typedef struct ngx_http_lua_ctx_s {
|
||||
/* for lua_code_cache off: */
|
||||
ngx_http_lua_vm_state_t *vm_state;
|
||||
|
||||
ngx_http_request_t *request;
|
||||
ngx_http_handler_pt resume_handler;
|
||||
|
||||
ngx_http_lua_co_ctx_t *cur_co_ctx; /* co ctx for the current coroutine */
|
||||
|
||||
/* FIXME: we should use rbtree here to prevent O(n) lookup overhead */
|
||||
ngx_list_t *user_co_ctx; /* coroutine contexts for user
|
||||
coroutines */
|
||||
|
||||
ngx_http_lua_co_ctx_t entry_co_ctx; /* coroutine context for the
|
||||
entry coroutine */
|
||||
|
||||
ngx_http_lua_co_ctx_t *on_abort_co_ctx; /* coroutine context for the
|
||||
on_abort thread */
|
||||
|
||||
int ctx_ref; /* reference to anchor
|
||||
request ctx data in lua
|
||||
registry */
|
||||
|
||||
unsigned flushing_coros; /* number of coroutines waiting on
|
||||
ngx.flush(true) */
|
||||
|
||||
ngx_chain_t *out; /* buffered output chain for HTTP 1.0 */
|
||||
ngx_chain_t *free_bufs;
|
||||
ngx_chain_t *busy_bufs;
|
||||
ngx_chain_t *free_recv_bufs;
|
||||
|
||||
ngx_chain_t *filter_in_bufs; /* for the body filter */
|
||||
ngx_chain_t *filter_busy_bufs; /* for the body filter */
|
||||
|
||||
ngx_pool_cleanup_pt *cleanup;
|
||||
|
||||
ngx_http_cleanup_t *free_cleanup; /* free list of cleanup records */
|
||||
|
||||
ngx_chain_t *body; /* buffered subrequest response body
|
||||
chains */
|
||||
|
||||
ngx_chain_t **last_body; /* for the "body" field */
|
||||
|
||||
ngx_str_t exec_uri;
|
||||
ngx_str_t exec_args;
|
||||
|
||||
ngx_int_t exit_code;
|
||||
|
||||
void *downstream; /* can be either
|
||||
ngx_http_lua_socket_tcp_upstream_t
|
||||
or ngx_http_lua_co_ctx_t */
|
||||
|
||||
ngx_uint_t index; /* index of the current
|
||||
subrequest in its parent
|
||||
request */
|
||||
|
||||
ngx_http_lua_posted_thread_t *posted_threads;
|
||||
|
||||
int uthreads; /* number of active user threads */
|
||||
|
||||
uint16_t context; /* the current running directive context
|
||||
(or running phase) for the current
|
||||
Lua chunk */
|
||||
|
||||
unsigned run_post_subrequest:1; /* whether it has run
|
||||
post_subrequest
|
||||
(for subrequests only) */
|
||||
|
||||
unsigned waiting_more_body:1; /* 1: waiting for more
|
||||
request body data;
|
||||
0: no need to wait */
|
||||
|
||||
unsigned co_op:2; /* coroutine API operation */
|
||||
|
||||
unsigned exited:1;
|
||||
|
||||
unsigned eof:1; /* 1: last_buf has been sent;
|
||||
0: last_buf not sent yet */
|
||||
|
||||
unsigned capture:1; /* 1: response body of current request
|
||||
is to be captured by the lua
|
||||
capture filter,
|
||||
0: not to be captured */
|
||||
|
||||
|
||||
unsigned read_body_done:1; /* 1: request body has been all
|
||||
read; 0: body has not been
|
||||
all read */
|
||||
|
||||
unsigned headers_set:1; /* whether the user has set custom
|
||||
response headers */
|
||||
unsigned mime_set:1; /* whether the user has set Content-Type
|
||||
response header */
|
||||
unsigned entered_server_rewrite_phase:1;
|
||||
unsigned entered_rewrite_phase:1;
|
||||
unsigned entered_access_phase:1;
|
||||
unsigned entered_content_phase:1;
|
||||
|
||||
unsigned buffering:1; /* HTTP 1.0 response body buffering flag */
|
||||
|
||||
unsigned no_abort:1; /* prohibit "world abortion" via ngx.exit()
|
||||
and etc */
|
||||
|
||||
unsigned header_sent:1; /* r->header_sent is not sufficient for
|
||||
* this because special header filters
|
||||
* like ngx_image_filter may intercept
|
||||
* the header. so we should always test
|
||||
* both flags. see the test case in
|
||||
* t/020-subrequest.t */
|
||||
|
||||
unsigned seen_last_in_filter:1; /* used by body_filter_by_lua* */
|
||||
unsigned seen_last_for_subreq:1; /* used by body capture filter */
|
||||
unsigned writing_raw_req_socket:1; /* used by raw downstream
|
||||
socket */
|
||||
unsigned acquired_raw_req_socket:1; /* whether a raw req socket
|
||||
is acquired */
|
||||
unsigned seen_body_data:1;
|
||||
} ngx_http_lua_ctx_t;
|
||||
|
||||
|
||||
struct ngx_http_lua_header_val_s {
|
||||
ngx_http_complex_value_t value;
|
||||
ngx_uint_t hash;
|
||||
ngx_str_t key;
|
||||
ngx_http_lua_set_header_pt handler;
|
||||
ngx_uint_t offset;
|
||||
unsigned no_override;
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t name;
|
||||
ngx_uint_t offset;
|
||||
ngx_http_lua_set_header_pt handler;
|
||||
} ngx_http_lua_set_header_t;
|
||||
|
||||
|
||||
extern ngx_module_t ngx_http_lua_module;
|
||||
extern ngx_http_output_header_filter_pt ngx_http_lua_next_header_filter;
|
||||
extern ngx_http_output_body_filter_pt ngx_http_lua_next_body_filter;
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_COMMON_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,70 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_http_lua_config.h"
|
||||
#include "api/ngx_http_lua_api.h"
|
||||
|
||||
|
||||
static int ngx_http_lua_config_prefix(lua_State *L);
|
||||
static int ngx_http_lua_config_configure(lua_State *L);
|
||||
|
||||
|
||||
void
|
||||
ngx_http_lua_inject_config_api(lua_State *L)
|
||||
{
|
||||
/* ngx.config */
|
||||
|
||||
lua_createtable(L, 0, 6 /* nrec */); /* .config */
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
lua_pushboolean(L, 1);
|
||||
#else
|
||||
lua_pushboolean(L, 0);
|
||||
#endif
|
||||
lua_setfield(L, -2, "debug");
|
||||
|
||||
lua_pushcfunction(L, ngx_http_lua_config_prefix);
|
||||
lua_setfield(L, -2, "prefix");
|
||||
|
||||
lua_pushinteger(L, nginx_version);
|
||||
lua_setfield(L, -2, "nginx_version");
|
||||
|
||||
lua_pushinteger(L, ngx_http_lua_version);
|
||||
lua_setfield(L, -2, "ngx_lua_version");
|
||||
|
||||
lua_pushcfunction(L, ngx_http_lua_config_configure);
|
||||
lua_setfield(L, -2, "nginx_configure");
|
||||
|
||||
lua_pushliteral(L, "http");
|
||||
lua_setfield(L, -2, "subsystem");
|
||||
|
||||
lua_setfield(L, -2, "config");
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_http_lua_config_prefix(lua_State *L)
|
||||
{
|
||||
lua_pushlstring(L, (char *) ngx_cycle->prefix.data,
|
||||
ngx_cycle->prefix.len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_http_lua_config_configure(lua_State *L)
|
||||
{
|
||||
lua_pushliteral(L, NGX_CONFIGURE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,19 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_CONFIG_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_CONFIG_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
void ngx_http_lua_inject_config_api(lua_State *L);
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_CONFIG_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,204 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_http_lua_consts.h"
|
||||
|
||||
|
||||
void
|
||||
ngx_http_lua_inject_core_consts(lua_State *L)
|
||||
{
|
||||
/* {{{ core constants */
|
||||
lua_pushinteger(L, NGX_OK);
|
||||
lua_setfield(L, -2, "OK");
|
||||
|
||||
lua_pushinteger(L, NGX_AGAIN);
|
||||
lua_setfield(L, -2, "AGAIN");
|
||||
|
||||
lua_pushinteger(L, NGX_DONE);
|
||||
lua_setfield(L, -2, "DONE");
|
||||
|
||||
lua_pushinteger(L, NGX_DECLINED);
|
||||
lua_setfield(L, -2, "DECLINED");
|
||||
|
||||
lua_pushinteger(L, NGX_ERROR);
|
||||
lua_setfield(L, -2, "ERROR");
|
||||
|
||||
lua_pushlightuserdata(L, NULL);
|
||||
lua_setfield(L, -2, "null");
|
||||
/* }}} */
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_http_lua_inject_http_consts(lua_State *L)
|
||||
{
|
||||
/* {{{ HTTP status constants */
|
||||
lua_pushinteger(L, NGX_HTTP_GET);
|
||||
lua_setfield(L, -2, "HTTP_GET");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_POST);
|
||||
lua_setfield(L, -2, "HTTP_POST");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_PUT);
|
||||
lua_setfield(L, -2, "HTTP_PUT");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_HEAD);
|
||||
lua_setfield(L, -2, "HTTP_HEAD");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_DELETE);
|
||||
lua_setfield(L, -2, "HTTP_DELETE");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_OPTIONS);
|
||||
lua_setfield(L, -2, "HTTP_OPTIONS");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_MKCOL);
|
||||
lua_setfield(L, -2, "HTTP_MKCOL");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_COPY);
|
||||
lua_setfield(L, -2, "HTTP_COPY");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_MOVE);
|
||||
lua_setfield(L, -2, "HTTP_MOVE");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_PROPFIND);
|
||||
lua_setfield(L, -2, "HTTP_PROPFIND");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_PROPPATCH);
|
||||
lua_setfield(L, -2, "HTTP_PROPPATCH");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_LOCK);
|
||||
lua_setfield(L, -2, "HTTP_LOCK");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_UNLOCK);
|
||||
lua_setfield(L, -2, "HTTP_UNLOCK");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_PATCH);
|
||||
lua_setfield(L, -2, "HTTP_PATCH");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_TRACE);
|
||||
lua_setfield(L, -2, "HTTP_TRACE");
|
||||
/* }}} */
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_CONTINUE);
|
||||
lua_setfield(L, -2, "HTTP_CONTINUE");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_SWITCHING_PROTOCOLS);
|
||||
lua_setfield(L, -2, "HTTP_SWITCHING_PROTOCOLS");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_OK);
|
||||
lua_setfield(L, -2, "HTTP_OK");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_CREATED);
|
||||
lua_setfield(L, -2, "HTTP_CREATED");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_ACCEPTED);
|
||||
lua_setfield(L, -2, "HTTP_ACCEPTED");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_NO_CONTENT);
|
||||
lua_setfield(L, -2, "HTTP_NO_CONTENT");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_PARTIAL_CONTENT);
|
||||
lua_setfield(L, -2, "HTTP_PARTIAL_CONTENT");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_SPECIAL_RESPONSE);
|
||||
lua_setfield(L, -2, "HTTP_SPECIAL_RESPONSE");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_MOVED_PERMANENTLY);
|
||||
lua_setfield(L, -2, "HTTP_MOVED_PERMANENTLY");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_MOVED_TEMPORARILY);
|
||||
lua_setfield(L, -2, "HTTP_MOVED_TEMPORARILY");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_SEE_OTHER);
|
||||
lua_setfield(L, -2, "HTTP_SEE_OTHER");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_PERMANENT_REDIRECT);
|
||||
lua_setfield(L, -2, "HTTP_PERMANENT_REDIRECT");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_NOT_MODIFIED);
|
||||
lua_setfield(L, -2, "HTTP_NOT_MODIFIED");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_TEMPORARY_REDIRECT);
|
||||
lua_setfield(L, -2, "HTTP_TEMPORARY_REDIRECT");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_BAD_REQUEST);
|
||||
lua_setfield(L, -2, "HTTP_BAD_REQUEST");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_UNAUTHORIZED);
|
||||
lua_setfield(L, -2, "HTTP_UNAUTHORIZED");
|
||||
|
||||
lua_pushinteger(L, 402);
|
||||
lua_setfield(L, -2, "HTTP_PAYMENT_REQUIRED");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_FORBIDDEN);
|
||||
lua_setfield(L, -2, "HTTP_FORBIDDEN");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_NOT_FOUND);
|
||||
lua_setfield(L, -2, "HTTP_NOT_FOUND");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_NOT_ALLOWED);
|
||||
lua_setfield(L, -2, "HTTP_NOT_ALLOWED");
|
||||
|
||||
lua_pushinteger(L, 406);
|
||||
lua_setfield(L, -2, "HTTP_NOT_ACCEPTABLE");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_REQUEST_TIME_OUT);
|
||||
lua_setfield(L, -2, "HTTP_REQUEST_TIMEOUT");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_CONFLICT);
|
||||
lua_setfield(L, -2, "HTTP_CONFLICT");
|
||||
|
||||
lua_pushinteger(L, 410);
|
||||
lua_setfield(L, -2, "HTTP_GONE");
|
||||
|
||||
lua_pushinteger(L, 426);
|
||||
lua_setfield(L, -2, "HTTP_UPGRADE_REQUIRED");
|
||||
|
||||
lua_pushinteger(L, 429);
|
||||
lua_setfield(L, -2, "HTTP_TOO_MANY_REQUESTS");
|
||||
|
||||
lua_pushinteger(L, 451);
|
||||
lua_setfield(L, -2, "HTTP_ILLEGAL");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_CLOSE);
|
||||
lua_setfield(L, -2, "HTTP_CLOSE");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||
lua_setfield(L, -2, "HTTP_INTERNAL_SERVER_ERROR");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_NOT_IMPLEMENTED);
|
||||
lua_setfield(L, -2, "HTTP_NOT_IMPLEMENTED");
|
||||
|
||||
/* keep for backward compatibility */
|
||||
lua_pushinteger(L, NGX_HTTP_NOT_IMPLEMENTED);
|
||||
lua_setfield(L, -2, "HTTP_METHOD_NOT_IMPLEMENTED");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_BAD_GATEWAY);
|
||||
lua_setfield(L, -2, "HTTP_BAD_GATEWAY");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_SERVICE_UNAVAILABLE);
|
||||
lua_setfield(L, -2, "HTTP_SERVICE_UNAVAILABLE");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_GATEWAY_TIME_OUT);
|
||||
lua_setfield(L, -2, "HTTP_GATEWAY_TIMEOUT");
|
||||
|
||||
lua_pushinteger(L, 505);
|
||||
lua_setfield(L, -2, "HTTP_VERSION_NOT_SUPPORTED");
|
||||
|
||||
lua_pushinteger(L, NGX_HTTP_INSUFFICIENT_STORAGE);
|
||||
lua_setfield(L, -2, "HTTP_INSUFFICIENT_STORAGE");
|
||||
|
||||
/* }}} */
|
||||
}
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_CONSTS_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_CONSTS_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
void ngx_http_lua_inject_http_consts(lua_State *L);
|
||||
void ngx_http_lua_inject_core_consts(lua_State *L);
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_CONSTS_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,389 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_http_lua_contentby.h"
|
||||
#include "ngx_http_lua_util.h"
|
||||
#include "ngx_http_lua_exception.h"
|
||||
#include "ngx_http_lua_cache.h"
|
||||
#include "ngx_http_lua_probe.h"
|
||||
|
||||
|
||||
static void ngx_http_lua_content_phase_post_read(ngx_http_request_t *r);
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r)
|
||||
{
|
||||
int co_ref;
|
||||
ngx_int_t rc;
|
||||
lua_State *co;
|
||||
ngx_event_t *rev;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_pool_cleanup_t *cln;
|
||||
|
||||
ngx_http_lua_loc_conf_t *llcf;
|
||||
|
||||
dd("content by chunk");
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
|
||||
if (ctx == NULL) {
|
||||
ctx = ngx_http_lua_create_ctx(r);
|
||||
if (ctx == NULL) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
} else {
|
||||
dd("reset ctx");
|
||||
ngx_http_lua_reset_ctx(r, L, ctx);
|
||||
}
|
||||
|
||||
ctx->entered_content_phase = 1;
|
||||
|
||||
/* {{{ new coroutine to handle request */
|
||||
co = ngx_http_lua_new_thread(r, L, &co_ref);
|
||||
|
||||
if (co == NULL) {
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"lua: failed to create new coroutine to handle request");
|
||||
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
/* move code closure to new coroutine */
|
||||
lua_xmove(L, co, 1);
|
||||
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
/* set closure's env table to new coroutine's globals table */
|
||||
ngx_http_lua_get_globals_table(co);
|
||||
lua_setfenv(co, -2);
|
||||
#endif
|
||||
|
||||
/* save nginx request in coroutine globals table */
|
||||
ngx_http_lua_set_req(co, r);
|
||||
|
||||
ctx->cur_co_ctx = &ctx->entry_co_ctx;
|
||||
ctx->cur_co_ctx->co = co;
|
||||
ctx->cur_co_ctx->co_ref = co_ref;
|
||||
#ifdef NGX_LUA_USE_ASSERT
|
||||
ctx->cur_co_ctx->co_top = 1;
|
||||
#endif
|
||||
|
||||
ngx_http_lua_attach_co_ctx_to_L(co, ctx->cur_co_ctx);
|
||||
|
||||
/* {{{ register request cleanup hooks */
|
||||
if (ctx->cleanup == NULL) {
|
||||
cln = ngx_pool_cleanup_add(r->pool, 0);
|
||||
if (cln == NULL) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
cln->handler = ngx_http_lua_request_cleanup_handler;
|
||||
cln->data = ctx;
|
||||
ctx->cleanup = &cln->handler;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
ctx->context = NGX_HTTP_LUA_CONTEXT_CONTENT;
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
|
||||
if (llcf->check_client_abort) {
|
||||
r->read_event_handler = ngx_http_lua_rd_check_broken_connection;
|
||||
|
||||
#if (NGX_HTTP_V2)
|
||||
if (!r->stream) {
|
||||
#endif
|
||||
|
||||
rev = r->connection->read;
|
||||
|
||||
if (!rev->active) {
|
||||
if (ngx_add_event(rev, NGX_READ_EVENT, 0) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
#if (NGX_HTTP_V2)
|
||||
}
|
||||
#endif
|
||||
|
||||
} else {
|
||||
r->read_event_handler = ngx_http_block_reading;
|
||||
}
|
||||
|
||||
rc = ngx_http_lua_run_thread(L, r, ctx, 0);
|
||||
|
||||
if (rc == NGX_ERROR || rc >= NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (rc == NGX_AGAIN) {
|
||||
return ngx_http_lua_content_run_posted_threads(L, r, ctx, 0);
|
||||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
return ngx_http_lua_content_run_posted_threads(L, r, ctx, 1);
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_http_lua_content_wev_handler(ngx_http_request_t *r)
|
||||
{
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
(void) ctx->resume_handler(r);
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_content_handler(ngx_http_request_t *r)
|
||||
{
|
||||
ngx_http_lua_loc_conf_t *llcf;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_int_t rc;
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua content handler, uri:\"%V\" c:%ud", &r->uri,
|
||||
r->main->count);
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
|
||||
if (llcf->content_handler == NULL) {
|
||||
dd("no content handler found");
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
|
||||
dd("ctx = %p", ctx);
|
||||
|
||||
if (ctx == NULL) {
|
||||
ctx = ngx_http_lua_create_ctx(r);
|
||||
if (ctx == NULL) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
dd("entered? %d", (int) ctx->entered_content_phase);
|
||||
|
||||
if (ctx->waiting_more_body) {
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
if (ctx->entered_content_phase) {
|
||||
dd("calling wev handler");
|
||||
rc = ctx->resume_handler(r);
|
||||
dd("wev handler returns %d", (int) rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (llcf->force_read_body && !ctx->read_body_done) {
|
||||
r->request_body_in_single_buf = 1;
|
||||
r->request_body_in_persistent_file = 1;
|
||||
r->request_body_in_clean_file = 1;
|
||||
|
||||
rc = ngx_http_read_client_request_body(r,
|
||||
ngx_http_lua_content_phase_post_read);
|
||||
|
||||
if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (rc == NGX_AGAIN) {
|
||||
ctx->waiting_more_body = 1;
|
||||
|
||||
return NGX_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
dd("setting entered");
|
||||
|
||||
ctx->entered_content_phase = 1;
|
||||
|
||||
dd("calling content handler");
|
||||
return llcf->content_handler(r);
|
||||
}
|
||||
|
||||
|
||||
/* post read callback for the content phase */
|
||||
static void
|
||||
ngx_http_lua_content_phase_post_read(ngx_http_request_t *r)
|
||||
{
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
|
||||
ctx->read_body_done = 1;
|
||||
|
||||
if (ctx->waiting_more_body) {
|
||||
ctx->waiting_more_body = 0;
|
||||
ngx_http_lua_finalize_request(r, ngx_http_lua_content_handler(r));
|
||||
|
||||
} else {
|
||||
r->main->count--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_content_handler_file(ngx_http_request_t *r)
|
||||
{
|
||||
lua_State *L;
|
||||
ngx_int_t rc;
|
||||
u_char *script_path;
|
||||
ngx_http_lua_loc_conf_t *llcf;
|
||||
ngx_str_t eval_src;
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
|
||||
if (ngx_http_complex_value(r, &llcf->content_src, &eval_src) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
script_path = ngx_http_lua_rebase_path(r->pool, eval_src.data,
|
||||
eval_src.len);
|
||||
|
||||
if (script_path == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
L = ngx_http_lua_get_lua_vm(r, NULL);
|
||||
|
||||
/* load Lua script file (w/ cache) sp = 1 */
|
||||
rc = ngx_http_lua_cache_loadfile(r->connection->log, L, script_path,
|
||||
&llcf->content_src_ref,
|
||||
llcf->content_src_key);
|
||||
if (rc != NGX_OK) {
|
||||
if (rc < NGX_HTTP_SPECIAL_RESPONSE) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* make sure we have a valid code chunk */
|
||||
ngx_http_lua_assert(lua_isfunction(L, -1));
|
||||
|
||||
return ngx_http_lua_content_by_chunk(L, r);
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_content_handler_inline(ngx_http_request_t *r)
|
||||
{
|
||||
lua_State *L;
|
||||
ngx_int_t rc;
|
||||
ngx_http_lua_loc_conf_t *llcf;
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
|
||||
L = ngx_http_lua_get_lua_vm(r, NULL);
|
||||
|
||||
/* load Lua inline script (w/ cache) sp = 1 */
|
||||
rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L,
|
||||
llcf->content_src.value.data,
|
||||
llcf->content_src.value.len,
|
||||
&llcf->content_src_ref,
|
||||
llcf->content_src_key,
|
||||
(const char *)
|
||||
llcf->content_chunkname);
|
||||
if (rc != NGX_OK) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
return ngx_http_lua_content_by_chunk(L, r);
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_content_run_posted_threads(lua_State *L, ngx_http_request_t *r,
|
||||
ngx_http_lua_ctx_t *ctx, int n)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
ngx_http_lua_posted_thread_t *pt;
|
||||
|
||||
dd("run posted threads: %p", ctx->posted_threads);
|
||||
|
||||
for ( ;; ) {
|
||||
pt = ctx->posted_threads;
|
||||
if (pt == NULL) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
ctx->posted_threads = pt->next;
|
||||
|
||||
ngx_http_lua_probe_run_posted_thread(r, pt->co_ctx->co,
|
||||
(int) pt->co_ctx->co_status);
|
||||
|
||||
dd("posted thread status: %d", pt->co_ctx->co_status);
|
||||
|
||||
if (pt->co_ctx->co_status != NGX_HTTP_LUA_CO_RUNNING) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ctx->cur_co_ctx = pt->co_ctx;
|
||||
|
||||
rc = ngx_http_lua_run_thread(L, r, ctx, 0);
|
||||
|
||||
if (rc == NGX_AGAIN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
n++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rc == NGX_OK) {
|
||||
while (n > 0) {
|
||||
ngx_http_lua_finalize_request(r, NGX_DONE);
|
||||
n--;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
/* rc == NGX_ERROR || rc > NGX_OK */
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
if (n == 1) {
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
r->main->count++;
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
/* n > 1 */
|
||||
|
||||
do {
|
||||
ngx_http_lua_finalize_request(r, NGX_DONE);
|
||||
} while (--n > 1);
|
||||
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,26 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_CONTENT_BY_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_CONTENT_BY_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
ngx_int_t ngx_http_lua_content_by_chunk(lua_State *L, ngx_http_request_t *r);
|
||||
void ngx_http_lua_content_wev_handler(ngx_http_request_t *r);
|
||||
ngx_int_t ngx_http_lua_content_handler_file(ngx_http_request_t *r);
|
||||
ngx_int_t ngx_http_lua_content_handler_inline(ngx_http_request_t *r);
|
||||
ngx_int_t ngx_http_lua_content_handler(ngx_http_request_t *r);
|
||||
ngx_int_t ngx_http_lua_content_run_posted_threads(lua_State *L,
|
||||
ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, int n);
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_CONTENT_BY_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,465 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_http_lua_control.h"
|
||||
#include "ngx_http_lua_util.h"
|
||||
#include "ngx_http_lua_coroutine.h"
|
||||
|
||||
|
||||
static int ngx_http_lua_ngx_exec(lua_State *L);
|
||||
static int ngx_http_lua_ngx_redirect(lua_State *L);
|
||||
static int ngx_http_lua_on_abort(lua_State *L);
|
||||
|
||||
|
||||
void
|
||||
ngx_http_lua_inject_control_api(ngx_log_t *log, lua_State *L)
|
||||
{
|
||||
/* ngx.redirect */
|
||||
|
||||
lua_pushcfunction(L, ngx_http_lua_ngx_redirect);
|
||||
lua_setfield(L, -2, "redirect");
|
||||
|
||||
/* ngx.exec */
|
||||
|
||||
lua_pushcfunction(L, ngx_http_lua_ngx_exec);
|
||||
lua_setfield(L, -2, "exec");
|
||||
|
||||
/* ngx.on_abort */
|
||||
|
||||
lua_pushcfunction(L, ngx_http_lua_on_abort);
|
||||
lua_setfield(L, -2, "on_abort");
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_http_lua_ngx_exec(lua_State *L)
|
||||
{
|
||||
int n;
|
||||
ngx_http_request_t *r;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_str_t uri;
|
||||
ngx_str_t args, user_args;
|
||||
ngx_uint_t flags;
|
||||
u_char *p;
|
||||
u_char *q;
|
||||
size_t len;
|
||||
const char *msg;
|
||||
|
||||
n = lua_gettop(L);
|
||||
if (n != 1 && n != 2) {
|
||||
return luaL_error(L, "expecting one or two arguments, but got %d",
|
||||
n);
|
||||
}
|
||||
|
||||
r = ngx_http_lua_get_req(L);
|
||||
if (r == NULL) {
|
||||
return luaL_error(L, "no request object found");
|
||||
}
|
||||
|
||||
ngx_str_null(&args);
|
||||
|
||||
/* read the 1st argument (uri) */
|
||||
|
||||
p = (u_char *) luaL_checklstring(L, 1, &len);
|
||||
|
||||
if (len == 0) {
|
||||
return luaL_error(L, "The uri argument is empty");
|
||||
}
|
||||
|
||||
uri.data = ngx_palloc(r->pool, len);
|
||||
if (uri.data == NULL) {
|
||||
return luaL_error(L, "no memory");
|
||||
}
|
||||
|
||||
ngx_memcpy(uri.data, p, len);
|
||||
|
||||
uri.len = len;
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return luaL_error(L, "no ctx found");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE
|
||||
| NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE
|
||||
| NGX_HTTP_LUA_CONTEXT_ACCESS
|
||||
| NGX_HTTP_LUA_CONTEXT_CONTENT);
|
||||
|
||||
ngx_http_lua_check_if_abortable(L, ctx);
|
||||
|
||||
flags = NGX_HTTP_LOG_UNSAFE;
|
||||
|
||||
if (ngx_http_parse_unsafe_uri(r, &uri, &args, &flags) != NGX_OK) {
|
||||
return luaL_error(L, "unsafe uri");
|
||||
}
|
||||
|
||||
if (n == 2) {
|
||||
/* read the 2nd argument (args) */
|
||||
dd("args type: %s", luaL_typename(L, 2));
|
||||
|
||||
switch (lua_type(L, 2)) {
|
||||
case LUA_TNUMBER:
|
||||
case LUA_TSTRING:
|
||||
p = (u_char *) lua_tolstring(L, 2, &len);
|
||||
|
||||
user_args.data = ngx_palloc(r->pool, len);
|
||||
if (user_args.data == NULL) {
|
||||
return luaL_error(L, "no memory");
|
||||
}
|
||||
|
||||
ngx_memcpy(user_args.data, p, len);
|
||||
|
||||
user_args.len = len;
|
||||
break;
|
||||
|
||||
case LUA_TTABLE:
|
||||
ngx_http_lua_process_args_option(r, L, 2, &user_args);
|
||||
|
||||
dd("user_args: %.*s", (int) user_args.len, user_args.data);
|
||||
|
||||
break;
|
||||
|
||||
case LUA_TNIL:
|
||||
ngx_str_null(&user_args);
|
||||
break;
|
||||
|
||||
default:
|
||||
msg = lua_pushfstring(L, "string, number, or table expected, "
|
||||
"but got %s", luaL_typename(L, 2));
|
||||
return luaL_argerror(L, 2, msg);
|
||||
}
|
||||
|
||||
} else {
|
||||
user_args.data = NULL;
|
||||
user_args.len = 0;
|
||||
}
|
||||
|
||||
if (user_args.len) {
|
||||
if (args.len == 0) {
|
||||
args = user_args;
|
||||
|
||||
} else {
|
||||
p = ngx_palloc(r->pool, args.len + user_args.len + 1);
|
||||
if (p == NULL) {
|
||||
return luaL_error(L, "no memory");
|
||||
}
|
||||
|
||||
q = ngx_copy(p, args.data, args.len);
|
||||
*q++ = '&';
|
||||
ngx_memcpy(q, user_args.data, user_args.len);
|
||||
|
||||
args.data = p;
|
||||
args.len += user_args.len + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (r->header_sent || ctx->header_sent) {
|
||||
return luaL_error(L, "attempt to call ngx.exec after "
|
||||
"sending out response headers");
|
||||
}
|
||||
|
||||
ctx->exec_uri = uri;
|
||||
ctx->exec_args = args;
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua exec \"%V?%V\"",
|
||||
&ctx->exec_uri, &ctx->exec_args);
|
||||
|
||||
return lua_yield(L, 0);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_http_lua_ngx_redirect(lua_State *L)
|
||||
{
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_int_t rc;
|
||||
int n;
|
||||
u_char *p;
|
||||
u_char *uri;
|
||||
u_char byte;
|
||||
size_t len;
|
||||
ngx_table_elt_t *h;
|
||||
ngx_http_request_t *r;
|
||||
size_t buf_len;
|
||||
u_char *buf;
|
||||
|
||||
n = lua_gettop(L);
|
||||
|
||||
if (n != 1 && n != 2) {
|
||||
return luaL_error(L, "expecting one or two arguments");
|
||||
}
|
||||
|
||||
p = (u_char *) luaL_checklstring(L, 1, &len);
|
||||
|
||||
if (n == 2) {
|
||||
rc = (ngx_int_t) luaL_checknumber(L, 2);
|
||||
|
||||
if (rc != NGX_HTTP_MOVED_TEMPORARILY
|
||||
&& rc != NGX_HTTP_MOVED_PERMANENTLY
|
||||
&& rc != NGX_HTTP_SEE_OTHER
|
||||
&& rc != NGX_HTTP_PERMANENT_REDIRECT
|
||||
&& rc != NGX_HTTP_TEMPORARY_REDIRECT)
|
||||
{
|
||||
return luaL_error(L, "only ngx.HTTP_MOVED_TEMPORARILY, "
|
||||
"ngx.HTTP_MOVED_PERMANENTLY, "
|
||||
"ngx.HTTP_PERMANENT_REDIRECT, "
|
||||
"ngx.HTTP_SEE_OTHER, and "
|
||||
"ngx.HTTP_TEMPORARY_REDIRECT are allowed");
|
||||
}
|
||||
|
||||
} else {
|
||||
rc = NGX_HTTP_MOVED_TEMPORARILY;
|
||||
}
|
||||
|
||||
r = ngx_http_lua_get_req(L);
|
||||
if (r == NULL) {
|
||||
return luaL_error(L, "no request object found");
|
||||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return luaL_error(L, "no request ctx found");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE
|
||||
| NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE
|
||||
| NGX_HTTP_LUA_CONTEXT_ACCESS
|
||||
| NGX_HTTP_LUA_CONTEXT_CONTENT);
|
||||
|
||||
ngx_http_lua_check_if_abortable(L, ctx);
|
||||
|
||||
if (r->header_sent || ctx->header_sent) {
|
||||
return luaL_error(L, "attempt to call ngx.redirect after sending out "
|
||||
"the headers");
|
||||
}
|
||||
|
||||
if (ngx_http_lua_check_unsafe_uri_bytes(r, p, len, &byte) != NGX_OK) {
|
||||
buf_len = ngx_http_lua_escape_log(NULL, p, len) + 1;
|
||||
buf = ngx_palloc(r->pool, buf_len);
|
||||
if (buf == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_http_lua_escape_log(buf, p, len);
|
||||
buf[buf_len - 1] = '\0';
|
||||
return luaL_error(L, "unsafe byte \"0x%02x\" in redirect uri \"%s\"",
|
||||
byte, buf);
|
||||
}
|
||||
|
||||
uri = ngx_palloc(r->pool, len);
|
||||
if (uri == NULL) {
|
||||
return luaL_error(L, "no memory");
|
||||
}
|
||||
|
||||
ngx_memcpy(uri, p, len);
|
||||
|
||||
h = ngx_list_push(&r->headers_out.headers);
|
||||
if (h == NULL) {
|
||||
return luaL_error(L, "no memory");
|
||||
}
|
||||
|
||||
h->hash = ngx_http_lua_location_hash;
|
||||
|
||||
#if 0
|
||||
dd("location hash: %lu == %lu",
|
||||
(unsigned long) h->hash,
|
||||
(unsigned long) ngx_hash_key_lc((u_char *) "Location",
|
||||
sizeof("Location") - 1));
|
||||
#endif
|
||||
|
||||
h->value.len = len;
|
||||
h->value.data = uri;
|
||||
ngx_str_set(&h->key, "Location");
|
||||
|
||||
r->headers_out.status = rc;
|
||||
|
||||
ctx->exit_code = rc;
|
||||
ctx->exited = 1;
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua redirect to \"%V\" with code %i",
|
||||
&h->value, ctx->exit_code);
|
||||
|
||||
if (len && uri[0] != '/') {
|
||||
r->headers_out.location = h;
|
||||
}
|
||||
|
||||
/*
|
||||
* we do not set r->headers_out.location here to avoid the handling
|
||||
* the local redirects without a host name by ngx_http_header_filter()
|
||||
*/
|
||||
|
||||
return lua_yield(L, 0);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_http_lua_on_abort(lua_State *L)
|
||||
{
|
||||
int co_ref;
|
||||
ngx_http_request_t *r;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_http_lua_co_ctx_t *coctx = NULL;
|
||||
ngx_http_lua_loc_conf_t *llcf;
|
||||
|
||||
r = ngx_http_lua_get_req(L);
|
||||
if (r == NULL) {
|
||||
return luaL_error(L, "no request found");
|
||||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return luaL_error(L, "no request ctx found");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_fake_request2(L, r, ctx);
|
||||
|
||||
if (ctx->on_abort_co_ctx) {
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "duplicate call");
|
||||
return 2;
|
||||
}
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
if (!llcf->check_client_abort) {
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "lua_check_client_abort is off");
|
||||
return 2;
|
||||
}
|
||||
|
||||
ngx_http_lua_coroutine_create_helper(L, r, ctx, &coctx, &co_ref);
|
||||
|
||||
coctx->co_ref = co_ref;
|
||||
coctx->is_uthread = 1;
|
||||
ctx->on_abort_co_ctx = coctx;
|
||||
|
||||
dd("on_wait thread 2: %p", coctx->co);
|
||||
|
||||
coctx->co_status = NGX_HTTP_LUA_CO_SUSPENDED;
|
||||
coctx->parent_co_ctx = ctx->cur_co_ctx;
|
||||
|
||||
lua_pushinteger(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_exit(ngx_http_request_t *r, int status, u_char *err,
|
||||
size_t *errlen)
|
||||
{
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
|
||||
if (status == NGX_AGAIN || status == NGX_DONE) {
|
||||
*errlen = ngx_snprintf(err, *errlen,
|
||||
"bad argument to 'ngx.exit': does not accept "
|
||||
"NGX_AGAIN or NGX_DONE")
|
||||
- err;
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
if (ctx == NULL) {
|
||||
*errlen = ngx_snprintf(err, *errlen, "no request ctx found") - err;
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ngx_http_lua_ffi_check_context(ctx, NGX_HTTP_LUA_CONTEXT_REWRITE
|
||||
| NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE
|
||||
| NGX_HTTP_LUA_CONTEXT_ACCESS
|
||||
| NGX_HTTP_LUA_CONTEXT_CONTENT
|
||||
| NGX_HTTP_LUA_CONTEXT_TIMER
|
||||
| NGX_HTTP_LUA_CONTEXT_HEADER_FILTER
|
||||
| NGX_HTTP_LUA_CONTEXT_BALANCER
|
||||
| NGX_HTTP_LUA_CONTEXT_SSL_CLIENT_HELLO
|
||||
| NGX_HTTP_LUA_CONTEXT_SSL_CERT
|
||||
| NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE
|
||||
| NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH,
|
||||
err, errlen)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ctx->context & (NGX_HTTP_LUA_CONTEXT_SSL_CERT
|
||||
| NGX_HTTP_LUA_CONTEXT_SSL_CLIENT_HELLO
|
||||
| NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE
|
||||
| NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH))
|
||||
{
|
||||
|
||||
#if (NGX_HTTP_SSL)
|
||||
|
||||
ctx->exit_code = status;
|
||||
ctx->exited = 1;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua exit with code %d", status);
|
||||
|
||||
if (ctx->context == NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE) {
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
|
||||
#else
|
||||
|
||||
return NGX_ERROR;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ctx->no_abort
|
||||
&& status != NGX_ERROR
|
||||
&& status != NGX_HTTP_CLOSE
|
||||
&& status != NGX_HTTP_REQUEST_TIME_OUT
|
||||
&& status != NGX_HTTP_CLIENT_CLOSED_REQUEST)
|
||||
{
|
||||
*errlen = ngx_snprintf(err, *errlen,
|
||||
"attempt to abort with pending subrequests")
|
||||
- err;
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if ((r->header_sent || ctx->header_sent)
|
||||
&& status >= NGX_HTTP_SPECIAL_RESPONSE
|
||||
&& status != NGX_HTTP_REQUEST_TIME_OUT
|
||||
&& status != NGX_HTTP_CLIENT_CLOSED_REQUEST
|
||||
&& status != NGX_HTTP_CLOSE)
|
||||
{
|
||||
if (status != (ngx_int_t) r->headers_out.status) {
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "attempt to "
|
||||
"set status %d via ngx.exit after sending out the "
|
||||
"response status %ui", status,
|
||||
r->headers_out.status);
|
||||
}
|
||||
|
||||
status = NGX_HTTP_OK;
|
||||
}
|
||||
|
||||
ctx->exit_code = status;
|
||||
ctx->exited = 1;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua exit with code %i", ctx->exit_code);
|
||||
|
||||
if (ctx->context & (NGX_HTTP_LUA_CONTEXT_HEADER_FILTER
|
||||
| NGX_HTTP_LUA_CONTEXT_BALANCER))
|
||||
{
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_CONTROL_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_CONTROL_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
void ngx_http_lua_inject_control_api(ngx_log_t *log, lua_State *L);
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_CONTROL_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,436 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_http_lua_coroutine.h"
|
||||
#include "ngx_http_lua_util.h"
|
||||
#include "ngx_http_lua_probe.h"
|
||||
|
||||
|
||||
/*
|
||||
* Design:
|
||||
*
|
||||
* In order to support using ngx.* API in Lua coroutines, we have to create
|
||||
* new coroutine in the main coroutine instead of the calling coroutine
|
||||
*/
|
||||
|
||||
|
||||
static int ngx_http_lua_coroutine_create(lua_State *L);
|
||||
static int ngx_http_lua_coroutine_wrap(lua_State *L);
|
||||
static int ngx_http_lua_coroutine_resume(lua_State *L);
|
||||
static int ngx_http_lua_coroutine_yield(lua_State *L);
|
||||
static int ngx_http_lua_coroutine_status(lua_State *L);
|
||||
|
||||
|
||||
static const ngx_str_t
|
||||
ngx_http_lua_co_status_names[] =
|
||||
{
|
||||
ngx_string("running"),
|
||||
ngx_string("suspended"),
|
||||
ngx_string("normal"),
|
||||
ngx_string("dead"),
|
||||
ngx_string("zombie")
|
||||
};
|
||||
|
||||
|
||||
|
||||
static int
|
||||
ngx_http_lua_coroutine_create(lua_State *L)
|
||||
{
|
||||
ngx_http_request_t *r;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
|
||||
r = ngx_http_lua_get_req(L);
|
||||
if (r == NULL) {
|
||||
return luaL_error(L, "no request found");
|
||||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return luaL_error(L, "no request ctx found");
|
||||
}
|
||||
|
||||
return ngx_http_lua_coroutine_create_helper(L, r, ctx, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_http_lua_coroutine_wrap_runner(lua_State *L)
|
||||
{
|
||||
/* retrieve closure and insert it at the bottom of
|
||||
* the stack for coroutine.resume() */
|
||||
lua_pushvalue(L, lua_upvalueindex(1));
|
||||
lua_insert(L, 1);
|
||||
|
||||
return ngx_http_lua_coroutine_resume(L);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_http_lua_coroutine_wrap(lua_State *L)
|
||||
{
|
||||
ngx_http_request_t *r;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_http_lua_co_ctx_t *coctx = NULL;
|
||||
|
||||
r = ngx_http_lua_get_req(L);
|
||||
if (r == NULL) {
|
||||
return luaL_error(L, "no request found");
|
||||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return luaL_error(L, "no request ctx found");
|
||||
}
|
||||
|
||||
ngx_http_lua_coroutine_create_helper(L, r, ctx, &coctx, NULL);
|
||||
|
||||
coctx->is_wrap = 1;
|
||||
|
||||
lua_pushcclosure(L, ngx_http_lua_coroutine_wrap_runner, 1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t *r,
|
||||
ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t **pcoctx, int *co_ref)
|
||||
{
|
||||
lua_State *vm; /* the Lua VM */
|
||||
lua_State *co; /* new coroutine to be created */
|
||||
ngx_http_lua_co_ctx_t *coctx; /* co ctx for the new coroutine */
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
|
||||
luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1,
|
||||
"Lua function expected");
|
||||
|
||||
ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_YIELDABLE);
|
||||
|
||||
vm = ngx_http_lua_get_lua_vm(r, ctx);
|
||||
|
||||
/* create new coroutine on root Lua state, so it always yields
|
||||
* to main Lua thread
|
||||
*/
|
||||
if (co_ref == NULL) {
|
||||
co = lua_newthread(vm);
|
||||
|
||||
} else {
|
||||
lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
|
||||
*co_ref = ngx_http_lua_new_cached_thread(vm, &co, lmcf, 0);
|
||||
}
|
||||
|
||||
ngx_http_lua_probe_user_coroutine_create(r, L, co);
|
||||
|
||||
coctx = ngx_http_lua_get_co_ctx(co, ctx);
|
||||
if (coctx == NULL) {
|
||||
coctx = ngx_http_lua_create_co_ctx(r, ctx);
|
||||
if (coctx == NULL) {
|
||||
return luaL_error(L, "no memory");
|
||||
}
|
||||
|
||||
} else {
|
||||
ngx_memzero(coctx, sizeof(ngx_http_lua_co_ctx_t));
|
||||
coctx->next_zombie_child_thread = &coctx->zombie_child_threads;
|
||||
coctx->co_ref = LUA_NOREF;
|
||||
}
|
||||
|
||||
coctx->co = co;
|
||||
coctx->co_status = NGX_HTTP_LUA_CO_SUSPENDED;
|
||||
|
||||
#ifdef OPENRESTY_LUAJIT
|
||||
ngx_http_lua_set_req(co, r);
|
||||
ngx_http_lua_attach_co_ctx_to_L(co, coctx);
|
||||
#else
|
||||
/* make new coroutine share globals of the parent coroutine.
|
||||
* NOTE: globals don't have to be separated! */
|
||||
ngx_http_lua_get_globals_table(L);
|
||||
lua_xmove(L, co, 1);
|
||||
ngx_http_lua_set_globals_table(co);
|
||||
#endif
|
||||
|
||||
lua_xmove(vm, L, 1); /* move coroutine from main thread to L */
|
||||
|
||||
if (co_ref) {
|
||||
lua_pop(vm, 1); /* pop coroutines */
|
||||
}
|
||||
|
||||
lua_pushvalue(L, 1); /* copy entry function to top of L*/
|
||||
lua_xmove(L, co, 1); /* move entry function from L to co */
|
||||
|
||||
if (pcoctx) {
|
||||
*pcoctx = coctx;
|
||||
}
|
||||
|
||||
#ifdef NGX_LUA_USE_ASSERT
|
||||
coctx->co_top = 1;
|
||||
#endif
|
||||
|
||||
return 1; /* return new coroutine to Lua */
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_http_lua_coroutine_resume(lua_State *L)
|
||||
{
|
||||
lua_State *co;
|
||||
ngx_http_request_t *r;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_http_lua_co_ctx_t *coctx;
|
||||
ngx_http_lua_co_ctx_t *p_coctx; /* parent co ctx */
|
||||
|
||||
co = lua_tothread(L, 1);
|
||||
|
||||
luaL_argcheck(L, co, 1, "coroutine expected");
|
||||
|
||||
r = ngx_http_lua_get_req(L);
|
||||
if (r == NULL) {
|
||||
return luaL_error(L, "no request found");
|
||||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return luaL_error(L, "no request ctx found");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_YIELDABLE);
|
||||
|
||||
p_coctx = ctx->cur_co_ctx;
|
||||
if (p_coctx == NULL) {
|
||||
return luaL_error(L, "no parent co ctx found");
|
||||
}
|
||||
|
||||
coctx = ngx_http_lua_get_co_ctx(co, ctx);
|
||||
if (coctx == NULL) {
|
||||
return luaL_error(L, "no co ctx found");
|
||||
}
|
||||
|
||||
ngx_http_lua_probe_user_coroutine_resume(r, L, co);
|
||||
|
||||
if (coctx->co_status != NGX_HTTP_LUA_CO_SUSPENDED) {
|
||||
dd("coroutine resume: %d", coctx->co_status);
|
||||
|
||||
lua_pushboolean(L, 0);
|
||||
lua_pushfstring(L, "cannot resume %s coroutine",
|
||||
ngx_http_lua_co_status_names[coctx->co_status].data);
|
||||
return 2;
|
||||
}
|
||||
|
||||
p_coctx->co_status = NGX_HTTP_LUA_CO_NORMAL;
|
||||
|
||||
coctx->parent_co_ctx = p_coctx;
|
||||
|
||||
dd("set coroutine to running");
|
||||
coctx->co_status = NGX_HTTP_LUA_CO_RUNNING;
|
||||
|
||||
ctx->co_op = NGX_HTTP_LUA_USER_CORO_RESUME;
|
||||
ctx->cur_co_ctx = coctx;
|
||||
|
||||
/* yield and pass args to main thread, and resume target coroutine from
|
||||
* there */
|
||||
return lua_yield(L, lua_gettop(L) - 1);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_http_lua_coroutine_yield(lua_State *L)
|
||||
{
|
||||
ngx_http_request_t *r;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_http_lua_co_ctx_t *coctx;
|
||||
|
||||
r = ngx_http_lua_get_req(L);
|
||||
if (r == NULL) {
|
||||
return luaL_error(L, "no request found");
|
||||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return luaL_error(L, "no request ctx found");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_YIELDABLE);
|
||||
|
||||
coctx = ctx->cur_co_ctx;
|
||||
|
||||
coctx->co_status = NGX_HTTP_LUA_CO_SUSPENDED;
|
||||
|
||||
ctx->co_op = NGX_HTTP_LUA_USER_CORO_YIELD;
|
||||
|
||||
if (!coctx->is_uthread && coctx->parent_co_ctx) {
|
||||
dd("set coroutine to running");
|
||||
coctx->parent_co_ctx->co_status = NGX_HTTP_LUA_CO_RUNNING;
|
||||
|
||||
ngx_http_lua_probe_user_coroutine_yield(r, coctx->parent_co_ctx->co, L);
|
||||
|
||||
} else {
|
||||
ngx_http_lua_probe_user_coroutine_yield(r, NULL, L);
|
||||
}
|
||||
|
||||
/* yield and pass retvals to main thread,
|
||||
* and resume parent coroutine there */
|
||||
return lua_yield(L, lua_gettop(L));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_http_lua_inject_coroutine_api(ngx_log_t *log, lua_State *L)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* new coroutine table */
|
||||
lua_createtable(L, 0 /* narr */, 16 /* nrec */);
|
||||
|
||||
/* get old coroutine table */
|
||||
lua_getglobal(L, "coroutine");
|
||||
|
||||
/* set running to the old one */
|
||||
lua_getfield(L, -1, "running");
|
||||
lua_setfield(L, -3, "running");
|
||||
|
||||
lua_getfield(L, -1, "create");
|
||||
lua_setfield(L, -3, "_create");
|
||||
|
||||
lua_getfield(L, -1, "wrap");
|
||||
lua_setfield(L, -3, "_wrap");
|
||||
|
||||
lua_getfield(L, -1, "resume");
|
||||
lua_setfield(L, -3, "_resume");
|
||||
|
||||
lua_getfield(L, -1, "yield");
|
||||
lua_setfield(L, -3, "_yield");
|
||||
|
||||
lua_getfield(L, -1, "status");
|
||||
lua_setfield(L, -3, "_status");
|
||||
|
||||
/* pop the old coroutine */
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_pushcfunction(L, ngx_http_lua_coroutine_create);
|
||||
lua_setfield(L, -2, "__create");
|
||||
|
||||
lua_pushcfunction(L, ngx_http_lua_coroutine_wrap);
|
||||
lua_setfield(L, -2, "__wrap");
|
||||
|
||||
lua_pushcfunction(L, ngx_http_lua_coroutine_resume);
|
||||
lua_setfield(L, -2, "__resume");
|
||||
|
||||
lua_pushcfunction(L, ngx_http_lua_coroutine_yield);
|
||||
lua_setfield(L, -2, "__yield");
|
||||
|
||||
lua_pushcfunction(L, ngx_http_lua_coroutine_status);
|
||||
lua_setfield(L, -2, "__status");
|
||||
|
||||
lua_setglobal(L, "coroutine");
|
||||
|
||||
/* inject coroutine APIs */
|
||||
{
|
||||
const char buf[] =
|
||||
"local keys = {'create', 'yield', 'resume', 'status', 'wrap'}\n"
|
||||
#ifdef OPENRESTY_LUAJIT
|
||||
"local get_req = require 'thread.exdata'\n"
|
||||
#else
|
||||
"local getfenv = getfenv\n"
|
||||
#endif
|
||||
"for _, key in ipairs(keys) do\n"
|
||||
"local std = coroutine['_' .. key]\n"
|
||||
"local ours = coroutine['__' .. key]\n"
|
||||
"local raw_ctx = ngx._phase_ctx\n"
|
||||
"coroutine[key] = function (...)\n"
|
||||
#ifdef OPENRESTY_LUAJIT
|
||||
"local r = get_req()\n"
|
||||
#else
|
||||
"local r = getfenv(0).__ngx_req\n"
|
||||
#endif
|
||||
"if r ~= nil then\n"
|
||||
#ifdef OPENRESTY_LUAJIT
|
||||
"local ctx = raw_ctx()\n"
|
||||
#else
|
||||
"local ctx = raw_ctx(r)\n"
|
||||
#endif
|
||||
/* ignore header and body filters */
|
||||
"if ctx ~= 0x020 and ctx ~= 0x040 then\n"
|
||||
"return ours(...)\n"
|
||||
"end\n"
|
||||
"end\n"
|
||||
"return std(...)\n"
|
||||
"end\n"
|
||||
"end\n"
|
||||
"package.loaded.coroutine = coroutine"
|
||||
#if 0
|
||||
"debug.sethook(function () collectgarbage() end, 'rl', 1)"
|
||||
#endif
|
||||
;
|
||||
|
||||
rc = luaL_loadbuffer(L, buf, sizeof(buf) - 1, "=coroutine_api");
|
||||
}
|
||||
|
||||
if (rc != 0) {
|
||||
ngx_log_error(NGX_LOG_ERR, log, 0,
|
||||
"failed to load Lua code for coroutine_api: %i: %s",
|
||||
rc, lua_tostring(L, -1));
|
||||
|
||||
lua_pop(L, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = lua_pcall(L, 0, 0, 0);
|
||||
if (rc != 0) {
|
||||
ngx_log_error(NGX_LOG_ERR, log, 0,
|
||||
"failed to run the Lua code for coroutine_api: %i: %s",
|
||||
rc, lua_tostring(L, -1));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_http_lua_coroutine_status(lua_State *L)
|
||||
{
|
||||
lua_State *co; /* new coroutine to be created */
|
||||
ngx_http_request_t *r;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_http_lua_co_ctx_t *coctx; /* co ctx for the new coroutine */
|
||||
|
||||
co = lua_tothread(L, 1);
|
||||
|
||||
luaL_argcheck(L, co, 1, "coroutine expected");
|
||||
|
||||
r = ngx_http_lua_get_req(L);
|
||||
if (r == NULL) {
|
||||
return luaL_error(L, "no request found");
|
||||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return luaL_error(L, "no request ctx found");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_YIELDABLE);
|
||||
|
||||
coctx = ngx_http_lua_get_co_ctx(co, ctx);
|
||||
if (coctx == NULL) {
|
||||
lua_pushlstring(L, (const char *)
|
||||
ngx_http_lua_co_status_names[NGX_HTTP_LUA_CO_DEAD].data,
|
||||
ngx_http_lua_co_status_names[NGX_HTTP_LUA_CO_DEAD].len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
dd("co status: %d", coctx->co_status);
|
||||
|
||||
lua_pushlstring(L, (const char *)
|
||||
ngx_http_lua_co_status_names[coctx->co_status].data,
|
||||
ngx_http_lua_co_status_names[coctx->co_status].len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_COROUTINE_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_COROUTINE_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
void ngx_http_lua_inject_coroutine_api(ngx_log_t *log, lua_State *L);
|
||||
|
||||
int ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t *r,
|
||||
ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t **pcoctx, int *co_ref);
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_COROUTINE_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,206 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_http_lua_util.h"
|
||||
#include "ngx_http_lua_ssl.h"
|
||||
#include "ngx_http_lua_ctx.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
int ref;
|
||||
lua_State *vm;
|
||||
} ngx_http_lua_ngx_ctx_cleanup_data_t;
|
||||
|
||||
|
||||
static ngx_int_t ngx_http_lua_ngx_ctx_add_cleanup(ngx_http_request_t *r,
|
||||
ngx_pool_t *pool, int ref);
|
||||
static void ngx_http_lua_ngx_ctx_cleanup(void *data);
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ngx_set_ctx_helper(lua_State *L, ngx_http_request_t *r,
|
||||
ngx_http_lua_ctx_t *ctx, int index)
|
||||
{
|
||||
ngx_pool_t *pool;
|
||||
|
||||
if (index < 0) {
|
||||
index = lua_gettop(L) + index + 1;
|
||||
}
|
||||
|
||||
if (ctx->ctx_ref == LUA_NOREF) {
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua create ngx.ctx table for the current request");
|
||||
|
||||
lua_pushliteral(L, ngx_http_lua_ctx_tables_key);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_pushvalue(L, index);
|
||||
ctx->ctx_ref = luaL_ref(L, -2);
|
||||
lua_pop(L, 1);
|
||||
|
||||
pool = r->pool;
|
||||
if (ngx_http_lua_ngx_ctx_add_cleanup(r, pool, ctx->ctx_ref) != NGX_OK) {
|
||||
return luaL_error(L, "no memory");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua fetching existing ngx.ctx table for the current "
|
||||
"request");
|
||||
|
||||
lua_pushliteral(L, ngx_http_lua_ctx_tables_key);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
luaL_unref(L, -1, ctx->ctx_ref);
|
||||
lua_pushvalue(L, index);
|
||||
ctx->ctx_ref = luaL_ref(L, -2);
|
||||
lua_pop(L, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_get_ctx_ref(ngx_http_request_t *r, int *in_ssl_phase,
|
||||
int *ssl_ctx_ref)
|
||||
{
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
#if (NGX_HTTP_SSL)
|
||||
ngx_http_lua_ssl_ctx_t *ssl_ctx;
|
||||
#endif
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return NGX_HTTP_LUA_FFI_NO_REQ_CTX;
|
||||
}
|
||||
|
||||
if (ctx->ctx_ref >= 0 || in_ssl_phase == NULL) {
|
||||
return ctx->ctx_ref;
|
||||
}
|
||||
|
||||
*in_ssl_phase = ctx->context & (NGX_HTTP_LUA_CONTEXT_SSL_CERT
|
||||
| NGX_HTTP_LUA_CONTEXT_SSL_CLIENT_HELLO
|
||||
| NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH
|
||||
| NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE);
|
||||
*ssl_ctx_ref = LUA_NOREF;
|
||||
|
||||
#if (NGX_HTTP_SSL)
|
||||
if (r->connection->ssl != NULL) {
|
||||
ssl_ctx = ngx_http_lua_ssl_get_ctx(r->connection->ssl->connection);
|
||||
|
||||
if (ssl_ctx != NULL) {
|
||||
*ssl_ctx_ref = ssl_ctx->ctx_ref;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return LUA_NOREF;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_set_ctx_ref(ngx_http_request_t *r, int ref)
|
||||
{
|
||||
ngx_pool_t *pool;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
#if (NGX_HTTP_SSL)
|
||||
ngx_connection_t *c;
|
||||
ngx_http_lua_ssl_ctx_t *ssl_ctx;
|
||||
#endif
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return NGX_HTTP_LUA_FFI_NO_REQ_CTX;
|
||||
}
|
||||
|
||||
#if (NGX_HTTP_SSL)
|
||||
if (ctx->context & (NGX_HTTP_LUA_CONTEXT_SSL_CERT
|
||||
| NGX_HTTP_LUA_CONTEXT_SSL_CLIENT_HELLO
|
||||
| NGX_HTTP_LUA_CONTEXT_SSL_SESS_FETCH
|
||||
| NGX_HTTP_LUA_CONTEXT_SSL_SESS_STORE))
|
||||
{
|
||||
ssl_ctx = ngx_http_lua_ssl_get_ctx(r->connection->ssl->connection);
|
||||
if (ssl_ctx == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ssl_ctx->ctx_ref = ref;
|
||||
c = ngx_ssl_get_connection(r->connection->ssl->connection);
|
||||
pool = c->pool;
|
||||
|
||||
} else {
|
||||
pool = r->pool;
|
||||
}
|
||||
|
||||
#else
|
||||
pool = r->pool;
|
||||
#endif
|
||||
|
||||
ctx->ctx_ref = ref;
|
||||
|
||||
if (ngx_http_lua_ngx_ctx_add_cleanup(r, pool, ref) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_lua_ngx_ctx_add_cleanup(ngx_http_request_t *r, ngx_pool_t *pool,
|
||||
int ref)
|
||||
{
|
||||
lua_State *L;
|
||||
ngx_pool_cleanup_t *cln;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
|
||||
ngx_http_lua_ngx_ctx_cleanup_data_t *data;
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
L = ngx_http_lua_get_lua_vm(r, ctx);
|
||||
|
||||
cln = ngx_pool_cleanup_add(pool,
|
||||
sizeof(ngx_http_lua_ngx_ctx_cleanup_data_t));
|
||||
if (cln == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
cln->handler = ngx_http_lua_ngx_ctx_cleanup;
|
||||
|
||||
data = cln->data;
|
||||
data->vm = L;
|
||||
data->ref = ref;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_http_lua_ngx_ctx_cleanup(void *data)
|
||||
{
|
||||
lua_State *L;
|
||||
|
||||
ngx_http_lua_ngx_ctx_cleanup_data_t *clndata = data;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
|
||||
"lua release ngx.ctx at ref %d", clndata->ref);
|
||||
|
||||
L = clndata->vm;
|
||||
|
||||
lua_pushliteral(L, ngx_http_lua_ctx_tables_key);
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
luaL_unref(L, -1, clndata->ref);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_CTX_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_CTX_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
int ngx_http_lua_ngx_set_ctx_helper(lua_State *L, ngx_http_request_t *r,
|
||||
ngx_http_lua_ctx_t *ctx, int index);
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_CTX_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,93 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_DIRECTIVE_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_DIRECTIVE_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
char *ngx_http_lua_shared_dict(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
char *ngx_http_lua_package_cpath(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *ngx_http_lua_package_path(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *ngx_http_lua_regex_cache_max_entries(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *ngx_http_lua_regex_match_limit(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *ngx_http_lua_content_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *ngx_http_lua_content_by_lua(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *ngx_http_lua_server_rewrite_by_lua(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *ngx_http_lua_server_rewrite_by_lua_block(ngx_conf_t *cf,
|
||||
ngx_command_t *cmd, void *conf);
|
||||
char *ngx_http_lua_rewrite_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *ngx_http_lua_rewrite_by_lua(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *ngx_http_lua_access_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *ngx_http_lua_access_by_lua(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *ngx_http_lua_log_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *ngx_http_lua_log_by_lua(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *ngx_http_lua_header_filter_by_lua_block(ngx_conf_t *cf,
|
||||
ngx_command_t *cmd, void *conf);
|
||||
char *ngx_http_lua_header_filter_by_lua(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *ngx_http_lua_body_filter_by_lua_block(ngx_conf_t *cf,
|
||||
ngx_command_t *cmd, void *conf);
|
||||
char *ngx_http_lua_body_filter_by_lua(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *ngx_http_lua_init_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *ngx_http_lua_init_by_lua(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *ngx_http_lua_init_worker_by_lua_block(ngx_conf_t *cf,
|
||||
ngx_command_t *cmd, void *conf);
|
||||
char *ngx_http_lua_init_worker_by_lua(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *ngx_http_lua_exit_worker_by_lua_block(ngx_conf_t *cf,
|
||||
ngx_command_t *cmd, void *conf);
|
||||
char *ngx_http_lua_exit_worker_by_lua(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *ngx_http_lua_code_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
char *ngx_http_lua_load_resty_core(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
|
||||
#if defined(NDK) && NDK
|
||||
|
||||
char *ngx_http_lua_set_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *ngx_http_lua_set_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
char *ngx_http_lua_set_by_lua_file(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
ngx_int_t ngx_http_lua_filter_set_by_lua_inline(ngx_http_request_t *r,
|
||||
ngx_str_t *val, ngx_http_variable_value_t *v, void *data);
|
||||
ngx_int_t ngx_http_lua_filter_set_by_lua_file(ngx_http_request_t *r,
|
||||
ngx_str_t *val, ngx_http_variable_value_t *v, void *data);
|
||||
|
||||
#endif
|
||||
|
||||
char *ngx_http_lua_rewrite_no_postpone(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *ngx_http_lua_conf_lua_block_parse(ngx_conf_t *cf,
|
||||
ngx_command_t *cmd);
|
||||
char *ngx_http_lua_capture_error_log(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
u_char *ngx_http_lua_gen_chunk_name(ngx_conf_t *cf, const char *tag,
|
||||
size_t tag_len, size_t *chunkname_len);
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_DIRECTIVE_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,58 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_http_lua_exception.h"
|
||||
#include "ngx_http_lua_util.h"
|
||||
|
||||
|
||||
/* longjmp mark for restoring nginx execution after Lua VM crashing */
|
||||
jmp_buf ngx_http_lua_exception;
|
||||
|
||||
/**
|
||||
* Override default Lua panic handler, output VM crash reason to nginx error
|
||||
* log, and restore execution to the nearest jmp-mark.
|
||||
*
|
||||
* @param L Lua state pointer
|
||||
* @retval Long jump to the nearest jmp-mark, never returns.
|
||||
* @note nginx request pointer should be stored in Lua thread's globals table
|
||||
* in order to make logging working.
|
||||
* */
|
||||
int
|
||||
ngx_http_lua_atpanic(lua_State *L)
|
||||
{
|
||||
#ifdef NGX_LUA_ABORT_AT_PANIC
|
||||
abort();
|
||||
#else
|
||||
u_char *s = NULL;
|
||||
size_t len = 0;
|
||||
|
||||
if (lua_type(L, -1) == LUA_TSTRING) {
|
||||
s = (u_char *) lua_tolstring(L, -1, &len);
|
||||
}
|
||||
|
||||
if (s == NULL) {
|
||||
s = (u_char *) "unknown reason";
|
||||
len = sizeof("unknown reason") - 1;
|
||||
}
|
||||
|
||||
ngx_log_stderr(0, "lua atpanic: Lua VM crashed, reason: %*s", len, s);
|
||||
ngx_quit = 1;
|
||||
|
||||
/* restore nginx execution */
|
||||
NGX_LUA_EXCEPTION_THROW(1);
|
||||
|
||||
/* impossible to reach here */
|
||||
#endif
|
||||
}
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,33 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_EXCEPTION_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_EXCEPTION_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
#define NGX_LUA_EXCEPTION_TRY \
|
||||
if (setjmp(ngx_http_lua_exception) == 0)
|
||||
|
||||
#define NGX_LUA_EXCEPTION_CATCH \
|
||||
else
|
||||
|
||||
#define NGX_LUA_EXCEPTION_THROW(x) \
|
||||
longjmp(ngx_http_lua_exception, (x))
|
||||
|
||||
|
||||
extern jmp_buf ngx_http_lua_exception;
|
||||
|
||||
|
||||
int ngx_http_lua_atpanic(lua_State *L);
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_EXCEPTION_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,127 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_http_lua_exitworkerby.h"
|
||||
#include "ngx_http_lua_util.h"
|
||||
|
||||
#if (NGX_THREADS)
|
||||
#include "ngx_http_lua_worker_thread.h"
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
ngx_http_lua_exit_worker(ngx_cycle_t *cycle)
|
||||
{
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
ngx_connection_t *c = NULL;
|
||||
ngx_http_request_t *r = NULL;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_http_conf_ctx_t *conf_ctx;
|
||||
|
||||
#if (NGX_THREADS)
|
||||
ngx_http_lua_thread_exit_process();
|
||||
#endif
|
||||
|
||||
lmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_lua_module);
|
||||
if (lmcf == NULL
|
||||
|| lmcf->exit_worker_handler == NULL
|
||||
|| lmcf->lua == NULL
|
||||
#if !(NGX_WIN32)
|
||||
|| (ngx_process == NGX_PROCESS_HELPER
|
||||
# ifdef HAVE_PRIVILEGED_PROCESS_PATCH
|
||||
&& !ngx_is_privileged_agent
|
||||
# endif
|
||||
)
|
||||
#endif /* NGX_WIN32 */
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
conf_ctx = ((ngx_http_conf_ctx_t *) cycle->conf_ctx[ngx_http_module.index]);
|
||||
|
||||
c = ngx_http_lua_create_fake_connection(NULL);
|
||||
if (c == NULL) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
c->log = ngx_cycle->log;
|
||||
|
||||
r = ngx_http_lua_create_fake_request(c);
|
||||
if (r == NULL) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
r->main_conf = conf_ctx->main_conf;
|
||||
r->srv_conf = conf_ctx->srv_conf;
|
||||
r->loc_conf = conf_ctx->loc_conf;
|
||||
|
||||
ctx = ngx_http_lua_create_ctx(r);
|
||||
if (ctx == NULL) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
ctx->context = NGX_HTTP_LUA_CONTEXT_EXIT_WORKER;
|
||||
ctx->cur_co_ctx = NULL;
|
||||
|
||||
ngx_http_lua_set_req(lmcf->lua, r);
|
||||
|
||||
(void) lmcf->exit_worker_handler(cycle->log, lmcf, lmcf->lua);
|
||||
|
||||
ngx_destroy_pool(c->pool);
|
||||
return;
|
||||
|
||||
failed:
|
||||
|
||||
if (c) {
|
||||
ngx_http_lua_close_fake_connection(c);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_exit_worker_by_inline(ngx_log_t *log,
|
||||
ngx_http_lua_main_conf_t *lmcf, lua_State *L)
|
||||
{
|
||||
int status;
|
||||
const char *chunkname;
|
||||
|
||||
if (lmcf->exit_worker_chunkname == NULL) {
|
||||
chunkname = "=exit_worker_by_lua";
|
||||
|
||||
} else {
|
||||
chunkname = (const char *) lmcf->exit_worker_chunkname;
|
||||
}
|
||||
|
||||
status = luaL_loadbuffer(L, (char *) lmcf->exit_worker_src.data,
|
||||
lmcf->exit_worker_src.len, chunkname)
|
||||
|| ngx_http_lua_do_call(log, L);
|
||||
|
||||
return ngx_http_lua_report(log, L, status, "exit_worker_by_lua");
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_exit_worker_by_file(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf,
|
||||
lua_State *L)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = luaL_loadfile(L, (char *) lmcf->exit_worker_src.data)
|
||||
|| ngx_http_lua_do_call(log, L);
|
||||
|
||||
return ngx_http_lua_report(log, L, status, "exit_worker_by_lua_file");
|
||||
}
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_EXITWORKERBY_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_EXITWORKERBY_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
ngx_int_t ngx_http_lua_exit_worker_by_inline(ngx_log_t *log,
|
||||
ngx_http_lua_main_conf_t *lmcf, lua_State *L);
|
||||
|
||||
ngx_int_t ngx_http_lua_exit_worker_by_file(ngx_log_t *log,
|
||||
ngx_http_lua_main_conf_t *lmcf, lua_State *L);
|
||||
|
||||
void ngx_http_lua_exit_worker(ngx_cycle_t *cycle);
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_EXITWORKERBY_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,303 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
#include "ngx_http_lua_headerfilterby.h"
|
||||
#include "ngx_http_lua_exception.h"
|
||||
#include "ngx_http_lua_util.h"
|
||||
#include "ngx_http_lua_pcrefix.h"
|
||||
#include "ngx_http_lua_log.h"
|
||||
#include "ngx_http_lua_cache.h"
|
||||
#include "ngx_http_lua_headers.h"
|
||||
#include "ngx_http_lua_string.h"
|
||||
#include "ngx_http_lua_misc.h"
|
||||
#include "ngx_http_lua_consts.h"
|
||||
#include "ngx_http_lua_shdict.h"
|
||||
|
||||
|
||||
static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
|
||||
|
||||
|
||||
/**
|
||||
* Set environment table for the given code closure.
|
||||
*
|
||||
* Before:
|
||||
* | code closure | <- top
|
||||
* | ... |
|
||||
*
|
||||
* After:
|
||||
* | code closure | <- top
|
||||
* | ... |
|
||||
* */
|
||||
static void
|
||||
ngx_http_lua_header_filter_by_lua_env(lua_State *L, ngx_http_request_t *r)
|
||||
{
|
||||
ngx_http_lua_set_req(L, r);
|
||||
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
/**
|
||||
* we want to create empty environment for current script
|
||||
*
|
||||
* newt = {}
|
||||
* newt["_G"] = newt
|
||||
* setmetatable(newt, {__index = _G})
|
||||
*
|
||||
* if a function or symbol is not defined in our env, __index will lookup
|
||||
* in the global env.
|
||||
*
|
||||
* all variables created in the script-env will be thrown away at the end
|
||||
* of the script run.
|
||||
* */
|
||||
ngx_http_lua_create_new_globals_table(L, 0 /* narr */, 1 /* nrec */);
|
||||
|
||||
/* {{{ make new env inheriting main thread's globals table */
|
||||
lua_createtable(L, 0, 1 /* nrec */); /* the metatable for the new env */
|
||||
ngx_http_lua_get_globals_table(L);
|
||||
lua_setfield(L, -2, "__index");
|
||||
lua_setmetatable(L, -2); /* setmetatable({}, {__index = _G}) */
|
||||
/* }}} */
|
||||
|
||||
lua_setfenv(L, -2); /* set new running env for the code closure */
|
||||
#endif /* OPENRESTY_LUAJIT */
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_header_filter_by_chunk(lua_State *L, ngx_http_request_t *r)
|
||||
{
|
||||
int old_exit_code = 0;
|
||||
ngx_int_t rc;
|
||||
u_char *err_msg;
|
||||
size_t len;
|
||||
#if (NGX_PCRE)
|
||||
ngx_pool_t *old_pool;
|
||||
#endif
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
if (ctx->exited) {
|
||||
old_exit_code = ctx->exit_code;
|
||||
}
|
||||
|
||||
/* initialize nginx context in Lua VM, code chunk at stack top sp = 1 */
|
||||
ngx_http_lua_header_filter_by_lua_env(L, r);
|
||||
|
||||
#if (NGX_PCRE)
|
||||
/* XXX: work-around to nginx regex subsystem */
|
||||
old_pool = ngx_http_lua_pcre_malloc_init(r->pool);
|
||||
#endif
|
||||
|
||||
lua_pushcfunction(L, ngx_http_lua_traceback);
|
||||
lua_insert(L, 1); /* put it under chunk and args */
|
||||
|
||||
/* protected call user code */
|
||||
rc = lua_pcall(L, 0, 1, 1);
|
||||
|
||||
lua_remove(L, 1); /* remove traceback function */
|
||||
|
||||
#if (NGX_PCRE)
|
||||
/* XXX: work-around to nginx regex subsystem */
|
||||
ngx_http_lua_pcre_malloc_done(old_pool);
|
||||
#endif
|
||||
|
||||
dd("rc == %d", (int) rc);
|
||||
|
||||
if (rc != 0) {
|
||||
/* error occurred when running loaded code */
|
||||
err_msg = (u_char *) lua_tolstring(L, -1, &len);
|
||||
|
||||
if (err_msg == NULL) {
|
||||
err_msg = (u_char *) "unknown reason";
|
||||
len = sizeof("unknown reason") - 1;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"failed to run header_filter_by_lua*: %*s", len, err_msg);
|
||||
|
||||
lua_settop(L, 0); /* clear remaining elems on stack */
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
dd("exited: %d, exit code: %d, old exit code: %d",
|
||||
(int) ctx->exited, (int) ctx->exit_code, (int) old_exit_code);
|
||||
|
||||
#if 1
|
||||
/* clear Lua stack */
|
||||
lua_settop(L, 0);
|
||||
#endif
|
||||
|
||||
if (ctx->exited && ctx->exit_code != old_exit_code) {
|
||||
if (ctx->exit_code == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
dd("finalize request with %d", (int) ctx->exit_code);
|
||||
|
||||
rc = ngx_http_filter_finalize_request(r, &ngx_http_lua_module,
|
||||
ctx->exit_code);
|
||||
if (rc == NGX_ERROR || rc == NGX_AGAIN) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_header_filter_inline(ngx_http_request_t *r)
|
||||
{
|
||||
lua_State *L;
|
||||
ngx_int_t rc;
|
||||
ngx_http_lua_loc_conf_t *llcf;
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
|
||||
L = ngx_http_lua_get_lua_vm(r, NULL);
|
||||
|
||||
/* load Lua inline script (w/ cache) sp = 1 */
|
||||
rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L,
|
||||
llcf->header_filter_src.value.data,
|
||||
llcf->header_filter_src.value.len,
|
||||
&llcf->header_filter_src_ref,
|
||||
llcf->header_filter_src_key,
|
||||
(const char *)
|
||||
llcf->header_filter_chunkname);
|
||||
if (rc != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
dd("calling header filter by chunk");
|
||||
|
||||
return ngx_http_lua_header_filter_by_chunk(L, r);
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_header_filter_file(ngx_http_request_t *r)
|
||||
{
|
||||
lua_State *L;
|
||||
ngx_int_t rc;
|
||||
u_char *script_path;
|
||||
ngx_http_lua_loc_conf_t *llcf;
|
||||
ngx_str_t eval_src;
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
|
||||
/* Eval nginx variables in code path string first */
|
||||
if (ngx_http_complex_value(r, &llcf->header_filter_src, &eval_src)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
script_path = ngx_http_lua_rebase_path(r->pool, eval_src.data,
|
||||
eval_src.len);
|
||||
|
||||
if (script_path == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
L = ngx_http_lua_get_lua_vm(r, NULL);
|
||||
|
||||
/* load Lua script file (w/ cache) sp = 1 */
|
||||
rc = ngx_http_lua_cache_loadfile(r->connection->log, L, script_path,
|
||||
&llcf->header_filter_src_ref,
|
||||
llcf->header_filter_src_key);
|
||||
if (rc != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
/* make sure we have a valid code chunk */
|
||||
ngx_http_lua_assert(lua_isfunction(L, -1));
|
||||
|
||||
return ngx_http_lua_header_filter_by_chunk(L, r);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_lua_header_filter(ngx_http_request_t *r)
|
||||
{
|
||||
ngx_http_lua_loc_conf_t *llcf;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_int_t rc;
|
||||
ngx_pool_cleanup_t *cln;
|
||||
uint16_t old_context;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua header filter for user lua code, uri \"%V\"", &r->uri);
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
|
||||
if (llcf->body_filter_handler) {
|
||||
r->filter_need_in_memory = 1;
|
||||
}
|
||||
|
||||
if (llcf->header_filter_handler == NULL) {
|
||||
dd("no header filter handler found");
|
||||
return ngx_http_next_header_filter(r);
|
||||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
|
||||
dd("ctx = %p", ctx);
|
||||
|
||||
if (ctx == NULL) {
|
||||
ctx = ngx_http_lua_create_ctx(r);
|
||||
if (ctx == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->cleanup == NULL) {
|
||||
cln = ngx_pool_cleanup_add(r->pool, 0);
|
||||
if (cln == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
cln->handler = ngx_http_lua_request_cleanup_handler;
|
||||
cln->data = ctx;
|
||||
ctx->cleanup = &cln->handler;
|
||||
}
|
||||
|
||||
old_context = ctx->context;
|
||||
ctx->context = NGX_HTTP_LUA_CONTEXT_HEADER_FILTER;
|
||||
|
||||
dd("calling header filter handler");
|
||||
rc = llcf->header_filter_handler(r);
|
||||
|
||||
ctx->context = old_context;
|
||||
|
||||
if (rc == NGX_DECLINED) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (rc == NGX_AGAIN || rc == NGX_ERROR) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return ngx_http_next_header_filter(r);
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_header_filter_init(void)
|
||||
{
|
||||
dd("calling header filter init");
|
||||
ngx_http_next_header_filter = ngx_http_top_header_filter;
|
||||
ngx_http_top_header_filter = ngx_http_lua_header_filter;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_HEADERFILTERBY_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_HEADERFILTERBY_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
extern ngx_http_output_header_filter_pt ngx_http_lua_next_filter_header_filter;
|
||||
|
||||
|
||||
ngx_int_t ngx_http_lua_header_filter_init(void);
|
||||
|
||||
ngx_int_t ngx_http_lua_header_filter_by_chunk(lua_State *L,
|
||||
ngx_http_request_t *r);
|
||||
|
||||
ngx_int_t ngx_http_lua_header_filter_inline(ngx_http_request_t *r);
|
||||
|
||||
ngx_int_t ngx_http_lua_header_filter_file(ngx_http_request_t *r);
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_HEADERFILTERBY_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,25 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_HEADERS_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_HEADERS_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
void ngx_http_lua_inject_resp_header_api(lua_State *L);
|
||||
void ngx_http_lua_inject_req_header_api(lua_State *L);
|
||||
void ngx_http_lua_create_headers_metatable(ngx_log_t *log, lua_State *L);
|
||||
#if (nginx_version >= 1011011)
|
||||
void ngx_http_lua_ngx_raw_header_cleanup(void *data);
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_HEADERS_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,902 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include <nginx.h>
|
||||
#include "ngx_http_lua_headers_in.h"
|
||||
#include "ngx_http_lua_util.h"
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
static ngx_int_t ngx_http_set_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value);
|
||||
static ngx_int_t ngx_http_set_header_helper(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value,
|
||||
ngx_table_elt_t **output_header);
|
||||
static ngx_int_t ngx_http_set_builtin_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value);
|
||||
static ngx_int_t ngx_http_set_user_agent_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value);
|
||||
static ngx_int_t ngx_http_set_connection_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value);
|
||||
static ngx_int_t ngx_http_set_content_length_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value);
|
||||
static ngx_int_t ngx_http_set_builtin_multi_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value);
|
||||
static ngx_int_t ngx_http_clear_builtin_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value);
|
||||
static ngx_int_t ngx_http_clear_content_length_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value);
|
||||
static ngx_int_t ngx_http_lua_validate_host(ngx_str_t *host, ngx_pool_t *pool,
|
||||
ngx_uint_t alloc);
|
||||
static ngx_int_t ngx_http_set_host_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value);
|
||||
static ngx_int_t ngx_http_lua_rm_header_helper(ngx_list_t *l,
|
||||
ngx_list_part_t *cur, ngx_uint_t i);
|
||||
|
||||
|
||||
static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = {
|
||||
{ ngx_string("Host"),
|
||||
offsetof(ngx_http_headers_in_t, host),
|
||||
ngx_http_set_host_header },
|
||||
|
||||
{ ngx_string("Connection"),
|
||||
offsetof(ngx_http_headers_in_t, connection),
|
||||
ngx_http_set_connection_header },
|
||||
|
||||
{ ngx_string("If-Modified-Since"),
|
||||
offsetof(ngx_http_headers_in_t, if_modified_since),
|
||||
ngx_http_set_builtin_header },
|
||||
|
||||
{ ngx_string("If-Unmodified-Since"),
|
||||
offsetof(ngx_http_headers_in_t, if_unmodified_since),
|
||||
ngx_http_set_builtin_header },
|
||||
|
||||
{ ngx_string("If-Match"),
|
||||
offsetof(ngx_http_headers_in_t, if_match),
|
||||
ngx_http_set_builtin_header },
|
||||
|
||||
{ ngx_string("If-None-Match"),
|
||||
offsetof(ngx_http_headers_in_t, if_none_match),
|
||||
ngx_http_set_builtin_header },
|
||||
|
||||
{ ngx_string("User-Agent"),
|
||||
offsetof(ngx_http_headers_in_t, user_agent),
|
||||
ngx_http_set_user_agent_header },
|
||||
|
||||
{ ngx_string("Referer"),
|
||||
offsetof(ngx_http_headers_in_t, referer),
|
||||
ngx_http_set_builtin_header },
|
||||
|
||||
{ ngx_string("Content-Length"),
|
||||
offsetof(ngx_http_headers_in_t, content_length),
|
||||
ngx_http_set_content_length_header },
|
||||
|
||||
{ ngx_string("Content-Type"),
|
||||
offsetof(ngx_http_headers_in_t, content_type),
|
||||
ngx_http_set_builtin_header },
|
||||
|
||||
{ ngx_string("Range"),
|
||||
offsetof(ngx_http_headers_in_t, range),
|
||||
ngx_http_set_builtin_header },
|
||||
|
||||
{ ngx_string("If-Range"),
|
||||
offsetof(ngx_http_headers_in_t, if_range),
|
||||
ngx_http_set_builtin_header },
|
||||
|
||||
{ ngx_string("Transfer-Encoding"),
|
||||
offsetof(ngx_http_headers_in_t, transfer_encoding),
|
||||
ngx_http_set_builtin_header },
|
||||
|
||||
{ ngx_string("Expect"),
|
||||
offsetof(ngx_http_headers_in_t, expect),
|
||||
ngx_http_set_builtin_header },
|
||||
|
||||
{ ngx_string("Upgrade"),
|
||||
offsetof(ngx_http_headers_in_t, upgrade),
|
||||
ngx_http_set_builtin_header },
|
||||
|
||||
#if (NGX_HTTP_GZIP)
|
||||
{ ngx_string("Accept-Encoding"),
|
||||
offsetof(ngx_http_headers_in_t, accept_encoding),
|
||||
ngx_http_set_builtin_header },
|
||||
|
||||
{ ngx_string("Via"),
|
||||
offsetof(ngx_http_headers_in_t, via),
|
||||
ngx_http_set_builtin_header },
|
||||
#endif
|
||||
|
||||
{ ngx_string("Authorization"),
|
||||
offsetof(ngx_http_headers_in_t, authorization),
|
||||
ngx_http_set_builtin_header },
|
||||
|
||||
{ ngx_string("Keep-Alive"),
|
||||
offsetof(ngx_http_headers_in_t, keep_alive),
|
||||
ngx_http_set_builtin_header },
|
||||
|
||||
#if (NGX_HTTP_X_FORWARDED_FOR)
|
||||
{ ngx_string("X-Forwarded-For"),
|
||||
offsetof(ngx_http_headers_in_t, x_forwarded_for),
|
||||
ngx_http_set_builtin_multi_header },
|
||||
|
||||
#endif
|
||||
|
||||
#if (NGX_HTTP_REALIP)
|
||||
{ ngx_string("X-Real-IP"),
|
||||
offsetof(ngx_http_headers_in_t, x_real_ip),
|
||||
ngx_http_set_builtin_header },
|
||||
#endif
|
||||
|
||||
#if (NGX_HTTP_DAV)
|
||||
{ ngx_string("Depth"),
|
||||
offsetof(ngx_http_headers_in_t, depth),
|
||||
ngx_http_set_builtin_header },
|
||||
|
||||
{ ngx_string("Destination"),
|
||||
offsetof(ngx_http_headers_in_t, destination),
|
||||
ngx_http_set_builtin_header },
|
||||
|
||||
{ ngx_string("Overwrite"),
|
||||
offsetof(ngx_http_headers_in_t, overwrite),
|
||||
ngx_http_set_builtin_header },
|
||||
|
||||
{ ngx_string("Date"), offsetof(ngx_http_headers_in_t, date),
|
||||
ngx_http_set_builtin_header },
|
||||
#endif
|
||||
|
||||
#if defined(nginx_version) && nginx_version >= 1023000
|
||||
{ ngx_string("Cookie"),
|
||||
offsetof(ngx_http_headers_in_t, cookie),
|
||||
ngx_http_set_builtin_multi_header },
|
||||
#else
|
||||
{ ngx_string("Cookie"),
|
||||
offsetof(ngx_http_headers_in_t, cookies),
|
||||
ngx_http_set_builtin_multi_header },
|
||||
#endif
|
||||
|
||||
{ ngx_null_string, 0, ngx_http_set_header }
|
||||
};
|
||||
|
||||
|
||||
/* request time implementation */
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_set_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv,
|
||||
ngx_str_t *value)
|
||||
{
|
||||
return ngx_http_set_header_helper(r, hv, value, NULL);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_set_header_helper(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv,
|
||||
ngx_str_t *value, ngx_table_elt_t **output_header)
|
||||
{
|
||||
ngx_table_elt_t *h, *matched;
|
||||
ngx_list_part_t *part;
|
||||
ngx_uint_t i;
|
||||
ngx_uint_t rc;
|
||||
|
||||
if (hv->no_override) {
|
||||
goto new_header;
|
||||
}
|
||||
|
||||
matched = NULL;
|
||||
|
||||
retry:
|
||||
|
||||
part = &r->headers_in.headers.part;
|
||||
h = part->elts;
|
||||
|
||||
for (i = 0; /* void */; i++) {
|
||||
if (i >= part->nelts) {
|
||||
if (part->next == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
part = part->next;
|
||||
h = part->elts;
|
||||
i = 0;
|
||||
}
|
||||
|
||||
dd("i: %d, part: %p", (int) i, part);
|
||||
|
||||
if (h[i].key.len == hv->key.len
|
||||
&& ngx_strncasecmp(h[i].key.data, hv->key.data, h[i].key.len)
|
||||
== 0)
|
||||
{
|
||||
if (value->len == 0 || (matched && matched != &h[i])) {
|
||||
h[i].hash = 0;
|
||||
|
||||
dd("rm header %.*s: %.*s", (int) h[i].key.len, h[i].key.data,
|
||||
(int) h[i].value.len, h[i].value.data);
|
||||
|
||||
rc = ngx_http_lua_rm_header_helper(&r->headers_in.headers,
|
||||
part, i);
|
||||
|
||||
ngx_http_lua_assert(!(r->headers_in.headers.part.next == NULL
|
||||
&& r->headers_in.headers.last
|
||||
!= &r->headers_in.headers.part));
|
||||
|
||||
dd("rm header: rc=%d", (int) rc);
|
||||
|
||||
if (rc == NGX_OK) {
|
||||
|
||||
if (output_header) {
|
||||
*output_header = NULL;
|
||||
}
|
||||
|
||||
goto retry;
|
||||
}
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
h[i].value = *value;
|
||||
|
||||
if (output_header) {
|
||||
*output_header = &h[i];
|
||||
dd("setting existing builtin input header");
|
||||
}
|
||||
|
||||
if (matched == NULL) {
|
||||
matched = &h[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (matched){
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (value->len == 0) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
new_header:
|
||||
|
||||
h = ngx_list_push(&r->headers_in.headers);
|
||||
|
||||
if (h == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
dd("created new header for %.*s", (int) hv->key.len, hv->key.data);
|
||||
|
||||
if (value->len == 0) {
|
||||
h->hash = 0;
|
||||
|
||||
} else {
|
||||
h->hash = hv->hash;
|
||||
}
|
||||
|
||||
h->key = hv->key;
|
||||
h->value = *value;
|
||||
|
||||
h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
|
||||
if (h->lowcase_key == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
|
||||
|
||||
if (output_header) {
|
||||
*output_header = h;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_set_builtin_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value)
|
||||
{
|
||||
ngx_table_elt_t *h, **old;
|
||||
|
||||
dd("entered set_builtin_header (input)");
|
||||
|
||||
if (hv->offset) {
|
||||
old = (ngx_table_elt_t **) ((char *) &r->headers_in + hv->offset);
|
||||
|
||||
} else {
|
||||
old = NULL;
|
||||
}
|
||||
|
||||
dd("old builtin ptr ptr: %p", old);
|
||||
if (old) {
|
||||
dd("old builtin ptr: %p", *old);
|
||||
}
|
||||
|
||||
if (old == NULL || *old == NULL) {
|
||||
dd("set normal header");
|
||||
return ngx_http_set_header_helper(r, hv, value, old);
|
||||
}
|
||||
|
||||
h = *old;
|
||||
|
||||
if (value->len == 0) {
|
||||
h->hash = 0;
|
||||
h->value = *value;
|
||||
|
||||
return ngx_http_set_header_helper(r, hv, value, old);
|
||||
}
|
||||
|
||||
h->hash = hv->hash;
|
||||
h->value = *value;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_lua_validate_host(ngx_str_t *host, ngx_pool_t *pool, ngx_uint_t alloc)
|
||||
{
|
||||
u_char *h, ch;
|
||||
size_t i, dot_pos, host_len;
|
||||
|
||||
enum {
|
||||
sw_usual = 0,
|
||||
sw_literal,
|
||||
sw_rest,
|
||||
} state;
|
||||
|
||||
dot_pos = host->len;
|
||||
host_len = host->len;
|
||||
|
||||
h = host->data;
|
||||
|
||||
state = sw_usual;
|
||||
|
||||
for (i = 0; i < host->len; i++) {
|
||||
ch = h[i];
|
||||
|
||||
switch (ch) {
|
||||
|
||||
case '.':
|
||||
if (dot_pos == i - 1) {
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
dot_pos = i;
|
||||
break;
|
||||
|
||||
case ':':
|
||||
if (state == sw_usual) {
|
||||
host_len = i;
|
||||
state = sw_rest;
|
||||
}
|
||||
break;
|
||||
|
||||
case '[':
|
||||
if (i == 0) {
|
||||
state = sw_literal;
|
||||
}
|
||||
break;
|
||||
|
||||
case ']':
|
||||
if (state == sw_literal) {
|
||||
host_len = i + 1;
|
||||
state = sw_rest;
|
||||
}
|
||||
break;
|
||||
|
||||
case '\0':
|
||||
return NGX_DECLINED;
|
||||
|
||||
default:
|
||||
|
||||
if (ngx_path_separator(ch)) {
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
if (ch >= 'A' && ch <= 'Z') {
|
||||
alloc = 1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (dot_pos == host_len - 1) {
|
||||
host_len--;
|
||||
}
|
||||
|
||||
if (host_len == 0) {
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
if (alloc) {
|
||||
host->data = ngx_pnalloc(pool, host_len);
|
||||
if (host->data == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_strlow(host->data, h, host_len);
|
||||
}
|
||||
|
||||
host->len = host_len;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_set_host_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv,
|
||||
ngx_str_t *value)
|
||||
{
|
||||
ngx_str_t host;
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
ngx_http_variable_value_t *var;
|
||||
|
||||
dd("server new value len: %d", (int) value->len);
|
||||
|
||||
lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
|
||||
|
||||
if (value->len) {
|
||||
host= *value;
|
||||
|
||||
if (ngx_http_lua_validate_host(&host, r->pool, 0) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
r->headers_in.server = host;
|
||||
|
||||
} else {
|
||||
r->headers_in.server = *value;
|
||||
}
|
||||
|
||||
var = &r->variables[lmcf->host_var_index];
|
||||
var->valid = 0;
|
||||
var->not_found = 0;
|
||||
|
||||
return ngx_http_set_builtin_header(r, hv, value);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_set_connection_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value)
|
||||
{
|
||||
r->headers_in.connection_type = 0;
|
||||
|
||||
if (value->len == 0) {
|
||||
return ngx_http_set_builtin_header(r, hv, value);
|
||||
}
|
||||
|
||||
if (ngx_strcasestrn(value->data, "close", 5 - 1)) {
|
||||
r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE;
|
||||
r->headers_in.keep_alive_n = -1;
|
||||
|
||||
} else if (ngx_strcasestrn(value->data, "keep-alive", 10 - 1)) {
|
||||
r->headers_in.connection_type = NGX_HTTP_CONNECTION_KEEP_ALIVE;
|
||||
}
|
||||
|
||||
return ngx_http_set_builtin_header(r, hv, value);
|
||||
}
|
||||
|
||||
|
||||
/* borrowed the code from ngx_http_request.c:ngx_http_process_user_agent */
|
||||
static ngx_int_t
|
||||
ngx_http_set_user_agent_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value)
|
||||
{
|
||||
u_char *user_agent, *msie;
|
||||
|
||||
/* clear existing settings */
|
||||
|
||||
r->headers_in.msie = 0;
|
||||
r->headers_in.msie6 = 0;
|
||||
r->headers_in.opera = 0;
|
||||
r->headers_in.gecko = 0;
|
||||
r->headers_in.chrome = 0;
|
||||
r->headers_in.safari = 0;
|
||||
r->headers_in.konqueror = 0;
|
||||
|
||||
if (value->len == 0) {
|
||||
return ngx_http_set_builtin_header(r, hv, value);
|
||||
}
|
||||
|
||||
/* check some widespread browsers */
|
||||
|
||||
user_agent = value->data;
|
||||
|
||||
msie = ngx_strstrn(user_agent, "MSIE ", 5 - 1);
|
||||
|
||||
if (msie && msie + 7 < user_agent + value->len) {
|
||||
|
||||
r->headers_in.msie = 1;
|
||||
|
||||
if (msie[6] == '.') {
|
||||
|
||||
switch (msie[5]) {
|
||||
case '4':
|
||||
case '5':
|
||||
r->headers_in.msie6 = 1;
|
||||
break;
|
||||
case '6':
|
||||
if (ngx_strstrn(msie + 8, "SV1", 3 - 1) == NULL) {
|
||||
r->headers_in.msie6 = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ngx_strstrn(user_agent, "Opera", 5 - 1)) {
|
||||
r->headers_in.opera = 1;
|
||||
r->headers_in.msie = 0;
|
||||
r->headers_in.msie6 = 0;
|
||||
}
|
||||
|
||||
if (!r->headers_in.msie && !r->headers_in.opera) {
|
||||
|
||||
if (ngx_strstrn(user_agent, "Gecko/", 6 - 1)) {
|
||||
r->headers_in.gecko = 1;
|
||||
|
||||
} else if (ngx_strstrn(user_agent, "Chrome/", 7 - 1)) {
|
||||
r->headers_in.chrome = 1;
|
||||
|
||||
} else if (ngx_strstrn(user_agent, "Safari/", 7 - 1)
|
||||
&& ngx_strstrn(user_agent, "Mac OS X", 8 - 1))
|
||||
{
|
||||
r->headers_in.safari = 1;
|
||||
|
||||
} else if (ngx_strstrn(user_agent, "Konqueror", 9 - 1)) {
|
||||
r->headers_in.konqueror = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return ngx_http_set_builtin_header(r, hv, value);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_set_content_length_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value)
|
||||
{
|
||||
off_t len;
|
||||
|
||||
if (value->len == 0) {
|
||||
return ngx_http_clear_content_length_header(r, hv, value);
|
||||
}
|
||||
|
||||
len = ngx_atoof(value->data, value->len);
|
||||
if (len == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
dd("reset headers_in.content_length_n to %d", (int) len);
|
||||
|
||||
r->headers_in.content_length_n = len;
|
||||
|
||||
return ngx_http_set_builtin_header(r, hv, value);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_set_builtin_multi_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value)
|
||||
{
|
||||
#if defined(nginx_version) && nginx_version >= 1023000
|
||||
ngx_table_elt_t **headers, **ph, *h;
|
||||
int nelts;
|
||||
|
||||
headers = (ngx_table_elt_t **) ((char *) &r->headers_in + hv->offset);
|
||||
|
||||
if (!hv->no_override && *headers != NULL) {
|
||||
nelts = 0;
|
||||
for (h = *headers; h; h = h->next) {
|
||||
nelts++;
|
||||
}
|
||||
|
||||
*headers = NULL;
|
||||
|
||||
dd("clear multi-value headers: %d", nelts);
|
||||
}
|
||||
|
||||
if (ngx_http_set_header_helper(r, hv, value, &h) == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (value->len == 0) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
dd("new multi-value header: %p", h);
|
||||
|
||||
if (*headers) {
|
||||
for (ph = headers; *ph; ph = &(*ph)->next) { /* void */ }
|
||||
*ph = h;
|
||||
|
||||
} else {
|
||||
*headers = h;
|
||||
}
|
||||
|
||||
h->next = NULL;
|
||||
|
||||
return NGX_OK;
|
||||
#else
|
||||
ngx_array_t *headers;
|
||||
ngx_table_elt_t **v, *h;
|
||||
|
||||
headers = (ngx_array_t *) ((char *) &r->headers_in + hv->offset);
|
||||
|
||||
if (!hv->no_override && headers->nelts > 0) {
|
||||
ngx_array_destroy(headers);
|
||||
|
||||
if (ngx_array_init(headers, r->pool, 2,
|
||||
sizeof(ngx_table_elt_t *))
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
dd("clear multi-value headers: %d", (int) headers->nelts);
|
||||
}
|
||||
|
||||
#if 1
|
||||
if (headers->nalloc == 0) {
|
||||
if (ngx_array_init(headers, r->pool, 2,
|
||||
sizeof(ngx_table_elt_t *))
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ngx_http_set_header_helper(r, hv, value, &h) == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (value->len == 0) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
dd("new multi-value header: %p", h);
|
||||
|
||||
v = ngx_array_push(headers);
|
||||
if (v == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
*v = h;
|
||||
return NGX_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_clear_content_length_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value)
|
||||
{
|
||||
r->headers_in.content_length_n = -1;
|
||||
|
||||
return ngx_http_clear_builtin_header(r, hv, value);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_clear_builtin_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value)
|
||||
{
|
||||
value->len = 0;
|
||||
return ngx_http_set_builtin_header(r, hv, value);
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_set_input_header(ngx_http_request_t *r, ngx_str_t key,
|
||||
ngx_str_t value, unsigned override)
|
||||
{
|
||||
ngx_http_lua_header_val_t hv;
|
||||
ngx_http_lua_set_header_t *handlers = ngx_http_lua_set_handlers;
|
||||
ngx_int_t rc;
|
||||
ngx_uint_t i;
|
||||
|
||||
dd("set header value: %.*s", (int) value.len, value.data);
|
||||
|
||||
rc = ngx_http_lua_copy_escaped_header(r, &key, 1);
|
||||
if (rc != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
rc = ngx_http_lua_copy_escaped_header(r, &value, 0);
|
||||
if (rc != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (value.len > 0) {
|
||||
hv.hash = ngx_hash_key_lc(key.data, key.len);
|
||||
|
||||
} else {
|
||||
hv.hash = 0;
|
||||
}
|
||||
|
||||
hv.key = key;
|
||||
|
||||
hv.offset = 0;
|
||||
hv.no_override = !override;
|
||||
hv.handler = NULL;
|
||||
|
||||
for (i = 0; handlers[i].name.len; i++) {
|
||||
if (hv.key.len != handlers[i].name.len
|
||||
|| ngx_strncasecmp(hv.key.data, handlers[i].name.data,
|
||||
handlers[i].name.len) != 0)
|
||||
{
|
||||
dd("hv key comparison: %s <> %s", handlers[i].name.data,
|
||||
hv.key.data);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
dd("Matched handler: %s %s", handlers[i].name.data, hv.key.data);
|
||||
|
||||
hv.offset = handlers[i].offset;
|
||||
hv.handler = handlers[i].handler;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (handlers[i].name.len == 0 && handlers[i].handler) {
|
||||
hv.offset = handlers[i].offset;
|
||||
hv.handler = handlers[i].handler;
|
||||
}
|
||||
|
||||
#if 1
|
||||
if (hv.handler == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (r->headers_out.status == 400 || r->headers_in.headers.last == NULL) {
|
||||
/* must be a 400 Bad Request */
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
return hv.handler(r, &hv, &value);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_lua_rm_header_helper(ngx_list_t *l, ngx_list_part_t *cur,
|
||||
ngx_uint_t i)
|
||||
{
|
||||
ngx_table_elt_t *data;
|
||||
ngx_list_part_t *new, *part;
|
||||
|
||||
dd("list rm item: part %p, i %d, nalloc %d", cur, (int) i,
|
||||
(int) l->nalloc);
|
||||
|
||||
data = cur->elts;
|
||||
|
||||
dd("cur: nelts %d, nalloc %d", (int) cur->nelts,
|
||||
(int) l->nalloc);
|
||||
|
||||
dd("removing: \"%.*s:%.*s\"", (int) data[i].key.len, data[i].key.data,
|
||||
(int) data[i].value.len, data[i].value.data);
|
||||
|
||||
if (i == 0) {
|
||||
dd("first entry in the part");
|
||||
cur->elts = (char *) cur->elts + l->size;
|
||||
cur->nelts--;
|
||||
|
||||
if (cur == l->last) {
|
||||
dd("being the last part");
|
||||
if (cur->nelts == 0) {
|
||||
#if 1
|
||||
part = &l->part;
|
||||
dd("cur=%p, part=%p, part next=%p, last=%p",
|
||||
cur, part, part->next, l->last);
|
||||
|
||||
if (part == cur) {
|
||||
cur->elts = (char *) cur->elts - l->size;
|
||||
/* do nothing */
|
||||
|
||||
} else {
|
||||
while (part->next != cur) {
|
||||
if (part->next == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
part = part->next;
|
||||
}
|
||||
|
||||
l->last = part;
|
||||
part->next = NULL;
|
||||
dd("part nelts: %d", (int) part->nelts);
|
||||
l->nalloc = part->nelts;
|
||||
}
|
||||
#endif
|
||||
|
||||
} else {
|
||||
l->nalloc--;
|
||||
dd("nalloc decreased: %d", (int) l->nalloc);
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (cur->nelts == 0) {
|
||||
dd("current part is empty");
|
||||
part = &l->part;
|
||||
if (part == cur) {
|
||||
ngx_http_lua_assert(cur->next != NULL);
|
||||
|
||||
dd("remove 'cur' from the list by rewriting 'cur': "
|
||||
"l->last: %p, cur: %p, cur->next: %p, part: %p",
|
||||
l->last, cur, cur->next, part);
|
||||
|
||||
if (l->last == cur->next) {
|
||||
dd("last is cur->next");
|
||||
l->part = *(cur->next);
|
||||
l->last = part;
|
||||
l->nalloc = part->nelts;
|
||||
|
||||
} else {
|
||||
l->part = *(cur->next);
|
||||
}
|
||||
|
||||
} else {
|
||||
dd("remove 'cur' from the list");
|
||||
while (part->next != cur) {
|
||||
if (part->next == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
part = part->next;
|
||||
}
|
||||
|
||||
part->next = cur->next;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (i == cur->nelts - 1) {
|
||||
dd("last entry in the part");
|
||||
|
||||
cur->nelts--;
|
||||
|
||||
if (cur == l->last) {
|
||||
l->nalloc--;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
dd("the middle entry in the part");
|
||||
|
||||
new = ngx_palloc(l->pool, sizeof(ngx_list_part_t));
|
||||
if (new == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
new->elts = &data[i + 1];
|
||||
new->nelts = cur->nelts - i - 1;
|
||||
new->next = cur->next;
|
||||
|
||||
cur->nelts = i;
|
||||
cur->next = new;
|
||||
|
||||
if (cur == l->last) {
|
||||
l->last = new;
|
||||
l->nalloc = new->nelts;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_HEADERS_IN_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_HEADERS_IN_H_INCLUDED_
|
||||
|
||||
|
||||
#include <nginx.h>
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
ngx_int_t ngx_http_lua_set_input_header(ngx_http_request_t *r, ngx_str_t key,
|
||||
ngx_str_t value, unsigned override);
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_HEADERS_IN_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,742 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include <nginx.h>
|
||||
#include "ngx_http_lua_headers_out.h"
|
||||
#include "ngx_http_lua_util.h"
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
static ngx_int_t ngx_http_set_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value);
|
||||
static ngx_int_t ngx_http_set_header_helper(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value,
|
||||
ngx_table_elt_t **output_header, unsigned no_create);
|
||||
static ngx_int_t ngx_http_set_builtin_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value);
|
||||
static ngx_int_t ngx_http_set_builtin_multi_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value);
|
||||
static ngx_int_t ngx_http_set_last_modified_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value);
|
||||
static ngx_int_t ngx_http_set_content_length_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value);
|
||||
static ngx_int_t ngx_http_set_content_type_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value);
|
||||
static ngx_int_t ngx_http_clear_builtin_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value);
|
||||
static ngx_int_t ngx_http_clear_last_modified_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value);
|
||||
static ngx_int_t ngx_http_clear_content_length_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value);
|
||||
static ngx_int_t ngx_http_set_location_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value);
|
||||
|
||||
|
||||
static ngx_http_lua_set_header_t ngx_http_lua_set_handlers[] = {
|
||||
|
||||
{ ngx_string("Server"),
|
||||
offsetof(ngx_http_headers_out_t, server),
|
||||
ngx_http_set_builtin_header },
|
||||
|
||||
{ ngx_string("Date"),
|
||||
offsetof(ngx_http_headers_out_t, date),
|
||||
ngx_http_set_builtin_header },
|
||||
|
||||
#if 1
|
||||
{ ngx_string("Content-Encoding"),
|
||||
offsetof(ngx_http_headers_out_t, content_encoding),
|
||||
ngx_http_set_builtin_header },
|
||||
#endif
|
||||
|
||||
{ ngx_string("Location"),
|
||||
offsetof(ngx_http_headers_out_t, location),
|
||||
ngx_http_set_location_header },
|
||||
|
||||
{ ngx_string("Refresh"),
|
||||
offsetof(ngx_http_headers_out_t, refresh),
|
||||
ngx_http_set_builtin_header },
|
||||
|
||||
{ ngx_string("Last-Modified"),
|
||||
offsetof(ngx_http_headers_out_t, last_modified),
|
||||
ngx_http_set_last_modified_header },
|
||||
|
||||
{ ngx_string("Content-Range"),
|
||||
offsetof(ngx_http_headers_out_t, content_range),
|
||||
ngx_http_set_builtin_header },
|
||||
|
||||
{ ngx_string("Accept-Ranges"),
|
||||
offsetof(ngx_http_headers_out_t, accept_ranges),
|
||||
ngx_http_set_builtin_header },
|
||||
|
||||
{ ngx_string("WWW-Authenticate"),
|
||||
offsetof(ngx_http_headers_out_t, www_authenticate),
|
||||
ngx_http_set_builtin_header },
|
||||
|
||||
{ ngx_string("Expires"),
|
||||
offsetof(ngx_http_headers_out_t, expires),
|
||||
ngx_http_set_builtin_header },
|
||||
|
||||
{ ngx_string("E-Tag"),
|
||||
offsetof(ngx_http_headers_out_t, etag),
|
||||
ngx_http_set_builtin_header },
|
||||
|
||||
{ ngx_string("ETag"),
|
||||
offsetof(ngx_http_headers_out_t, etag),
|
||||
ngx_http_set_builtin_header },
|
||||
|
||||
{ ngx_string("Content-Length"),
|
||||
offsetof(ngx_http_headers_out_t, content_length),
|
||||
ngx_http_set_content_length_header },
|
||||
|
||||
{ ngx_string("Content-Type"),
|
||||
offsetof(ngx_http_headers_out_t, content_type),
|
||||
ngx_http_set_content_type_header },
|
||||
|
||||
{ ngx_string("Cache-Control"),
|
||||
offsetof(ngx_http_headers_out_t, cache_control),
|
||||
ngx_http_set_builtin_multi_header },
|
||||
|
||||
#if (nginx_version >= 1013009)
|
||||
{ ngx_string("Link"),
|
||||
offsetof(ngx_http_headers_out_t, link),
|
||||
ngx_http_set_builtin_multi_header },
|
||||
#endif
|
||||
|
||||
{ ngx_null_string, 0, ngx_http_set_header }
|
||||
};
|
||||
|
||||
|
||||
/* request time implementation */
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_set_header(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv,
|
||||
ngx_str_t *value)
|
||||
{
|
||||
return ngx_http_set_header_helper(r, hv, value, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_set_header_helper(ngx_http_request_t *r, ngx_http_lua_header_val_t *hv,
|
||||
ngx_str_t *value, ngx_table_elt_t **output_header,
|
||||
unsigned no_create)
|
||||
{
|
||||
ngx_table_elt_t *h;
|
||||
ngx_list_part_t *part;
|
||||
ngx_uint_t i;
|
||||
unsigned matched = 0;
|
||||
|
||||
if (hv->no_override) {
|
||||
goto new_header;
|
||||
}
|
||||
|
||||
#if 1
|
||||
if (r->headers_out.location
|
||||
&& r->headers_out.location->value.len
|
||||
&& r->headers_out.location->value.data[0] == '/')
|
||||
{
|
||||
/* XXX ngx_http_core_find_config_phase, for example,
|
||||
* may not initialize the "key" and "hash" fields
|
||||
* for a nasty optimization purpose, and
|
||||
* we have to work-around it here */
|
||||
|
||||
r->headers_out.location->hash = ngx_http_lua_location_hash;
|
||||
ngx_str_set(&r->headers_out.location->key, "Location");
|
||||
}
|
||||
#endif
|
||||
|
||||
part = &r->headers_out.headers.part;
|
||||
h = part->elts;
|
||||
|
||||
for (i = 0; /* void */; i++) {
|
||||
|
||||
if (i >= part->nelts) {
|
||||
if (part->next == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
part = part->next;
|
||||
h = part->elts;
|
||||
i = 0;
|
||||
}
|
||||
|
||||
if (h[i].hash != 0
|
||||
&& h[i].key.len == hv->key.len
|
||||
&& ngx_strncasecmp(hv->key.data, h[i].key.data, h[i].key.len) == 0)
|
||||
{
|
||||
dd("found out header %.*s", (int) h[i].key.len, h[i].key.data);
|
||||
|
||||
if (value->len == 0 || matched) {
|
||||
dd("clearing normal header for %.*s", (int) hv->key.len,
|
||||
hv->key.data);
|
||||
|
||||
h[i].value.len = 0;
|
||||
h[i].hash = 0;
|
||||
|
||||
} else {
|
||||
dd("setting header to value %.*s", (int) value->len,
|
||||
value->data);
|
||||
|
||||
h[i].value = *value;
|
||||
h[i].hash = hv->hash;
|
||||
}
|
||||
|
||||
if (output_header) {
|
||||
*output_header = &h[i];
|
||||
}
|
||||
|
||||
/* return NGX_OK; */
|
||||
matched = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (matched){
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (no_create && value->len == 0) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
new_header:
|
||||
|
||||
/* XXX we still need to create header slot even if the value
|
||||
* is empty because some builtin headers like Last-Modified
|
||||
* relies on this to get cleared */
|
||||
|
||||
h = ngx_list_push(&r->headers_out.headers);
|
||||
|
||||
if (h == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (value->len == 0) {
|
||||
h->hash = 0;
|
||||
|
||||
} else {
|
||||
h->hash = hv->hash;
|
||||
}
|
||||
|
||||
h->key = hv->key;
|
||||
h->value = *value;
|
||||
|
||||
h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
|
||||
if (h->lowcase_key == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
|
||||
|
||||
if (output_header) {
|
||||
*output_header = h;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_set_location_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
ngx_table_elt_t *h;
|
||||
|
||||
rc = ngx_http_set_builtin_header(r, hv, value);
|
||||
if (rc != NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* we do not set r->headers_out.location here to avoid the handling
|
||||
* the local redirects without a host name by ngx_http_header_filter()
|
||||
*/
|
||||
|
||||
h = r->headers_out.location;
|
||||
if (h && h->value.len && h->value.data[0] == '/') {
|
||||
r->headers_out.location = NULL;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_set_builtin_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value)
|
||||
{
|
||||
ngx_table_elt_t *h, **old;
|
||||
|
||||
if (hv->offset) {
|
||||
old = (ngx_table_elt_t **) ((char *) &r->headers_out + hv->offset);
|
||||
|
||||
} else {
|
||||
old = NULL;
|
||||
}
|
||||
|
||||
if (old == NULL || *old == NULL) {
|
||||
return ngx_http_set_header_helper(r, hv, value, old, 0);
|
||||
}
|
||||
|
||||
h = *old;
|
||||
|
||||
if (value->len == 0) {
|
||||
dd("clearing the builtin header");
|
||||
|
||||
h->hash = 0;
|
||||
h->value = *value;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
h->hash = hv->hash;
|
||||
h->key = hv->key;
|
||||
h->value = *value;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_set_builtin_multi_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value)
|
||||
{
|
||||
#if defined(nginx_version) && nginx_version >= 1023000
|
||||
ngx_table_elt_t **headers, *h, *ho, **ph;
|
||||
|
||||
headers = (ngx_table_elt_t **) ((char *) &r->headers_out + hv->offset);
|
||||
|
||||
if (hv->no_override) {
|
||||
for (h = *headers; h; h = h->next) {
|
||||
if (!h->hash) {
|
||||
h->value = *value;
|
||||
h->hash = hv->hash;
|
||||
return NGX_OK;
|
||||
}
|
||||
}
|
||||
|
||||
goto create;
|
||||
}
|
||||
|
||||
/* override old values (if any) */
|
||||
|
||||
if (*headers) {
|
||||
for (h = (*headers)->next; h; h = h->next) {
|
||||
h->hash = 0;
|
||||
h->value.len = 0;
|
||||
}
|
||||
|
||||
h = *headers;
|
||||
|
||||
h->value = *value;
|
||||
|
||||
if (value->len == 0) {
|
||||
h->hash = 0;
|
||||
|
||||
} else {
|
||||
h->hash = hv->hash;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
create:
|
||||
|
||||
for (ph = headers; *ph; ph = &(*ph)->next) { /* void */ }
|
||||
|
||||
ho = ngx_list_push(&r->headers_out.headers);
|
||||
if (ho == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ho->value = *value;
|
||||
|
||||
if (value->len == 0) {
|
||||
ho->hash = 0;
|
||||
|
||||
} else {
|
||||
ho->hash = hv->hash;
|
||||
}
|
||||
|
||||
ho->key = hv->key;
|
||||
ho->next = NULL;
|
||||
*ph = ho;
|
||||
|
||||
return NGX_OK;
|
||||
#else
|
||||
ngx_array_t *pa;
|
||||
ngx_table_elt_t *ho, **ph;
|
||||
ngx_uint_t i;
|
||||
|
||||
pa = (ngx_array_t *) ((char *) &r->headers_out + hv->offset);
|
||||
|
||||
if (pa->elts == NULL) {
|
||||
if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *))
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (hv->no_override) {
|
||||
ph = pa->elts;
|
||||
for (i = 0; i < pa->nelts; i++) {
|
||||
if (!ph[i]->hash) {
|
||||
ph[i]->value = *value;
|
||||
ph[i]->hash = hv->hash;
|
||||
return NGX_OK;
|
||||
}
|
||||
}
|
||||
|
||||
goto create;
|
||||
}
|
||||
|
||||
/* override old values (if any) */
|
||||
|
||||
if (pa->nelts > 0) {
|
||||
ph = pa->elts;
|
||||
for (i = 1; i < pa->nelts; i++) {
|
||||
ph[i]->hash = 0;
|
||||
ph[i]->value.len = 0;
|
||||
}
|
||||
|
||||
ph[0]->value = *value;
|
||||
|
||||
if (value->len == 0) {
|
||||
ph[0]->hash = 0;
|
||||
|
||||
} else {
|
||||
ph[0]->hash = hv->hash;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
create:
|
||||
|
||||
ph = ngx_array_push(pa);
|
||||
if (ph == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ho = ngx_list_push(&r->headers_out.headers);
|
||||
if (ho == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ho->value = *value;
|
||||
|
||||
if (value->len == 0) {
|
||||
ho->hash = 0;
|
||||
|
||||
} else {
|
||||
ho->hash = hv->hash;
|
||||
}
|
||||
|
||||
ho->key = hv->key;
|
||||
*ph = ho;
|
||||
|
||||
return NGX_OK;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_set_content_type_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value)
|
||||
{
|
||||
ngx_uint_t i;
|
||||
|
||||
r->headers_out.content_type_len = value->len;
|
||||
|
||||
#if 1
|
||||
for (i = 0; i < value->len; i++) {
|
||||
if (value->data[i] == ';') {
|
||||
r->headers_out.content_type_len = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
r->headers_out.content_type = *value;
|
||||
r->headers_out.content_type_hash = hv->hash;
|
||||
r->headers_out.content_type_lowcase = NULL;
|
||||
|
||||
value->len = 0;
|
||||
|
||||
return ngx_http_set_header_helper(r, hv, value, NULL, 1);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t ngx_http_set_last_modified_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value)
|
||||
{
|
||||
if (value->len == 0) {
|
||||
return ngx_http_clear_last_modified_header(r, hv, value);
|
||||
}
|
||||
|
||||
r->headers_out.last_modified_time = ngx_http_parse_time(value->data,
|
||||
value->len);
|
||||
|
||||
dd("last modified time: %d", (int) r->headers_out.last_modified_time);
|
||||
|
||||
return ngx_http_set_builtin_header(r, hv, value);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_clear_last_modified_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value)
|
||||
{
|
||||
r->headers_out.last_modified_time = -1;
|
||||
|
||||
return ngx_http_clear_builtin_header(r, hv, value);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_set_content_length_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value)
|
||||
{
|
||||
off_t len;
|
||||
|
||||
if (value->len == 0) {
|
||||
return ngx_http_clear_content_length_header(r, hv, value);
|
||||
}
|
||||
|
||||
len = ngx_atoof(value->data, value->len);
|
||||
if (len == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
r->headers_out.content_length_n = len;
|
||||
|
||||
return ngx_http_set_builtin_header(r, hv, value);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_clear_content_length_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value)
|
||||
{
|
||||
r->headers_out.content_length_n = -1;
|
||||
|
||||
return ngx_http_clear_builtin_header(r, hv, value);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_clear_builtin_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_header_val_t *hv, ngx_str_t *value)
|
||||
{
|
||||
value->len = 0;
|
||||
|
||||
return ngx_http_set_builtin_header(r, hv, value);
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx,
|
||||
ngx_str_t key, ngx_str_t value, unsigned override)
|
||||
{
|
||||
ngx_http_lua_header_val_t hv;
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
ngx_http_lua_set_header_t *lsh;
|
||||
ngx_hash_t *hash;
|
||||
|
||||
dd("set header value: %.*s", (int) value.len, value.data);
|
||||
|
||||
if (ngx_http_lua_copy_escaped_header(r, &key, 1) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ngx_http_lua_copy_escaped_header(r, &value, 0) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
hv.hash = ngx_hash_key_lc(key.data, key.len);
|
||||
hv.key = key;
|
||||
|
||||
hv.offset = 0;
|
||||
hv.no_override = !override;
|
||||
hv.handler = ngx_http_set_header;
|
||||
|
||||
lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
|
||||
hash = &lmcf->builtin_headers_out;
|
||||
lsh = ngx_http_lua_hash_find_lc(hash, hv.hash, hv.key.data, hv.key.len);
|
||||
if (lsh) {
|
||||
dd("Matched handler: %s %s", lsh->name.data, hv.key.data);
|
||||
hv.offset = lsh->offset;
|
||||
hv.handler = lsh->handler;
|
||||
if (hv.handler == ngx_http_set_content_type_header) {
|
||||
ctx->mime_set = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return hv.handler(r, &hv, &value);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r,
|
||||
ngx_http_lua_ctx_t *ctx, ngx_str_t *key)
|
||||
{
|
||||
ngx_table_elt_t *h;
|
||||
ngx_list_part_t *part;
|
||||
ngx_uint_t i;
|
||||
unsigned found;
|
||||
|
||||
dd("looking for response header \"%.*s\"", (int) key->len, key->data);
|
||||
|
||||
switch (key->len) {
|
||||
case 14:
|
||||
if (r->headers_out.content_length == NULL
|
||||
&& r->headers_out.content_length_n >= 0
|
||||
&& ngx_strncasecmp(key->data, (u_char *) "Content-Length", 14) == 0)
|
||||
{
|
||||
lua_pushinteger(L, (lua_Integer) r->headers_out.content_length_n);
|
||||
return 1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 12:
|
||||
if (ngx_strncasecmp(key->data, (u_char *) "Content-Type", 12) == 0
|
||||
&& r->headers_out.content_type.len)
|
||||
{
|
||||
lua_pushlstring(L, (char *) r->headers_out.content_type.data,
|
||||
r->headers_out.content_type.len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
dd("not a built-in output header");
|
||||
|
||||
found = 0;
|
||||
|
||||
#if 1
|
||||
if (r->headers_out.location
|
||||
&& r->headers_out.location->value.len
|
||||
&& r->headers_out.location->value.data[0] == '/')
|
||||
{
|
||||
/* XXX ngx_http_core_find_config_phase, for example,
|
||||
* may not initialize the "key" and "hash" fields
|
||||
* for a nasty optimization purpose, and
|
||||
* we have to work-around it here */
|
||||
|
||||
r->headers_out.location->hash = ngx_http_lua_location_hash;
|
||||
ngx_str_set(&r->headers_out.location->key, "Location");
|
||||
}
|
||||
#endif
|
||||
|
||||
part = &r->headers_out.headers.part;
|
||||
h = part->elts;
|
||||
|
||||
for (i = 0; /* void */; i++) {
|
||||
|
||||
if (i >= part->nelts) {
|
||||
if (part->next == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
part = part->next;
|
||||
h = part->elts;
|
||||
i = 0;
|
||||
}
|
||||
|
||||
if (h[i].hash == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (h[i].hash != 0
|
||||
&& h[i].key.len == key->len
|
||||
&& ngx_strncasecmp(key->data, h[i].key.data, h[i].key.len) == 0)
|
||||
{
|
||||
if (!found) {
|
||||
found = 1;
|
||||
|
||||
lua_pushlstring(L, (char *) h[i].value.data, h[i].value.len);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (found == 1) {
|
||||
lua_createtable(L, 4 /* narr */, 0);
|
||||
lua_insert(L, -2);
|
||||
lua_rawseti(L, -2, found);
|
||||
}
|
||||
|
||||
found++;
|
||||
|
||||
lua_pushlstring(L, (char *) h[i].value.data, h[i].value.len);
|
||||
lua_rawseti(L, -2, found);
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_init_builtin_headers_out(ngx_conf_t *cf,
|
||||
ngx_http_lua_main_conf_t *lmcf)
|
||||
{
|
||||
ngx_array_t headers;
|
||||
ngx_hash_key_t *hk;
|
||||
ngx_hash_init_t hash;
|
||||
ngx_http_lua_set_header_t *handlers = ngx_http_lua_set_handlers;
|
||||
ngx_uint_t count;
|
||||
|
||||
count = sizeof(ngx_http_lua_set_handlers)
|
||||
/ sizeof(ngx_http_lua_set_header_t);
|
||||
|
||||
if (ngx_array_init(&headers, cf->temp_pool, count, sizeof(ngx_hash_key_t))
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
while (handlers->name.data) {
|
||||
hk = ngx_array_push(&headers);
|
||||
if (hk == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
hk->key = handlers->name;
|
||||
hk->key_hash = ngx_hash_key_lc(handlers->name.data, handlers->name.len);
|
||||
hk->value = (void *) handlers;
|
||||
|
||||
handlers++;
|
||||
}
|
||||
|
||||
hash.hash = &lmcf->builtin_headers_out;
|
||||
hash.key = ngx_hash_key_lc;
|
||||
hash.max_size = 512;
|
||||
hash.bucket_size = ngx_align(64, ngx_cacheline_size);
|
||||
hash.name = "builtin_headers_out_hash";
|
||||
hash.pool = cf->pool;
|
||||
hash.temp_pool = NULL;
|
||||
|
||||
return ngx_hash_init(&hash, headers.elts, headers.nelts);
|
||||
}
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,41 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_HEADERS_OUT_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_HEADERS_OUT_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
#if (NGX_DARWIN)
|
||||
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;
|
||||
#endif
|
||||
|
||||
|
||||
ngx_int_t ngx_http_lua_set_output_header(ngx_http_request_t *r,
|
||||
ngx_http_lua_ctx_t *ctx, ngx_str_t key, ngx_str_t value, unsigned override);
|
||||
int ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r,
|
||||
ngx_http_lua_ctx_t *ctx, ngx_str_t *key);
|
||||
ngx_int_t ngx_http_lua_init_builtin_headers_out(ngx_conf_t *cf,
|
||||
ngx_http_lua_main_conf_t *lmcf);
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_HEADERS_OUT_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,51 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
|
||||
#include "ddebug.h"
|
||||
#include "ngx_http_lua_initby.h"
|
||||
#include "ngx_http_lua_util.h"
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_init_by_inline(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf,
|
||||
lua_State *L)
|
||||
{
|
||||
int status;
|
||||
const char *chunkname;
|
||||
|
||||
|
||||
if (lmcf->init_chunkname == NULL) {
|
||||
chunkname = "=init_by_lua";
|
||||
|
||||
} else {
|
||||
chunkname = (const char *) lmcf->init_chunkname;
|
||||
}
|
||||
|
||||
status = luaL_loadbuffer(L, (char *) lmcf->init_src.data,
|
||||
lmcf->init_src.len, chunkname)
|
||||
|| ngx_http_lua_do_call(log, L);
|
||||
|
||||
return ngx_http_lua_report(log, L, status, "init_by_lua");
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_init_by_file(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf,
|
||||
lua_State *L)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = luaL_loadfile(L, (char *) lmcf->init_src.data)
|
||||
|| ngx_http_lua_do_call(log, L);
|
||||
|
||||
return ngx_http_lua_report(log, L, status, "init_by_lua_file");
|
||||
}
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_INITBY_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_INITBY_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
ngx_int_t ngx_http_lua_init_by_inline(ngx_log_t *log,
|
||||
ngx_http_lua_main_conf_t *lmcf, lua_State *L);
|
||||
|
||||
ngx_int_t ngx_http_lua_init_by_file(ngx_log_t *log,
|
||||
ngx_http_lua_main_conf_t *lmcf, lua_State *L);
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_INITBY_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,367 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_http_lua_initworkerby.h"
|
||||
#include "ngx_http_lua_util.h"
|
||||
#include "ngx_http_lua_pipe.h"
|
||||
|
||||
|
||||
static u_char *ngx_http_lua_log_init_worker_error(ngx_log_t *log,
|
||||
u_char *buf, size_t len);
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_init_worker(ngx_cycle_t *cycle)
|
||||
{
|
||||
char *rv;
|
||||
void *cur, *prev;
|
||||
ngx_uint_t i;
|
||||
ngx_conf_t conf;
|
||||
ngx_conf_file_t cf_file;
|
||||
ngx_cycle_t *fake_cycle;
|
||||
ngx_module_t **modules;
|
||||
ngx_open_file_t *file, *ofile;
|
||||
ngx_list_part_t *part;
|
||||
ngx_connection_t *c = NULL;
|
||||
ngx_http_module_t *module;
|
||||
ngx_http_request_t *r = NULL;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_http_conf_ctx_t *conf_ctx, http_ctx;
|
||||
ngx_http_lua_loc_conf_t *top_llcf;
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
ngx_http_core_loc_conf_t *clcf, *top_clcf;
|
||||
|
||||
lmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_lua_module);
|
||||
|
||||
if (lmcf == NULL || lmcf->lua == NULL) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
/* lmcf != NULL && lmcf->lua != NULL */
|
||||
|
||||
#if !(NGX_WIN32)
|
||||
if (ngx_process == NGX_PROCESS_HELPER
|
||||
# ifdef HAVE_PRIVILEGED_PROCESS_PATCH
|
||||
&& !ngx_is_privileged_agent
|
||||
# endif
|
||||
)
|
||||
{
|
||||
/* disable init_worker_by_lua* and destroy lua VM in cache processes */
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
|
||||
"lua close the global Lua VM %p in the "
|
||||
"cache helper process %P", lmcf->lua, ngx_pid);
|
||||
|
||||
lmcf->vm_cleanup->handler(lmcf->vm_cleanup->data);
|
||||
lmcf->vm_cleanup->handler = NULL;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
# ifdef HAVE_NGX_LUA_PIPE
|
||||
if (ngx_http_lua_pipe_add_signal_handler(cycle) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
# endif
|
||||
|
||||
#endif /* NGX_WIN32 */
|
||||
|
||||
#if (NGX_HTTP_LUA_HAVE_SA_RESTART)
|
||||
if (lmcf->set_sa_restart) {
|
||||
ngx_http_lua_set_sa_restart(ngx_cycle->log);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (lmcf->init_worker_handler == NULL) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
conf_ctx = (ngx_http_conf_ctx_t *) cycle->conf_ctx[ngx_http_module.index];
|
||||
http_ctx.main_conf = conf_ctx->main_conf;
|
||||
|
||||
top_clcf = conf_ctx->loc_conf[ngx_http_core_module.ctx_index];
|
||||
top_llcf = conf_ctx->loc_conf[ngx_http_lua_module.ctx_index];
|
||||
|
||||
ngx_memzero(&conf, sizeof(ngx_conf_t));
|
||||
|
||||
conf.temp_pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, cycle->log);
|
||||
if (conf.temp_pool == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
conf.temp_pool->log = cycle->log;
|
||||
|
||||
/* we fake a temporary ngx_cycle_t here because some
|
||||
* modules' merge conf handler may produce side effects in
|
||||
* cf->cycle (like ngx_proxy vs cf->cycle->paths).
|
||||
* also, we cannot allocate our temp cycle on the stack
|
||||
* because some modules like ngx_http_core_module reference
|
||||
* addresses within cf->cycle (i.e., via "&cf->cycle->new_log")
|
||||
*/
|
||||
|
||||
fake_cycle = ngx_palloc(cycle->pool, sizeof(ngx_cycle_t));
|
||||
if (fake_cycle == NULL) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
ngx_memcpy(fake_cycle, cycle, sizeof(ngx_cycle_t));
|
||||
|
||||
ngx_queue_init(&fake_cycle->reusable_connections_queue);
|
||||
|
||||
if (ngx_array_init(&fake_cycle->listening, cycle->pool,
|
||||
cycle->listening.nelts ? cycle->listening.nelts : 1,
|
||||
sizeof(ngx_listening_t))
|
||||
!= NGX_OK)
|
||||
{
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (ngx_array_init(&fake_cycle->paths, cycle->pool,
|
||||
cycle->paths.nelts ? cycle->paths.nelts : 1,
|
||||
sizeof(ngx_path_t *))
|
||||
!= NGX_OK)
|
||||
{
|
||||
goto failed;
|
||||
}
|
||||
|
||||
part = &cycle->open_files.part;
|
||||
ofile = part->elts;
|
||||
|
||||
if (ngx_list_init(&fake_cycle->open_files, cycle->pool,
|
||||
part->nelts ? part->nelts : 1,
|
||||
sizeof(ngx_open_file_t))
|
||||
!= NGX_OK)
|
||||
{
|
||||
goto failed;
|
||||
}
|
||||
|
||||
for (i = 0; /* void */ ; i++) {
|
||||
|
||||
if (i >= part->nelts) {
|
||||
if (part->next == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
part = part->next;
|
||||
ofile = part->elts;
|
||||
i = 0;
|
||||
}
|
||||
|
||||
file = ngx_list_push(&fake_cycle->open_files);
|
||||
if (file == NULL) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
ngx_memcpy(file, ofile, sizeof(ngx_open_file_t));
|
||||
}
|
||||
|
||||
if (ngx_list_init(&fake_cycle->shared_memory, cycle->pool, 1,
|
||||
sizeof(ngx_shm_zone_t))
|
||||
!= NGX_OK)
|
||||
{
|
||||
goto failed;
|
||||
}
|
||||
|
||||
conf.ctx = &http_ctx;
|
||||
conf.cycle = fake_cycle;
|
||||
conf.pool = fake_cycle->pool;
|
||||
conf.log = cycle->log;
|
||||
|
||||
ngx_memzero(&cf_file, sizeof(cf_file));
|
||||
cf_file.file.name = cycle->conf_file;
|
||||
conf.conf_file = &cf_file;
|
||||
|
||||
http_ctx.loc_conf = ngx_pcalloc(conf.pool,
|
||||
sizeof(void *) * ngx_http_max_module);
|
||||
if (http_ctx.loc_conf == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
http_ctx.srv_conf = ngx_pcalloc(conf.pool,
|
||||
sizeof(void *) * ngx_http_max_module);
|
||||
if (http_ctx.srv_conf == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
#if (nginx_version >= 1009011)
|
||||
modules = cycle->modules;
|
||||
#else
|
||||
modules = ngx_modules;
|
||||
#endif
|
||||
|
||||
for (i = 0; modules[i]; i++) {
|
||||
if (modules[i]->type != NGX_HTTP_MODULE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
module = modules[i]->ctx;
|
||||
|
||||
if (module->create_srv_conf) {
|
||||
cur = module->create_srv_conf(&conf);
|
||||
if (cur == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
http_ctx.srv_conf[modules[i]->ctx_index] = cur;
|
||||
|
||||
if (module->merge_srv_conf) {
|
||||
prev = module->create_srv_conf(&conf);
|
||||
if (prev == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
rv = module->merge_srv_conf(&conf, prev, cur);
|
||||
if (rv != NGX_CONF_OK) {
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (module->create_loc_conf) {
|
||||
cur = module->create_loc_conf(&conf);
|
||||
if (cur == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
http_ctx.loc_conf[modules[i]->ctx_index] = cur;
|
||||
|
||||
if (module->merge_loc_conf) {
|
||||
if (modules[i] == &ngx_http_lua_module) {
|
||||
prev = top_llcf;
|
||||
|
||||
} else if (modules[i] == &ngx_http_core_module) {
|
||||
prev = top_clcf;
|
||||
|
||||
} else {
|
||||
prev = module->create_loc_conf(&conf);
|
||||
if (prev == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
rv = module->merge_loc_conf(&conf, prev, cur);
|
||||
if (rv != NGX_CONF_OK) {
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ngx_destroy_pool(conf.temp_pool);
|
||||
conf.temp_pool = NULL;
|
||||
|
||||
c = ngx_http_lua_create_fake_connection(NULL);
|
||||
if (c == NULL) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
c->log->handler = ngx_http_lua_log_init_worker_error;
|
||||
|
||||
r = ngx_http_lua_create_fake_request(c);
|
||||
if (r == NULL) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
r->main_conf = http_ctx.main_conf;
|
||||
r->srv_conf = http_ctx.srv_conf;
|
||||
r->loc_conf = http_ctx.loc_conf;
|
||||
|
||||
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
|
||||
|
||||
#if (nginx_version >= 1009000)
|
||||
ngx_set_connection_log(r->connection, clcf->error_log);
|
||||
|
||||
#else
|
||||
ngx_http_set_connection_log(r->connection, clcf->error_log);
|
||||
#endif
|
||||
|
||||
ctx = ngx_http_lua_create_ctx(r);
|
||||
if (ctx == NULL) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
ctx->context = NGX_HTTP_LUA_CONTEXT_INIT_WORKER;
|
||||
ctx->cur_co_ctx = NULL;
|
||||
r->read_event_handler = ngx_http_block_reading;
|
||||
|
||||
ngx_http_lua_set_req(lmcf->lua, r);
|
||||
|
||||
(void) lmcf->init_worker_handler(cycle->log, lmcf, lmcf->lua);
|
||||
|
||||
ngx_destroy_pool(c->pool);
|
||||
return NGX_OK;
|
||||
|
||||
failed:
|
||||
|
||||
if (conf.temp_pool) {
|
||||
ngx_destroy_pool(conf.temp_pool);
|
||||
}
|
||||
|
||||
if (c) {
|
||||
ngx_http_lua_close_fake_connection(c);
|
||||
}
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_init_worker_by_inline(ngx_log_t *log,
|
||||
ngx_http_lua_main_conf_t *lmcf, lua_State *L)
|
||||
{
|
||||
int status;
|
||||
const char *chunkname;
|
||||
|
||||
if (lmcf->init_worker_chunkname == NULL) {
|
||||
chunkname = "=init_worker_by_lua";
|
||||
|
||||
} else {
|
||||
chunkname = (const char *) lmcf->init_worker_chunkname;
|
||||
}
|
||||
|
||||
status = luaL_loadbuffer(L, (char *) lmcf->init_worker_src.data,
|
||||
lmcf->init_worker_src.len, chunkname)
|
||||
|| ngx_http_lua_do_call(log, L);
|
||||
|
||||
return ngx_http_lua_report(log, L, status, "init_worker_by_lua");
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_init_worker_by_file(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf,
|
||||
lua_State *L)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = luaL_loadfile(L, (char *) lmcf->init_worker_src.data)
|
||||
|| ngx_http_lua_do_call(log, L);
|
||||
|
||||
return ngx_http_lua_report(log, L, status, "init_worker_by_lua_file");
|
||||
}
|
||||
|
||||
|
||||
static u_char *
|
||||
ngx_http_lua_log_init_worker_error(ngx_log_t *log, u_char *buf, size_t len)
|
||||
{
|
||||
u_char *p;
|
||||
|
||||
if (log->action) {
|
||||
p = ngx_snprintf(buf, len, " while %s", log->action);
|
||||
len -= p - buf;
|
||||
buf = p;
|
||||
}
|
||||
|
||||
return ngx_snprintf(buf, len, ", context: init_worker_by_lua*");
|
||||
}
|
||||
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_INITWORKERBY_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_INITWORKERBY_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
ngx_int_t ngx_http_lua_init_worker_by_inline(ngx_log_t *log,
|
||||
ngx_http_lua_main_conf_t *lmcf, lua_State *L);
|
||||
|
||||
ngx_int_t ngx_http_lua_init_worker_by_file(ngx_log_t *log,
|
||||
ngx_http_lua_main_conf_t *lmcf, lua_State *L);
|
||||
|
||||
ngx_int_t ngx_http_lua_init_worker(ngx_cycle_t *cycle);
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_INITWORKERBY_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,137 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) by OpenResty Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_read_bytes(ngx_buf_t *src, ngx_chain_t *buf_in, size_t *rest,
|
||||
ssize_t bytes, ngx_log_t *log)
|
||||
{
|
||||
if (bytes == 0) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if ((size_t) bytes >= *rest) {
|
||||
|
||||
buf_in->buf->last += *rest;
|
||||
src->pos += *rest;
|
||||
*rest = 0;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
/* bytes < *rest */
|
||||
|
||||
buf_in->buf->last += bytes;
|
||||
src->pos += bytes;
|
||||
*rest -= bytes;
|
||||
|
||||
return NGX_AGAIN;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_read_all(ngx_buf_t *src, ngx_chain_t *buf_in, ssize_t bytes,
|
||||
ngx_log_t *log)
|
||||
{
|
||||
if (bytes == 0) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
buf_in->buf->last += bytes;
|
||||
src->pos += bytes;
|
||||
|
||||
return NGX_AGAIN;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_read_any(ngx_buf_t *src, ngx_chain_t *buf_in, size_t *max,
|
||||
ssize_t bytes, ngx_log_t *log)
|
||||
{
|
||||
if (bytes == 0) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (bytes >= (ssize_t) *max) {
|
||||
bytes = (ssize_t) *max;
|
||||
}
|
||||
|
||||
buf_in->buf->last += bytes;
|
||||
src->pos += bytes;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_read_line(ngx_buf_t *src, ngx_chain_t *buf_in, ssize_t bytes,
|
||||
ngx_log_t *log)
|
||||
{
|
||||
u_char *dst;
|
||||
u_char c;
|
||||
#if (NGX_DEBUG)
|
||||
u_char *begin;
|
||||
#endif
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
begin = src->pos;
|
||||
#endif
|
||||
|
||||
if (bytes == 0) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
dd("already read: %p: %.*s", buf_in,
|
||||
(int) (buf_in->buf->last - buf_in->buf->pos), buf_in->buf->pos);
|
||||
|
||||
dd("data read: %.*s", (int) bytes, src->pos);
|
||||
|
||||
dst = buf_in->buf->last;
|
||||
|
||||
while (bytes--) {
|
||||
|
||||
c = *src->pos++;
|
||||
|
||||
switch (c) {
|
||||
case '\n':
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0,
|
||||
"lua read the final line part: \"%*s\"",
|
||||
src->pos - 1 - begin, begin);
|
||||
|
||||
buf_in->buf->last = dst;
|
||||
|
||||
dd("read a line: %p: %.*s", buf_in,
|
||||
(int) (buf_in->buf->last - buf_in->buf->pos), buf_in->buf->pos);
|
||||
|
||||
return NGX_OK;
|
||||
|
||||
case '\r':
|
||||
/* ignore it */
|
||||
break;
|
||||
|
||||
default:
|
||||
*dst++ = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0,
|
||||
"lua read partial line data: %*s", dst - begin, begin);
|
||||
#endif
|
||||
|
||||
buf_in->buf->last = dst;
|
||||
|
||||
return NGX_AGAIN;
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) by OpenResty Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_INPUT_FILTERS_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_INPUT_FILTERS_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
ngx_int_t ngx_http_lua_read_bytes(ngx_buf_t *src, ngx_chain_t *buf_in,
|
||||
size_t *rest, ssize_t bytes, ngx_log_t *log);
|
||||
|
||||
ngx_int_t ngx_http_lua_read_all(ngx_buf_t *src, ngx_chain_t *buf_in,
|
||||
ssize_t bytes, ngx_log_t *log);
|
||||
|
||||
ngx_int_t ngx_http_lua_read_any(ngx_buf_t *src, ngx_chain_t *buf_in,
|
||||
size_t *max, ssize_t bytes, ngx_log_t *log);
|
||||
|
||||
ngx_int_t ngx_http_lua_read_line(ngx_buf_t *src, ngx_chain_t *buf_in,
|
||||
ssize_t bytes, ngx_log_t *log);
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_INPUT_FILTERS_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,17 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_LEX_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_LEX_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
int ngx_http_lua_lex(const u_char *const s, size_t len, int *const ovec);
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,462 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_http_lua_log.h"
|
||||
#include "ngx_http_lua_util.h"
|
||||
#include "ngx_http_lua_log_ringbuf.h"
|
||||
#include "ngx_http_lua_output.h"
|
||||
|
||||
|
||||
static int ngx_http_lua_print(lua_State *L);
|
||||
static int ngx_http_lua_ngx_log(lua_State *L);
|
||||
static int log_wrapper(ngx_log_t *log, const char *ident,
|
||||
ngx_uint_t level, lua_State *L);
|
||||
static void ngx_http_lua_inject_log_consts(lua_State *L);
|
||||
|
||||
|
||||
/**
|
||||
* Wrapper of nginx log functionality. Take a log level param and varargs of
|
||||
* log message params.
|
||||
*
|
||||
* @param L Lua state pointer
|
||||
* @retval always 0 (don't return values to Lua)
|
||||
* */
|
||||
int
|
||||
ngx_http_lua_ngx_log(lua_State *L)
|
||||
{
|
||||
ngx_log_t *log;
|
||||
ngx_http_request_t *r;
|
||||
const char *msg;
|
||||
int level;
|
||||
|
||||
r = ngx_http_lua_get_req(L);
|
||||
|
||||
if (r && r->connection && r->connection->log) {
|
||||
log = r->connection->log;
|
||||
|
||||
} else {
|
||||
log = ngx_cycle->log;
|
||||
}
|
||||
|
||||
level = luaL_checkint(L, 1);
|
||||
if (level < NGX_LOG_STDERR || level > NGX_LOG_DEBUG) {
|
||||
msg = lua_pushfstring(L, "bad log level: %d", level);
|
||||
return luaL_argerror(L, 1, msg);
|
||||
}
|
||||
|
||||
/* remove log-level param from stack */
|
||||
lua_remove(L, 1);
|
||||
|
||||
return log_wrapper(log, "[lua] ", (ngx_uint_t) level, L);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Override Lua print function, output message to nginx error logs. Equal to
|
||||
* ngx.log(ngx.NOTICE, ...).
|
||||
*
|
||||
* @param L Lua state pointer
|
||||
* @retval always 0 (don't return values to Lua)
|
||||
* */
|
||||
int
|
||||
ngx_http_lua_print(lua_State *L)
|
||||
{
|
||||
ngx_log_t *log;
|
||||
ngx_http_request_t *r;
|
||||
|
||||
r = ngx_http_lua_get_req(L);
|
||||
|
||||
if (r && r->connection && r->connection->log) {
|
||||
log = r->connection->log;
|
||||
|
||||
} else {
|
||||
log = ngx_cycle->log;
|
||||
}
|
||||
|
||||
return log_wrapper(log, "[lua] ", NGX_LOG_NOTICE, L);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
log_wrapper(ngx_log_t *log, const char *ident, ngx_uint_t level,
|
||||
lua_State *L)
|
||||
{
|
||||
u_char *buf;
|
||||
u_char *p, *q;
|
||||
ngx_str_t name;
|
||||
int nargs, i;
|
||||
size_t size, len;
|
||||
size_t src_len = 0;
|
||||
int type;
|
||||
const char *msg;
|
||||
lua_Debug ar;
|
||||
|
||||
if (level > log->log_level) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 1
|
||||
/* add debug info */
|
||||
|
||||
lua_getstack(L, 1, &ar);
|
||||
lua_getinfo(L, "Snl", &ar);
|
||||
|
||||
/* get the basename of the Lua source file path, stored in q */
|
||||
name.data = (u_char *) ar.short_src;
|
||||
if (name.data == NULL) {
|
||||
name.len = 0;
|
||||
|
||||
} else {
|
||||
p = name.data;
|
||||
while (*p != '\0') {
|
||||
if (*p == '/' || *p == '\\') {
|
||||
name.data = p + 1;
|
||||
}
|
||||
|
||||
p++;
|
||||
}
|
||||
|
||||
name.len = p - name.data;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
nargs = lua_gettop(L);
|
||||
|
||||
size = name.len + NGX_INT_T_LEN + sizeof(":: ") - 1;
|
||||
|
||||
if (*ar.namewhat != '\0' && *ar.what == 'L') {
|
||||
src_len = ngx_strlen(ar.name);
|
||||
size += src_len + sizeof("(): ") - 1;
|
||||
}
|
||||
|
||||
for (i = 1; i <= nargs; i++) {
|
||||
type = lua_type(L, i);
|
||||
switch (type) {
|
||||
case LUA_TNUMBER:
|
||||
size += ngx_http_lua_get_num_len(L, i);
|
||||
break;
|
||||
|
||||
case LUA_TSTRING:
|
||||
lua_tolstring(L, i, &len);
|
||||
size += len;
|
||||
break;
|
||||
|
||||
case LUA_TNIL:
|
||||
size += sizeof("nil") - 1;
|
||||
break;
|
||||
|
||||
case LUA_TBOOLEAN:
|
||||
if (lua_toboolean(L, i)) {
|
||||
size += sizeof("true") - 1;
|
||||
|
||||
} else {
|
||||
size += sizeof("false") - 1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case LUA_TTABLE:
|
||||
if (!luaL_callmeta(L, i, "__tostring")) {
|
||||
return luaL_argerror(L, i, "expected table to have "
|
||||
"__tostring metamethod");
|
||||
}
|
||||
|
||||
lua_tolstring(L, -1, &len);
|
||||
size += len;
|
||||
break;
|
||||
|
||||
case LUA_TLIGHTUSERDATA:
|
||||
if (lua_touserdata(L, i) == NULL) {
|
||||
size += sizeof("null") - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
|
||||
default:
|
||||
msg = lua_pushfstring(L, "string, number, boolean, or nil "
|
||||
"expected, got %s",
|
||||
lua_typename(L, type));
|
||||
return luaL_argerror(L, i, msg);
|
||||
}
|
||||
}
|
||||
|
||||
buf = lua_newuserdata(L, size);
|
||||
|
||||
p = ngx_copy(buf, name.data, name.len);
|
||||
|
||||
*p++ = ':';
|
||||
|
||||
p = ngx_snprintf(p, NGX_INT_T_LEN, "%d",
|
||||
ar.currentline > 0 ? ar.currentline : ar.linedefined);
|
||||
|
||||
*p++ = ':'; *p++ = ' ';
|
||||
|
||||
if (*ar.namewhat != '\0' && *ar.what == 'L') {
|
||||
p = ngx_copy(p, ar.name, src_len);
|
||||
*p++ = '(';
|
||||
*p++ = ')';
|
||||
*p++ = ':';
|
||||
*p++ = ' ';
|
||||
}
|
||||
|
||||
for (i = 1; i <= nargs; i++) {
|
||||
type = lua_type(L, i);
|
||||
switch (type) {
|
||||
case LUA_TNUMBER:
|
||||
p = ngx_http_lua_write_num(L, i, p);
|
||||
break;
|
||||
|
||||
case LUA_TSTRING:
|
||||
q = (u_char *) lua_tolstring(L, i, &len);
|
||||
p = ngx_copy(p, q, len);
|
||||
break;
|
||||
|
||||
case LUA_TNIL:
|
||||
*p++ = 'n';
|
||||
*p++ = 'i';
|
||||
*p++ = 'l';
|
||||
break;
|
||||
|
||||
case LUA_TBOOLEAN:
|
||||
if (lua_toboolean(L, i)) {
|
||||
*p++ = 't';
|
||||
*p++ = 'r';
|
||||
*p++ = 'u';
|
||||
*p++ = 'e';
|
||||
|
||||
} else {
|
||||
*p++ = 'f';
|
||||
*p++ = 'a';
|
||||
*p++ = 'l';
|
||||
*p++ = 's';
|
||||
*p++ = 'e';
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case LUA_TTABLE:
|
||||
luaL_callmeta(L, i, "__tostring");
|
||||
q = (u_char *) lua_tolstring(L, -1, &len);
|
||||
p = ngx_copy(p, q, len);
|
||||
break;
|
||||
|
||||
case LUA_TLIGHTUSERDATA:
|
||||
*p++ = 'n';
|
||||
*p++ = 'u';
|
||||
*p++ = 'l';
|
||||
*p++ = 'l';
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return luaL_error(L, "impossible to reach here");
|
||||
}
|
||||
}
|
||||
|
||||
if (p - buf > (off_t) size) {
|
||||
return luaL_error(L, "buffer error: %d > %d", (int) (p - buf),
|
||||
(int) size);
|
||||
}
|
||||
|
||||
ngx_log_error(level, log, 0, "%s%*s", ident, (size_t) (p - buf), buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_http_lua_inject_log_api(lua_State *L)
|
||||
{
|
||||
ngx_http_lua_inject_log_consts(L);
|
||||
|
||||
lua_pushcfunction(L, ngx_http_lua_ngx_log);
|
||||
lua_setfield(L, -2, "log");
|
||||
|
||||
lua_pushcfunction(L, ngx_http_lua_print);
|
||||
lua_setglobal(L, "print");
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_http_lua_inject_log_consts(lua_State *L)
|
||||
{
|
||||
/* {{{ nginx log level constants */
|
||||
lua_pushinteger(L, NGX_LOG_STDERR);
|
||||
lua_setfield(L, -2, "STDERR");
|
||||
|
||||
lua_pushinteger(L, NGX_LOG_EMERG);
|
||||
lua_setfield(L, -2, "EMERG");
|
||||
|
||||
lua_pushinteger(L, NGX_LOG_ALERT);
|
||||
lua_setfield(L, -2, "ALERT");
|
||||
|
||||
lua_pushinteger(L, NGX_LOG_CRIT);
|
||||
lua_setfield(L, -2, "CRIT");
|
||||
|
||||
lua_pushinteger(L, NGX_LOG_ERR);
|
||||
lua_setfield(L, -2, "ERR");
|
||||
|
||||
lua_pushinteger(L, NGX_LOG_WARN);
|
||||
lua_setfield(L, -2, "WARN");
|
||||
|
||||
lua_pushinteger(L, NGX_LOG_NOTICE);
|
||||
lua_setfield(L, -2, "NOTICE");
|
||||
|
||||
lua_pushinteger(L, NGX_LOG_INFO);
|
||||
lua_setfield(L, -2, "INFO");
|
||||
|
||||
lua_pushinteger(L, NGX_LOG_DEBUG);
|
||||
lua_setfield(L, -2, "DEBUG");
|
||||
/* }}} */
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_INTERCEPT_ERROR_LOG_PATCH
|
||||
ngx_int_t
|
||||
ngx_http_lua_capture_log_handler(ngx_log_t *log,
|
||||
ngx_uint_t level, u_char *buf, size_t n)
|
||||
{
|
||||
ngx_http_lua_log_ringbuf_t *ringbuf;
|
||||
|
||||
dd("enter");
|
||||
|
||||
ringbuf = (ngx_http_lua_log_ringbuf_t *)
|
||||
ngx_cycle->intercept_error_log_data;
|
||||
|
||||
if (level > ringbuf->filter_level) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_http_lua_log_ringbuf_write(ringbuf, level, buf, n);
|
||||
|
||||
dd("capture log: %s\n", buf);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_errlog_set_filter_level(int level, u_char *err, size_t *errlen)
|
||||
{
|
||||
#ifdef HAVE_INTERCEPT_ERROR_LOG_PATCH
|
||||
ngx_http_lua_log_ringbuf_t *ringbuf;
|
||||
|
||||
ringbuf = ngx_cycle->intercept_error_log_data;
|
||||
|
||||
if (ringbuf == NULL) {
|
||||
*errlen = ngx_snprintf(err, *errlen,
|
||||
"directive \"lua_capture_error_log\" is not set")
|
||||
- err;
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (level > NGX_LOG_DEBUG || level < NGX_LOG_STDERR) {
|
||||
*errlen = ngx_snprintf(err, *errlen, "bad log level: %d", level)
|
||||
- err;
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ringbuf->filter_level = level;
|
||||
return NGX_OK;
|
||||
#else
|
||||
*errlen = ngx_snprintf(err, *errlen,
|
||||
"missing the capture error log patch for nginx")
|
||||
- err;
|
||||
return NGX_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_errlog_get_msg(char **log, int *loglevel, u_char *err,
|
||||
size_t *errlen, double *log_time)
|
||||
{
|
||||
#ifdef HAVE_INTERCEPT_ERROR_LOG_PATCH
|
||||
ngx_uint_t loglen;
|
||||
|
||||
ngx_http_lua_log_ringbuf_t *ringbuf;
|
||||
|
||||
ringbuf = ngx_cycle->intercept_error_log_data;
|
||||
|
||||
if (ringbuf == NULL) {
|
||||
*errlen = ngx_snprintf(err, *errlen,
|
||||
"directive \"lua_capture_error_log\" is not set")
|
||||
- err;
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ringbuf->count == 0) {
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
ngx_http_lua_log_ringbuf_read(ringbuf, loglevel, (void **) log, &loglen,
|
||||
log_time);
|
||||
return loglen;
|
||||
#else
|
||||
*errlen = ngx_snprintf(err, *errlen,
|
||||
"missing the capture error log patch for nginx")
|
||||
- err;
|
||||
return NGX_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_errlog_get_sys_filter_level(ngx_http_request_t *r)
|
||||
{
|
||||
ngx_log_t *log;
|
||||
int log_level;
|
||||
|
||||
if (r && r->connection && r->connection->log) {
|
||||
log = r->connection->log;
|
||||
|
||||
} else {
|
||||
log = ngx_cycle->log;
|
||||
}
|
||||
|
||||
log_level = log->log_level;
|
||||
if (log_level == NGX_LOG_DEBUG_ALL) {
|
||||
log_level = NGX_LOG_DEBUG;
|
||||
}
|
||||
|
||||
return log_level;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_raw_log(ngx_http_request_t *r, int level, u_char *s,
|
||||
size_t s_len)
|
||||
{
|
||||
ngx_log_t *log;
|
||||
|
||||
if (level > NGX_LOG_DEBUG || level < NGX_LOG_STDERR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (r && r->connection && r->connection->log) {
|
||||
log = r->connection->log;
|
||||
|
||||
} else {
|
||||
log = ngx_cycle->log;
|
||||
}
|
||||
|
||||
ngx_log_error((unsigned) level, log, 0, "%*s", s_len, s);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,24 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_LOG_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_LOG_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
void ngx_http_lua_inject_log_api(lua_State *L);
|
||||
#ifdef HAVE_INTERCEPT_ERROR_LOG_PATCH
|
||||
ngx_int_t ngx_http_lua_capture_log_handler(ngx_log_t *log,
|
||||
ngx_uint_t level, u_char *buf, size_t n);
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_LOG_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,228 @@
|
|||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
#include "ngx_http_lua_log_ringbuf.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
double time;
|
||||
unsigned len;
|
||||
unsigned log_level;
|
||||
} ngx_http_lua_log_ringbuf_header_t;
|
||||
|
||||
|
||||
enum {
|
||||
HEADER_LEN = sizeof(ngx_http_lua_log_ringbuf_header_t),
|
||||
};
|
||||
|
||||
|
||||
static void *ngx_http_lua_log_ringbuf_next_header(
|
||||
ngx_http_lua_log_ringbuf_t *rb);
|
||||
static void ngx_http_lua_log_ringbuf_append(
|
||||
ngx_http_lua_log_ringbuf_t *rb, int log_level, void *buf, int n);
|
||||
static size_t ngx_http_lua_log_ringbuf_free_spaces(
|
||||
ngx_http_lua_log_ringbuf_t *rb);
|
||||
|
||||
|
||||
void
|
||||
ngx_http_lua_log_ringbuf_init(ngx_http_lua_log_ringbuf_t *rb, void *buf,
|
||||
size_t len)
|
||||
{
|
||||
rb->data = buf;
|
||||
rb->size = len;
|
||||
|
||||
rb->tail = rb->data;
|
||||
rb->head = rb->data;
|
||||
rb->sentinel = rb->data + rb->size;
|
||||
rb->count = 0;
|
||||
rb->filter_level = NGX_LOG_DEBUG;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_http_lua_log_ringbuf_reset(ngx_http_lua_log_ringbuf_t *rb)
|
||||
{
|
||||
rb->tail = rb->data;
|
||||
rb->head = rb->data;
|
||||
rb->sentinel = rb->data + rb->size;
|
||||
rb->count = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get the next data header, it'll skip the useless data space or
|
||||
* placehold data
|
||||
*/
|
||||
static void *
|
||||
ngx_http_lua_log_ringbuf_next_header(ngx_http_lua_log_ringbuf_t *rb)
|
||||
{
|
||||
/* useless data */
|
||||
if (rb->size - (rb->head - rb->data) < HEADER_LEN)
|
||||
{
|
||||
return rb->data;
|
||||
}
|
||||
|
||||
/* placehold data */
|
||||
if (rb->head >= rb->sentinel) {
|
||||
return rb->data;
|
||||
}
|
||||
|
||||
return rb->head;
|
||||
}
|
||||
|
||||
|
||||
/* append data to ring buffer directly */
|
||||
static void
|
||||
ngx_http_lua_log_ringbuf_append(ngx_http_lua_log_ringbuf_t *rb,
|
||||
int log_level, void *buf, int n)
|
||||
{
|
||||
ngx_http_lua_log_ringbuf_header_t *head;
|
||||
ngx_time_t *tp;
|
||||
|
||||
head = (ngx_http_lua_log_ringbuf_header_t *) rb->tail;
|
||||
head->len = n;
|
||||
head->log_level = log_level;
|
||||
|
||||
tp = ngx_timeofday();
|
||||
head->time = tp->sec + tp->msec / 1000.0L;
|
||||
|
||||
rb->tail += HEADER_LEN;
|
||||
ngx_memcpy(rb->tail, buf, n);
|
||||
rb->tail += n;
|
||||
rb->count++;
|
||||
|
||||
if (rb->tail > rb->sentinel) {
|
||||
rb->sentinel = rb->tail;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* throw away data at head */
|
||||
static void
|
||||
ngx_http_lua_log_ringbuf_throw_away(ngx_http_lua_log_ringbuf_t *rb)
|
||||
{
|
||||
ngx_http_lua_log_ringbuf_header_t *head;
|
||||
|
||||
if (rb->count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
head = (ngx_http_lua_log_ringbuf_header_t *) rb->head;
|
||||
|
||||
rb->head += HEADER_LEN + head->len;
|
||||
rb->count--;
|
||||
|
||||
if (rb->count == 0) {
|
||||
ngx_http_lua_log_ringbuf_reset(rb);
|
||||
}
|
||||
|
||||
rb->head = ngx_http_lua_log_ringbuf_next_header(rb);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* size of free spaces */
|
||||
static size_t
|
||||
ngx_http_lua_log_ringbuf_free_spaces(ngx_http_lua_log_ringbuf_t *rb)
|
||||
{
|
||||
if (rb->count == 0) {
|
||||
return rb->size;
|
||||
}
|
||||
|
||||
if (rb->tail > rb->head) {
|
||||
return rb->data + rb->size - rb->tail;
|
||||
}
|
||||
|
||||
return rb->head - rb->tail;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* try to write log data to ring buffer, throw away old data
|
||||
* if there was not enough free spaces.
|
||||
*/
|
||||
ngx_int_t
|
||||
ngx_http_lua_log_ringbuf_write(ngx_http_lua_log_ringbuf_t *rb, int log_level,
|
||||
void *buf, size_t n)
|
||||
{
|
||||
if (n + HEADER_LEN > rb->size) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ngx_http_lua_log_ringbuf_free_spaces(rb) < n + HEADER_LEN) {
|
||||
/* if the right space is not enough, mark it as placehold data */
|
||||
if ((size_t)(rb->data + rb->size - rb->tail) < n + HEADER_LEN) {
|
||||
|
||||
while (rb->head >= rb->tail && rb->count) {
|
||||
/* head is after tail, so we will throw away all data between
|
||||
* head and sentinel */
|
||||
ngx_http_lua_log_ringbuf_throw_away(rb);
|
||||
}
|
||||
|
||||
rb->sentinel = rb->tail;
|
||||
rb->tail = rb->data;
|
||||
}
|
||||
|
||||
while (ngx_http_lua_log_ringbuf_free_spaces(rb) < n + HEADER_LEN) {
|
||||
ngx_http_lua_log_ringbuf_throw_away(rb);
|
||||
}
|
||||
}
|
||||
|
||||
ngx_http_lua_log_ringbuf_append(rb, log_level, buf, n);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
/* read log from ring buffer, do reset if all of the logs were readed. */
|
||||
ngx_int_t
|
||||
ngx_http_lua_log_ringbuf_read(ngx_http_lua_log_ringbuf_t *rb, int *log_level,
|
||||
void **buf, size_t *n, double *log_time)
|
||||
{
|
||||
ngx_http_lua_log_ringbuf_header_t *head;
|
||||
|
||||
if (rb->count == 0) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
head = (ngx_http_lua_log_ringbuf_header_t *) rb->head;
|
||||
|
||||
if (rb->head >= rb->sentinel) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
*log_level = head->log_level;
|
||||
*n = head->len;
|
||||
rb->head += HEADER_LEN;
|
||||
*buf = rb->head;
|
||||
rb->head += head->len;
|
||||
|
||||
if (log_time) {
|
||||
*log_time = head->time;
|
||||
}
|
||||
|
||||
rb->count--;
|
||||
|
||||
if (rb->count == 0) {
|
||||
ngx_http_lua_log_ringbuf_reset(rb);
|
||||
}
|
||||
|
||||
rb->head = ngx_http_lua_log_ringbuf_next_header(rb);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
#ifndef _NGX_HTTP_LUA_RINGBUF_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_RINGBUF_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_uint_t filter_level;
|
||||
char *tail; /* writed point */
|
||||
char *head; /* readed point */
|
||||
char *data; /* buffer */
|
||||
char *sentinel;
|
||||
size_t size; /* buffer total size */
|
||||
size_t count; /* count of logs */
|
||||
} ngx_http_lua_log_ringbuf_t;
|
||||
|
||||
|
||||
void ngx_http_lua_log_ringbuf_init(ngx_http_lua_log_ringbuf_t *rb,
|
||||
void *buf, size_t len);
|
||||
void ngx_http_lua_log_ringbuf_reset(ngx_http_lua_log_ringbuf_t *rb);
|
||||
ngx_int_t ngx_http_lua_log_ringbuf_read(ngx_http_lua_log_ringbuf_t *rb,
|
||||
int *log_level, void **buf, size_t *n, double *log_time);
|
||||
ngx_int_t ngx_http_lua_log_ringbuf_write(ngx_http_lua_log_ringbuf_t *rb,
|
||||
int log_level, void *buf, size_t n);
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_RINGBUF_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,268 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_http_lua_directive.h"
|
||||
#include "ngx_http_lua_logby.h"
|
||||
#include "ngx_http_lua_exception.h"
|
||||
#include "ngx_http_lua_util.h"
|
||||
#include "ngx_http_lua_pcrefix.h"
|
||||
#include "ngx_http_lua_log.h"
|
||||
#include "ngx_http_lua_cache.h"
|
||||
#include "ngx_http_lua_headers.h"
|
||||
#include "ngx_http_lua_string.h"
|
||||
#include "ngx_http_lua_misc.h"
|
||||
#include "ngx_http_lua_consts.h"
|
||||
#include "ngx_http_lua_shdict.h"
|
||||
#if (NGX_HTTP_LUA_HAVE_MALLOC_TRIM)
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
|
||||
static ngx_int_t ngx_http_lua_log_by_chunk(lua_State *L, ngx_http_request_t *r);
|
||||
|
||||
|
||||
static void
|
||||
ngx_http_lua_log_by_lua_env(lua_State *L, ngx_http_request_t *r)
|
||||
{
|
||||
ngx_http_lua_set_req(L, r);
|
||||
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
/**
|
||||
* we want to create empty environment for current script
|
||||
*
|
||||
* newt = {}
|
||||
* newt["_G"] = newt
|
||||
* setmetatable(newt, {__index = _G})
|
||||
*
|
||||
* if a function or symbol is not defined in our env, __index will lookup
|
||||
* in the global env.
|
||||
*
|
||||
* all variables created in the script-env will be thrown away at the end
|
||||
* of the script run.
|
||||
* */
|
||||
ngx_http_lua_create_new_globals_table(L, 0 /* narr */, 1 /* nrec */);
|
||||
|
||||
/* {{{ make new env inheriting main thread's globals table */
|
||||
lua_createtable(L, 0, 1); /* the metatable for the new env */
|
||||
ngx_http_lua_get_globals_table(L);
|
||||
lua_setfield(L, -2, "__index");
|
||||
lua_setmetatable(L, -2); /* setmetatable({}, {__index = _G}) */
|
||||
/* }}} */
|
||||
|
||||
lua_setfenv(L, -2); /* set new running env for the code closure */
|
||||
#endif /* OPENRESTY_LUAJIT */
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_log_handler(ngx_http_request_t *r)
|
||||
{
|
||||
#if (NGX_HTTP_LUA_HAVE_MALLOC_TRIM)
|
||||
ngx_uint_t trim_cycle, trim_nreq;
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
#if (NGX_DEBUG)
|
||||
ngx_int_t trim_ret;
|
||||
#endif
|
||||
#endif
|
||||
ngx_http_lua_loc_conf_t *llcf;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
|
||||
#if (NGX_HTTP_LUA_HAVE_MALLOC_TRIM)
|
||||
lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
|
||||
|
||||
trim_cycle = lmcf->malloc_trim_cycle;
|
||||
|
||||
if (trim_cycle > 0) {
|
||||
|
||||
dd("cycle: %d", (int) trim_cycle);
|
||||
|
||||
trim_nreq = ++lmcf->malloc_trim_req_count;
|
||||
|
||||
if (trim_nreq >= trim_cycle) {
|
||||
lmcf->malloc_trim_req_count = 0;
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
trim_ret = malloc_trim(1);
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"malloc_trim(1) returned %d", trim_ret);
|
||||
#else
|
||||
(void) malloc_trim(1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
# if (NGX_DEBUG)
|
||||
else {
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"malloc_trim() disabled");
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua log handler, uri:\"%V\" c:%ud", &r->uri,
|
||||
r->main->count);
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
|
||||
if (llcf->log_handler == NULL) {
|
||||
dd("no log handler found");
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
|
||||
dd("ctx = %p", ctx);
|
||||
|
||||
if (ctx == NULL) {
|
||||
ctx = ngx_http_lua_create_ctx(r);
|
||||
if (ctx == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->context = NGX_HTTP_LUA_CONTEXT_LOG;
|
||||
|
||||
dd("calling log handler");
|
||||
return llcf->log_handler(r);
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_log_handler_inline(ngx_http_request_t *r)
|
||||
{
|
||||
lua_State *L;
|
||||
ngx_int_t rc;
|
||||
ngx_http_lua_loc_conf_t *llcf;
|
||||
|
||||
dd("log by lua inline");
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
|
||||
L = ngx_http_lua_get_lua_vm(r, NULL);
|
||||
|
||||
/* load Lua inline script (w/ cache) sp = 1 */
|
||||
rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L,
|
||||
llcf->log_src.value.data,
|
||||
llcf->log_src.value.len,
|
||||
&llcf->log_src_ref,
|
||||
llcf->log_src_key,
|
||||
(const char *) llcf->log_chunkname);
|
||||
if (rc != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return ngx_http_lua_log_by_chunk(L, r);
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_log_handler_file(ngx_http_request_t *r)
|
||||
{
|
||||
lua_State *L;
|
||||
ngx_int_t rc;
|
||||
u_char *script_path;
|
||||
ngx_http_lua_loc_conf_t *llcf;
|
||||
ngx_str_t eval_src;
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
|
||||
if (ngx_http_complex_value(r, &llcf->log_src, &eval_src) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
script_path = ngx_http_lua_rebase_path(r->pool, eval_src.data,
|
||||
eval_src.len);
|
||||
|
||||
if (script_path == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
L = ngx_http_lua_get_lua_vm(r, NULL);
|
||||
|
||||
/* load Lua script file (w/ cache) sp = 1 */
|
||||
rc = ngx_http_lua_cache_loadfile(r->connection->log, L, script_path,
|
||||
&llcf->log_src_ref,
|
||||
llcf->log_src_key);
|
||||
if (rc != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return ngx_http_lua_log_by_chunk(L, r);
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_log_by_chunk(lua_State *L, ngx_http_request_t *r)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
u_char *err_msg;
|
||||
size_t len;
|
||||
#if (NGX_PCRE)
|
||||
ngx_pool_t *old_pool;
|
||||
#endif
|
||||
|
||||
/* set Lua VM panic handler */
|
||||
lua_atpanic(L, ngx_http_lua_atpanic);
|
||||
|
||||
NGX_LUA_EXCEPTION_TRY {
|
||||
|
||||
/* initialize nginx context in Lua VM, code chunk at stack top sp = 1 */
|
||||
ngx_http_lua_log_by_lua_env(L, r);
|
||||
|
||||
#if (NGX_PCRE)
|
||||
/* XXX: work-around to nginx regex subsystem */
|
||||
old_pool = ngx_http_lua_pcre_malloc_init(r->pool);
|
||||
#endif
|
||||
|
||||
lua_pushcfunction(L, ngx_http_lua_traceback);
|
||||
lua_insert(L, 1); /* put it under chunk and args */
|
||||
|
||||
/* protected call user code */
|
||||
rc = lua_pcall(L, 0, 1, 1);
|
||||
|
||||
lua_remove(L, 1); /* remove traceback function */
|
||||
|
||||
#if (NGX_PCRE)
|
||||
/* XXX: work-around to nginx regex subsystem */
|
||||
ngx_http_lua_pcre_malloc_done(old_pool);
|
||||
#endif
|
||||
|
||||
if (rc != 0) {
|
||||
/* error occurred when running loaded code */
|
||||
err_msg = (u_char *) lua_tolstring(L, -1, &len);
|
||||
|
||||
if (err_msg == NULL) {
|
||||
err_msg = (u_char *) "unknown reason";
|
||||
len = sizeof("unknown reason") - 1;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"failed to run log_by_lua*: %*s", len, err_msg);
|
||||
|
||||
lua_settop(L, 0); /* clear remaining elems on stack */
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
} NGX_LUA_EXCEPTION_CATCH {
|
||||
|
||||
dd("nginx execution restored");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
/* clear Lua stack */
|
||||
lua_settop(L, 0);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_LOGBY_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_LOGBY_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
ngx_int_t ngx_http_lua_log_handler(ngx_http_request_t *r);
|
||||
ngx_int_t ngx_http_lua_log_handler_inline(ngx_http_request_t *r);
|
||||
ngx_int_t ngx_http_lua_log_handler_file(ngx_http_request_t *r);
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_LOGBY_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,169 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_http_lua_misc.h"
|
||||
#include "ngx_http_lua_util.h"
|
||||
|
||||
|
||||
static int ngx_http_lua_ngx_req_is_internal(lua_State *L);
|
||||
|
||||
|
||||
void
|
||||
ngx_http_lua_inject_req_misc_api(lua_State *L)
|
||||
{
|
||||
lua_pushcfunction(L, ngx_http_lua_ngx_req_is_internal);
|
||||
lua_setfield(L, -2, "is_internal");
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_http_lua_ngx_req_is_internal(lua_State *L)
|
||||
{
|
||||
ngx_http_request_t *r;
|
||||
|
||||
r = ngx_http_lua_get_req(L);
|
||||
if (r == NULL) {
|
||||
return luaL_error(L, "no request object found");
|
||||
}
|
||||
|
||||
lua_pushboolean(L, r->internal == 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_get_resp_status(ngx_http_request_t *r)
|
||||
{
|
||||
if (r->connection->fd == (ngx_socket_t) -1) {
|
||||
return NGX_HTTP_LUA_FFI_BAD_CONTEXT;
|
||||
}
|
||||
|
||||
if (r->err_status) {
|
||||
return r->err_status;
|
||||
|
||||
} else if (r->headers_out.status) {
|
||||
return r->headers_out.status;
|
||||
|
||||
} else if (r->http_version == NGX_HTTP_VERSION_9) {
|
||||
return 9;
|
||||
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_set_resp_status(ngx_http_request_t *r, int status)
|
||||
{
|
||||
if (r->connection->fd == (ngx_socket_t) -1) {
|
||||
return NGX_HTTP_LUA_FFI_BAD_CONTEXT;
|
||||
}
|
||||
|
||||
if (r->header_sent) {
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"attempt to set ngx.status after sending out "
|
||||
"response headers");
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
r->headers_out.status = status;
|
||||
|
||||
if (r->err_status) {
|
||||
r->err_status = 0;
|
||||
}
|
||||
|
||||
if (status == 101) {
|
||||
/*
|
||||
* XXX work-around a bug in the Nginx core older than 1.5.5
|
||||
* that 101 does not have a default status line
|
||||
*/
|
||||
|
||||
ngx_str_set(&r->headers_out.status_line, "101 Switching Protocols");
|
||||
|
||||
} else {
|
||||
r->headers_out.status_line.len = 0;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_req_is_internal(ngx_http_request_t *r)
|
||||
{
|
||||
if (r->connection->fd == (ngx_socket_t) -1) {
|
||||
return NGX_HTTP_LUA_FFI_BAD_CONTEXT;
|
||||
}
|
||||
|
||||
return r->internal;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_is_subrequest(ngx_http_request_t *r)
|
||||
{
|
||||
if (r->connection->fd == (ngx_socket_t) -1) {
|
||||
return NGX_HTTP_LUA_FFI_BAD_CONTEXT;
|
||||
}
|
||||
|
||||
return r != r->main;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_headers_sent(ngx_http_request_t *r)
|
||||
{
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return NGX_HTTP_LUA_FFI_NO_REQ_CTX;
|
||||
}
|
||||
|
||||
if (r->connection->fd == (ngx_socket_t) -1) {
|
||||
return NGX_HTTP_LUA_FFI_BAD_CONTEXT;
|
||||
}
|
||||
|
||||
return r->header_sent ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_get_conf_env(u_char *name, u_char **env_buf, size_t *name_len)
|
||||
{
|
||||
ngx_uint_t i;
|
||||
ngx_str_t *var;
|
||||
ngx_core_conf_t *ccf;
|
||||
|
||||
ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
|
||||
ngx_core_module);
|
||||
|
||||
var = ccf->env.elts;
|
||||
|
||||
for (i = 0; i < ccf->env.nelts; i++) {
|
||||
if (var[i].data[var[i].len] == '='
|
||||
&& ngx_strncmp(name, var[i].data, var[i].len) == 0)
|
||||
{
|
||||
*env_buf = var[i].data;
|
||||
*name_len = var[i].len;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_MISC_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_MISC_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
void ngx_http_lua_inject_req_misc_api(lua_State *L);
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_MISC_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,134 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_http_lua_ndk.h"
|
||||
#include "ngx_http_lua_util.h"
|
||||
|
||||
|
||||
#if defined(NDK) && NDK
|
||||
|
||||
|
||||
static ndk_set_var_value_pt ngx_http_lookup_ndk_set_var_directive(u_char *name,
|
||||
size_t name_len);
|
||||
|
||||
|
||||
void
|
||||
ngx_http_lua_inject_ndk_api(lua_State *L)
|
||||
{
|
||||
lua_createtable(L, 0, 1 /* nrec */); /* ndk.* */
|
||||
|
||||
lua_getglobal(L, "package"); /* ndk package */
|
||||
lua_getfield(L, -1, "loaded"); /* ndk package loaded */
|
||||
lua_pushvalue(L, -3); /* ndk package loaded ndk */
|
||||
lua_setfield(L, -2, "ndk"); /* ndk package loaded */
|
||||
lua_pop(L, 2);
|
||||
|
||||
lua_setglobal(L, "ndk");
|
||||
}
|
||||
|
||||
|
||||
static ndk_set_var_value_pt
|
||||
ngx_http_lookup_ndk_set_var_directive(u_char *name,
|
||||
size_t name_len)
|
||||
{
|
||||
ndk_set_var_t *filter;
|
||||
ngx_uint_t i;
|
||||
ngx_module_t *module;
|
||||
ngx_module_t **modules;
|
||||
ngx_command_t *cmd;
|
||||
|
||||
#if (nginx_version >= 1009011)
|
||||
modules = ngx_cycle->modules;
|
||||
#else
|
||||
modules = ngx_modules;
|
||||
#endif
|
||||
|
||||
for (i = 0; modules[i]; i++) {
|
||||
module = modules[i];
|
||||
if (module->type != NGX_HTTP_MODULE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
cmd = modules[i]->commands;
|
||||
if (cmd == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for ( /* void */ ; cmd->name.len; cmd++) {
|
||||
if (cmd->set != ndk_set_var_value) {
|
||||
continue;
|
||||
}
|
||||
|
||||
filter = cmd->post;
|
||||
if (filter == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cmd->name.len != name_len
|
||||
|| ngx_strncmp(cmd->name.data, name, name_len) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return (ndk_set_var_value_pt)(filter->func);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_ndk_lookup_directive(const u_char *var_data,
|
||||
size_t var_len, ndk_set_var_value_pt *func)
|
||||
{
|
||||
*func = ngx_http_lookup_ndk_set_var_directive((u_char *) var_data, var_len);
|
||||
|
||||
if (*func == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_ndk_set_var_get(ngx_http_request_t *r,
|
||||
ndk_set_var_value_pt func, const u_char *arg_data, size_t arg_len,
|
||||
ngx_http_lua_ffi_str_t *value)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
ngx_str_t res;
|
||||
ngx_http_variable_value_t arg;
|
||||
|
||||
ngx_memzero(&arg, sizeof(ngx_http_variable_value_t));
|
||||
arg.valid = 1;
|
||||
|
||||
arg.data = (u_char *) arg_data;
|
||||
arg.len = arg_len;
|
||||
|
||||
rc = func(r, &res, &arg);
|
||||
|
||||
if (rc != NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
value->data = res.data;
|
||||
value->len = res.len;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
#endif /* defined(NDK) && NDK */
|
||||
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_NDK_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_NDK_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
#if defined(NDK) && NDK
|
||||
void ngx_http_lua_inject_ndk_api(lua_State *L);
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_NDK_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,829 @@
|
|||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_http_lua_output.h"
|
||||
#include "ngx_http_lua_util.h"
|
||||
#include "ngx_http_lua_contentby.h"
|
||||
#include <math.h>
|
||||
|
||||
|
||||
static int ngx_http_lua_ngx_say(lua_State *L);
|
||||
static int ngx_http_lua_ngx_print(lua_State *L);
|
||||
static int ngx_http_lua_ngx_flush(lua_State *L);
|
||||
static int ngx_http_lua_ngx_eof(lua_State *L);
|
||||
static int ngx_http_lua_ngx_send_headers(lua_State *L);
|
||||
static int ngx_http_lua_ngx_echo(lua_State *L, unsigned newline);
|
||||
static void ngx_http_lua_flush_cleanup(void *data);
|
||||
|
||||
|
||||
static int
|
||||
ngx_http_lua_ngx_print(lua_State *L)
|
||||
{
|
||||
dd("calling lua print");
|
||||
return ngx_http_lua_ngx_echo(L, 0);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_http_lua_ngx_say(lua_State *L)
|
||||
{
|
||||
dd("calling");
|
||||
return ngx_http_lua_ngx_echo(L, 1);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_http_lua_ngx_echo(lua_State *L, unsigned newline)
|
||||
{
|
||||
ngx_http_request_t *r;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
const char *p;
|
||||
size_t len;
|
||||
size_t size;
|
||||
ngx_buf_t *b;
|
||||
ngx_chain_t *cl;
|
||||
ngx_int_t rc;
|
||||
int i;
|
||||
int nargs;
|
||||
int type;
|
||||
const char *msg;
|
||||
|
||||
r = ngx_http_lua_get_req(L);
|
||||
if (r == NULL) {
|
||||
return luaL_error(L, "no request object found");
|
||||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
|
||||
if (ctx == NULL) {
|
||||
return luaL_error(L, "no request ctx found");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE
|
||||
| NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE
|
||||
| NGX_HTTP_LUA_CONTEXT_ACCESS
|
||||
| NGX_HTTP_LUA_CONTEXT_CONTENT);
|
||||
|
||||
if (ctx->acquired_raw_req_socket) {
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "raw request socket acquired");
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (r->header_only) {
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "header only");
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (ctx->eof) {
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "seen eof");
|
||||
return 2;
|
||||
}
|
||||
|
||||
nargs = lua_gettop(L);
|
||||
size = 0;
|
||||
|
||||
for (i = 1; i <= nargs; i++) {
|
||||
|
||||
type = lua_type(L, i);
|
||||
|
||||
switch (type) {
|
||||
case LUA_TNUMBER:
|
||||
size += ngx_http_lua_get_num_len(L, i);
|
||||
break;
|
||||
|
||||
case LUA_TSTRING:
|
||||
|
||||
lua_tolstring(L, i, &len);
|
||||
size += len;
|
||||
break;
|
||||
|
||||
case LUA_TNIL:
|
||||
|
||||
size += sizeof("nil") - 1;
|
||||
break;
|
||||
|
||||
case LUA_TBOOLEAN:
|
||||
|
||||
if (lua_toboolean(L, i)) {
|
||||
size += sizeof("true") - 1;
|
||||
|
||||
} else {
|
||||
size += sizeof("false") - 1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case LUA_TTABLE:
|
||||
|
||||
size += ngx_http_lua_calc_strlen_in_table(L, i, i,
|
||||
0 /* strict */);
|
||||
break;
|
||||
|
||||
case LUA_TLIGHTUSERDATA:
|
||||
|
||||
dd("userdata: %p", lua_touserdata(L, i));
|
||||
|
||||
if (lua_touserdata(L, i) == NULL) {
|
||||
size += sizeof("null") - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
|
||||
default:
|
||||
|
||||
msg = lua_pushfstring(L, "string, number, boolean, nil, "
|
||||
"ngx.null, or array table expected, "
|
||||
"but got %s", lua_typename(L, type));
|
||||
|
||||
return luaL_argerror(L, i, msg);
|
||||
}
|
||||
}
|
||||
|
||||
if (newline) {
|
||||
size += sizeof("\n") - 1;
|
||||
}
|
||||
|
||||
if (size == 0) {
|
||||
rc = ngx_http_lua_send_header_if_needed(r, ctx);
|
||||
if (rc == NGX_ERROR || rc > NGX_OK) {
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "nginx output filter error");
|
||||
return 2;
|
||||
}
|
||||
|
||||
lua_pushinteger(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ctx->seen_body_data = 1;
|
||||
|
||||
cl = ngx_http_lua_chain_get_free_buf(r->connection->log, r->pool,
|
||||
&ctx->free_bufs, size);
|
||||
|
||||
if (cl == NULL) {
|
||||
return luaL_error(L, "no memory");
|
||||
}
|
||||
|
||||
b = cl->buf;
|
||||
|
||||
for (i = 1; i <= nargs; i++) {
|
||||
type = lua_type(L, i);
|
||||
switch (type) {
|
||||
case LUA_TNUMBER:
|
||||
b->last = ngx_http_lua_write_num(L, i, b->last);
|
||||
break;
|
||||
|
||||
case LUA_TSTRING:
|
||||
p = lua_tolstring(L, i, &len);
|
||||
b->last = ngx_copy(b->last, (u_char *) p, len);
|
||||
break;
|
||||
|
||||
case LUA_TNIL:
|
||||
*b->last++ = 'n';
|
||||
*b->last++ = 'i';
|
||||
*b->last++ = 'l';
|
||||
break;
|
||||
|
||||
case LUA_TBOOLEAN:
|
||||
if (lua_toboolean(L, i)) {
|
||||
*b->last++ = 't';
|
||||
*b->last++ = 'r';
|
||||
*b->last++ = 'u';
|
||||
*b->last++ = 'e';
|
||||
|
||||
} else {
|
||||
*b->last++ = 'f';
|
||||
*b->last++ = 'a';
|
||||
*b->last++ = 'l';
|
||||
*b->last++ = 's';
|
||||
*b->last++ = 'e';
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case LUA_TTABLE:
|
||||
b->last = ngx_http_lua_copy_str_in_table(L, i, b->last);
|
||||
break;
|
||||
|
||||
case LUA_TLIGHTUSERDATA:
|
||||
*b->last++ = 'n';
|
||||
*b->last++ = 'u';
|
||||
*b->last++ = 'l';
|
||||
*b->last++ = 'l';
|
||||
break;
|
||||
|
||||
default:
|
||||
return luaL_error(L, "impossible to reach here");
|
||||
}
|
||||
}
|
||||
|
||||
if (newline) {
|
||||
*b->last++ = '\n';
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (b->last != b->end) {
|
||||
return luaL_error(L, "buffer error: %p != %p", b->last, b->end);
|
||||
}
|
||||
#endif
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
newline ? "lua say response" : "lua print response");
|
||||
|
||||
rc = ngx_http_lua_send_chain_link(r, ctx, cl);
|
||||
|
||||
if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "nginx output filter error");
|
||||
return 2;
|
||||
}
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"%s has %sbusy bufs",
|
||||
newline ? "lua say response" : "lua print response",
|
||||
ctx->busy_bufs != NULL ? "" : "no ");
|
||||
|
||||
dd("downstream write: %d, buf len: %d", (int) rc,
|
||||
(int) (b->last - b->pos));
|
||||
|
||||
lua_pushinteger(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
ngx_http_lua_calc_strlen_in_table(lua_State *L, int index, int arg_i,
|
||||
unsigned strict)
|
||||
{
|
||||
double key;
|
||||
int max;
|
||||
int i;
|
||||
int type;
|
||||
size_t size;
|
||||
size_t len;
|
||||
const char *msg;
|
||||
|
||||
if (index < 0) {
|
||||
index = lua_gettop(L) + index + 1;
|
||||
}
|
||||
|
||||
dd("table index: %d", index);
|
||||
|
||||
max = 0;
|
||||
|
||||
lua_pushnil(L); /* stack: table key */
|
||||
while (lua_next(L, index) != 0) { /* stack: table key value */
|
||||
dd("key type: %s", luaL_typename(L, -2));
|
||||
|
||||
if (lua_type(L, -2) == LUA_TNUMBER) {
|
||||
|
||||
key = lua_tonumber(L, -2);
|
||||
|
||||
dd("key value: %d", (int) key);
|
||||
|
||||
if (floor(key) == key && key >= 1) {
|
||||
if (key > max) {
|
||||
max = (int) key;
|
||||
}
|
||||
|
||||
lua_pop(L, 1); /* stack: table key */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* not an array (non positive integer key) */
|
||||
lua_pop(L, 2); /* stack: table */
|
||||
|
||||
luaL_argerror(L, arg_i, "non-array table found");
|
||||
return 0;
|
||||
}
|
||||
|
||||
size = 0;
|
||||
|
||||
for (i = 1; i <= max; i++) {
|
||||
lua_rawgeti(L, index, i); /* stack: table value */
|
||||
type = lua_type(L, -1);
|
||||
|
||||
switch (type) {
|
||||
case LUA_TNUMBER:
|
||||
size += ngx_http_lua_get_num_len(L, -1);
|
||||
break;
|
||||
|
||||
case LUA_TSTRING:
|
||||
lua_tolstring(L, -1, &len);
|
||||
size += len;
|
||||
break;
|
||||
|
||||
case LUA_TNIL:
|
||||
|
||||
if (strict) {
|
||||
goto bad_type;
|
||||
}
|
||||
|
||||
size += sizeof("nil") - 1;
|
||||
break;
|
||||
|
||||
case LUA_TBOOLEAN:
|
||||
|
||||
if (strict) {
|
||||
goto bad_type;
|
||||
}
|
||||
|
||||
if (lua_toboolean(L, -1)) {
|
||||
size += sizeof("true") - 1;
|
||||
|
||||
} else {
|
||||
size += sizeof("false") - 1;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case LUA_TTABLE:
|
||||
|
||||
size += ngx_http_lua_calc_strlen_in_table(L, -1, arg_i, strict);
|
||||
break;
|
||||
|
||||
case LUA_TLIGHTUSERDATA:
|
||||
|
||||
if (strict) {
|
||||
goto bad_type;
|
||||
}
|
||||
|
||||
if (lua_touserdata(L, -1) == NULL) {
|
||||
size += sizeof("null") - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
|
||||
default:
|
||||
|
||||
bad_type:
|
||||
|
||||
msg = lua_pushfstring(L, "bad data type %s found",
|
||||
lua_typename(L, type));
|
||||
return luaL_argerror(L, arg_i, msg);
|
||||
}
|
||||
|
||||
lua_pop(L, 1); /* stack: table */
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
u_char *
|
||||
ngx_http_lua_copy_str_in_table(lua_State *L, int index, u_char *dst)
|
||||
{
|
||||
double key;
|
||||
int max;
|
||||
int i;
|
||||
int type;
|
||||
size_t len;
|
||||
u_char *p;
|
||||
|
||||
if (index < 0) {
|
||||
index = lua_gettop(L) + index + 1;
|
||||
}
|
||||
|
||||
max = 0;
|
||||
|
||||
lua_pushnil(L); /* stack: table key */
|
||||
while (lua_next(L, index) != 0) { /* stack: table key value */
|
||||
key = lua_tonumber(L, -2);
|
||||
if (key > max) {
|
||||
max = (int) key;
|
||||
}
|
||||
|
||||
lua_pop(L, 1); /* stack: table key */
|
||||
}
|
||||
|
||||
for (i = 1; i <= max; i++) {
|
||||
lua_rawgeti(L, index, i); /* stack: table value */
|
||||
type = lua_type(L, -1);
|
||||
switch (type) {
|
||||
case LUA_TNUMBER:
|
||||
dst = ngx_http_lua_write_num(L, -1, dst);
|
||||
break;
|
||||
|
||||
case LUA_TSTRING:
|
||||
p = (u_char *) lua_tolstring(L, -1, &len);
|
||||
dst = ngx_copy(dst, p, len);
|
||||
break;
|
||||
|
||||
case LUA_TNIL:
|
||||
*dst++ = 'n';
|
||||
*dst++ = 'i';
|
||||
*dst++ = 'l';
|
||||
break;
|
||||
|
||||
case LUA_TBOOLEAN:
|
||||
if (lua_toboolean(L, -1)) {
|
||||
*dst++ = 't';
|
||||
*dst++ = 'r';
|
||||
*dst++ = 'u';
|
||||
*dst++ = 'e';
|
||||
|
||||
} else {
|
||||
*dst++ = 'f';
|
||||
*dst++ = 'a';
|
||||
*dst++ = 'l';
|
||||
*dst++ = 's';
|
||||
*dst++ = 'e';
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case LUA_TTABLE:
|
||||
dst = ngx_http_lua_copy_str_in_table(L, -1, dst);
|
||||
break;
|
||||
|
||||
case LUA_TLIGHTUSERDATA:
|
||||
|
||||
*dst++ = 'n';
|
||||
*dst++ = 'u';
|
||||
*dst++ = 'l';
|
||||
*dst++ = 'l';
|
||||
break;
|
||||
|
||||
default:
|
||||
luaL_error(L, "impossible to reach here");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lua_pop(L, 1); /* stack: table */
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Force flush out response content
|
||||
* */
|
||||
static int
|
||||
ngx_http_lua_ngx_flush(lua_State *L)
|
||||
{
|
||||
ngx_http_request_t *r;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_chain_t *cl;
|
||||
ngx_int_t rc;
|
||||
int n;
|
||||
unsigned wait = 0;
|
||||
ngx_event_t *wev;
|
||||
ngx_http_core_loc_conf_t *clcf;
|
||||
ngx_http_lua_co_ctx_t *coctx;
|
||||
|
||||
n = lua_gettop(L);
|
||||
if (n > 1) {
|
||||
return luaL_error(L, "attempt to pass %d arguments, but accepted 0 "
|
||||
"or 1", n);
|
||||
}
|
||||
|
||||
r = ngx_http_lua_get_req(L);
|
||||
|
||||
if (n == 1 && r == r->main) {
|
||||
luaL_checktype(L, 1, LUA_TBOOLEAN);
|
||||
wait = lua_toboolean(L, 1);
|
||||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return luaL_error(L, "no request ctx found");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE
|
||||
| NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE
|
||||
| NGX_HTTP_LUA_CONTEXT_ACCESS
|
||||
| NGX_HTTP_LUA_CONTEXT_CONTENT);
|
||||
|
||||
if (ctx->acquired_raw_req_socket) {
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "raw request socket acquired");
|
||||
return 2;
|
||||
}
|
||||
|
||||
coctx = ctx->cur_co_ctx;
|
||||
if (coctx == NULL) {
|
||||
return luaL_error(L, "no co ctx found");
|
||||
}
|
||||
|
||||
if (r->header_only) {
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "header only");
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (ctx->eof) {
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "seen eof");
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (ctx->buffering) {
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua http 1.0 buffering makes ngx.flush() a no-op");
|
||||
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "buffering");
|
||||
return 2;
|
||||
}
|
||||
|
||||
#if 1
|
||||
if ((!r->header_sent && !ctx->header_sent)
|
||||
|| (!ctx->seen_body_data && !wait))
|
||||
{
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "nothing to flush");
|
||||
return 2;
|
||||
}
|
||||
#endif
|
||||
|
||||
cl = ngx_http_lua_get_flush_chain(r, ctx);
|
||||
if (cl == NULL) {
|
||||
return luaL_error(L, "no memory");
|
||||
}
|
||||
|
||||
rc = ngx_http_lua_send_chain_link(r, ctx, cl);
|
||||
|
||||
dd("send chain: %d", (int) rc);
|
||||
|
||||
if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "nginx output filter error");
|
||||
return 2;
|
||||
}
|
||||
|
||||
dd("wait:%d, rc:%d, buffered:0x%x", wait, (int) rc,
|
||||
r->connection->buffered);
|
||||
|
||||
wev = r->connection->write;
|
||||
|
||||
if (wait && (r->connection->buffered
|
||||
& (NGX_HTTP_LOWLEVEL_BUFFERED | NGX_LOWLEVEL_BUFFERED)
|
||||
|| wev->delayed))
|
||||
{
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua flush requires waiting: buffered 0x%uxd, "
|
||||
"delayed:%d", (unsigned) r->connection->buffered,
|
||||
wev->delayed);
|
||||
|
||||
coctx->flushing = 1;
|
||||
ctx->flushing_coros++;
|
||||
|
||||
if (ctx->entered_content_phase) {
|
||||
/* mimic ngx_http_set_write_handler */
|
||||
r->write_event_handler = ngx_http_lua_content_wev_handler;
|
||||
|
||||
} else {
|
||||
r->write_event_handler = ngx_http_core_run_phases;
|
||||
}
|
||||
|
||||
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
|
||||
|
||||
if (!wev->delayed) {
|
||||
ngx_add_timer(wev, clcf->send_timeout);
|
||||
}
|
||||
|
||||
if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) {
|
||||
if (wev->timer_set) {
|
||||
wev->delayed = 0;
|
||||
ngx_del_timer(wev);
|
||||
}
|
||||
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "connection broken");
|
||||
return 2;
|
||||
}
|
||||
|
||||
ngx_http_lua_cleanup_pending_operation(ctx->cur_co_ctx);
|
||||
coctx->cleanup = ngx_http_lua_flush_cleanup;
|
||||
coctx->data = r;
|
||||
|
||||
return lua_yield(L, 0);
|
||||
}
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua flush asynchronously");
|
||||
|
||||
lua_pushinteger(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send last_buf, terminate output stream
|
||||
* */
|
||||
static int
|
||||
ngx_http_lua_ngx_eof(lua_State *L)
|
||||
{
|
||||
ngx_http_request_t *r;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_int_t rc;
|
||||
|
||||
r = ngx_http_lua_get_req(L);
|
||||
if (r == NULL) {
|
||||
return luaL_error(L, "no request object found");
|
||||
}
|
||||
|
||||
if (lua_gettop(L) != 0) {
|
||||
return luaL_error(L, "no argument is expected");
|
||||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return luaL_error(L, "no ctx found");
|
||||
}
|
||||
|
||||
if (ctx->acquired_raw_req_socket) {
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "raw request socket acquired");
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (ctx->eof) {
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "seen eof");
|
||||
return 2;
|
||||
}
|
||||
|
||||
ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE
|
||||
| NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE
|
||||
| NGX_HTTP_LUA_CONTEXT_ACCESS
|
||||
| NGX_HTTP_LUA_CONTEXT_CONTENT);
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua send eof");
|
||||
|
||||
rc = ngx_http_lua_send_chain_link(r, ctx, NULL /* indicate last_buf */);
|
||||
|
||||
dd("send chain: %d", (int) rc);
|
||||
|
||||
if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "nginx output filter error");
|
||||
return 2;
|
||||
}
|
||||
|
||||
lua_pushinteger(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_http_lua_inject_output_api(lua_State *L)
|
||||
{
|
||||
lua_pushcfunction(L, ngx_http_lua_ngx_send_headers);
|
||||
lua_setfield(L, -2, "send_headers");
|
||||
|
||||
lua_pushcfunction(L, ngx_http_lua_ngx_print);
|
||||
lua_setfield(L, -2, "print");
|
||||
|
||||
lua_pushcfunction(L, ngx_http_lua_ngx_say);
|
||||
lua_setfield(L, -2, "say");
|
||||
|
||||
lua_pushcfunction(L, ngx_http_lua_ngx_flush);
|
||||
lua_setfield(L, -2, "flush");
|
||||
|
||||
lua_pushcfunction(L, ngx_http_lua_ngx_eof);
|
||||
lua_setfield(L, -2, "eof");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send out headers
|
||||
* */
|
||||
static int
|
||||
ngx_http_lua_ngx_send_headers(lua_State *L)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
ngx_http_request_t *r;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
|
||||
r = ngx_http_lua_get_req(L);
|
||||
if (r == NULL) {
|
||||
return luaL_error(L, "no request found");
|
||||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return luaL_error(L, "no ctx found");
|
||||
}
|
||||
|
||||
ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE
|
||||
| NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE
|
||||
| NGX_HTTP_LUA_CONTEXT_ACCESS
|
||||
| NGX_HTTP_LUA_CONTEXT_CONTENT);
|
||||
|
||||
if (!r->header_sent && !ctx->header_sent) {
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua send headers");
|
||||
|
||||
rc = ngx_http_lua_send_header_if_needed(r, ctx);
|
||||
if (rc == NGX_ERROR || rc > NGX_OK) {
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "nginx output filter error");
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
lua_pushinteger(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_flush_resume_helper(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx)
|
||||
{
|
||||
int n;
|
||||
lua_State *vm;
|
||||
ngx_int_t rc;
|
||||
ngx_uint_t nreqs;
|
||||
ngx_connection_t *c;
|
||||
|
||||
c = r->connection;
|
||||
|
||||
ctx->cur_co_ctx->cleanup = NULL;
|
||||
|
||||
/* push the return values */
|
||||
|
||||
if (c->timedout) {
|
||||
lua_pushnil(ctx->cur_co_ctx->co);
|
||||
lua_pushliteral(ctx->cur_co_ctx->co, "timeout");
|
||||
n = 2;
|
||||
|
||||
} else if (c->error) {
|
||||
lua_pushnil(ctx->cur_co_ctx->co);
|
||||
lua_pushliteral(ctx->cur_co_ctx->co, "client aborted");
|
||||
n = 2;
|
||||
|
||||
} else {
|
||||
lua_pushinteger(ctx->cur_co_ctx->co, 1);
|
||||
n = 1;
|
||||
}
|
||||
|
||||
vm = ngx_http_lua_get_lua_vm(r, ctx);
|
||||
nreqs = c->requests;
|
||||
|
||||
rc = ngx_http_lua_run_thread(vm, r, ctx, n);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua run thread returned %d", rc);
|
||||
|
||||
if (rc == NGX_AGAIN) {
|
||||
return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs);
|
||||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
ngx_http_lua_finalize_request(r, NGX_DONE);
|
||||
return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs);
|
||||
}
|
||||
|
||||
/* rc == NGX_ERROR || rc >= NGX_OK */
|
||||
|
||||
if (ctx->entered_content_phase) {
|
||||
ngx_http_lua_finalize_request(r, rc);
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_http_lua_flush_cleanup(void *data)
|
||||
{
|
||||
ngx_http_request_t *r;
|
||||
ngx_event_t *wev;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_http_lua_co_ctx_t *coctx = data;
|
||||
|
||||
coctx->flushing = 0;
|
||||
|
||||
r = coctx->data;
|
||||
if (r == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
wev = r->connection->write;
|
||||
|
||||
if (wev && wev->timer_set) {
|
||||
ngx_del_timer(wev);
|
||||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->flushing_coros--;
|
||||
}
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,77 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_OUTPUT_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_OUTPUT_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
void ngx_http_lua_inject_output_api(lua_State *L);
|
||||
|
||||
size_t ngx_http_lua_calc_strlen_in_table(lua_State *L, int index, int arg_i,
|
||||
unsigned strict);
|
||||
|
||||
u_char *ngx_http_lua_copy_str_in_table(lua_State *L, int index, u_char *dst);
|
||||
|
||||
ngx_int_t ngx_http_lua_flush_resume_helper(ngx_http_request_t *r,
|
||||
ngx_http_lua_ctx_t *ctx);
|
||||
|
||||
|
||||
/* Get the maximum possible length, not the actual length */
|
||||
static ngx_inline size_t
|
||||
ngx_http_lua_get_num_len(lua_State *L, int idx)
|
||||
{
|
||||
double num;
|
||||
|
||||
num = (double) lua_tonumber(L, idx);
|
||||
if (num == (double) (int32_t) num) {
|
||||
return NGX_INT32_LEN;
|
||||
}
|
||||
|
||||
return NGX_DOUBLE_LEN;
|
||||
}
|
||||
|
||||
|
||||
static ngx_inline u_char *
|
||||
ngx_http_lua_write_num(lua_State *L, int idx, u_char *dst)
|
||||
{
|
||||
double num;
|
||||
int n;
|
||||
|
||||
num = (double) lua_tonumber(L, idx);
|
||||
/*
|
||||
* luajit format number with only 14 significant digits.
|
||||
* To be consistent with lujit, don't use (double) (long) below
|
||||
* or integer greater than 99,999,999,999,999 will different from luajit.
|
||||
*/
|
||||
if (num == (double) (int32_t) num) {
|
||||
dst = ngx_snprintf(dst, NGX_INT64_LEN, "%D", (int32_t) num);
|
||||
|
||||
} else {
|
||||
/*
|
||||
* The maximum number of significant digits is 14 in lua.
|
||||
* Please refer to lj_strfmt.c for more details.
|
||||
*/
|
||||
n = snprintf((char *) dst, NGX_DOUBLE_LEN, "%.14g", num);
|
||||
if (n < 0) {
|
||||
ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, ngx_errno,
|
||||
"snprintf(\"%f\") failed");
|
||||
|
||||
} else {
|
||||
dst += n;
|
||||
}
|
||||
}
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_OUTPUT_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,106 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_http_lua_pcrefix.h"
|
||||
#include "stdio.h"
|
||||
|
||||
#if (NGX_PCRE)
|
||||
|
||||
static ngx_pool_t *ngx_http_lua_pcre_pool = NULL;
|
||||
|
||||
static void *(*old_pcre_malloc)(size_t);
|
||||
static void (*old_pcre_free)(void *ptr);
|
||||
|
||||
|
||||
/* XXX: work-around to nginx regex subsystem, must init a memory pool
|
||||
* to use PCRE functions. As PCRE still has memory-leaking problems,
|
||||
* and nginx overwrote pcre_malloc/free hooks with its own static
|
||||
* functions, so nobody else can reuse nginx regex subsystem... */
|
||||
static void *
|
||||
ngx_http_lua_pcre_malloc(size_t size)
|
||||
{
|
||||
dd("lua pcre pool is %p", ngx_http_lua_pcre_pool);
|
||||
|
||||
if (ngx_http_lua_pcre_pool) {
|
||||
return ngx_palloc(ngx_http_lua_pcre_pool, size);
|
||||
}
|
||||
|
||||
fprintf(stderr, "error: lua pcre malloc failed due to empty pcre pool");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_http_lua_pcre_free(void *ptr)
|
||||
{
|
||||
dd("lua pcre pool is %p", ngx_http_lua_pcre_pool);
|
||||
|
||||
if (ngx_http_lua_pcre_pool) {
|
||||
ngx_pfree(ngx_http_lua_pcre_pool, ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(stderr, "error: lua pcre free failed due to empty pcre pool");
|
||||
}
|
||||
|
||||
|
||||
ngx_pool_t *
|
||||
ngx_http_lua_pcre_malloc_init(ngx_pool_t *pool)
|
||||
{
|
||||
ngx_pool_t *old_pool;
|
||||
|
||||
if (pcre_malloc != ngx_http_lua_pcre_malloc) {
|
||||
|
||||
dd("overriding nginx pcre malloc and free");
|
||||
|
||||
ngx_http_lua_pcre_pool = pool;
|
||||
|
||||
old_pcre_malloc = pcre_malloc;
|
||||
old_pcre_free = pcre_free;
|
||||
|
||||
pcre_malloc = ngx_http_lua_pcre_malloc;
|
||||
pcre_free = ngx_http_lua_pcre_free;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dd("lua pcre pool was %p", ngx_http_lua_pcre_pool);
|
||||
|
||||
old_pool = ngx_http_lua_pcre_pool;
|
||||
ngx_http_lua_pcre_pool = pool;
|
||||
|
||||
dd("lua pcre pool is %p", ngx_http_lua_pcre_pool);
|
||||
|
||||
return old_pool;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_http_lua_pcre_malloc_done(ngx_pool_t *old_pool)
|
||||
{
|
||||
dd("lua pcre pool was %p", ngx_http_lua_pcre_pool);
|
||||
|
||||
ngx_http_lua_pcre_pool = old_pool;
|
||||
|
||||
dd("lua pcre pool is %p", ngx_http_lua_pcre_pool);
|
||||
|
||||
if (old_pool == NULL) {
|
||||
pcre_malloc = old_pcre_malloc;
|
||||
pcre_free = old_pcre_free;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* NGX_PCRE */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_PCREFIX_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_PCREFIX_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
#if (NGX_PCRE)
|
||||
ngx_pool_t *ngx_http_lua_pcre_malloc_init(ngx_pool_t *pool);
|
||||
void ngx_http_lua_pcre_malloc_done(ngx_pool_t *old_pool);
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_PCREFIX_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_get_phase(ngx_http_request_t *r, char **err)
|
||||
{
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
if (ctx == NULL) {
|
||||
*err = "no request context";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return ctx->context;
|
||||
}
|
||||
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,96 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) by OpenResty Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_PIPE_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_PIPE_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
typedef ngx_int_t (*ngx_http_lua_pipe_input_filter)(void *data, ssize_t bytes);
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_connection_t *c;
|
||||
ngx_http_lua_pipe_input_filter input_filter;
|
||||
void *input_filter_ctx;
|
||||
size_t rest;
|
||||
ngx_chain_t *buf_in;
|
||||
ngx_chain_t *bufs_in;
|
||||
ngx_buf_t buffer;
|
||||
ngx_err_t pipe_errno;
|
||||
unsigned err_type:16;
|
||||
unsigned eof:1;
|
||||
} ngx_http_lua_pipe_ctx_t;
|
||||
|
||||
|
||||
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;
|
||||
/* pipe hides the implementation from the Lua binding */
|
||||
ngx_http_lua_pipe_t *pipe;
|
||||
} ngx_http_lua_ffi_pipe_proc_t;
|
||||
|
||||
|
||||
typedef int (*ngx_http_lua_pipe_retval_handler)(
|
||||
ngx_http_lua_ffi_pipe_proc_t *proc, lua_State *L);
|
||||
|
||||
|
||||
struct ngx_http_lua_pipe_s {
|
||||
ngx_pool_t *pool;
|
||||
ngx_chain_t *free_bufs;
|
||||
ngx_rbtree_node_t *node;
|
||||
int stdin_fd;
|
||||
int stdout_fd;
|
||||
int stderr_fd;
|
||||
ngx_http_lua_pipe_ctx_t *stdin_ctx;
|
||||
ngx_http_lua_pipe_ctx_t *stdout_ctx;
|
||||
ngx_http_lua_pipe_ctx_t *stderr_ctx;
|
||||
ngx_http_lua_pipe_retval_handler retval_handler;
|
||||
ngx_http_cleanup_pt *cleanup;
|
||||
ngx_http_request_t *r;
|
||||
size_t buffer_size;
|
||||
unsigned closed:1;
|
||||
unsigned dead:1;
|
||||
unsigned timeout:1;
|
||||
unsigned merge_stderr:1;
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
u_char color;
|
||||
u_char reason_code;
|
||||
int status;
|
||||
ngx_http_lua_co_ctx_t *wait_co_ctx;
|
||||
ngx_http_lua_ffi_pipe_proc_t *proc;
|
||||
} ngx_http_lua_pipe_node_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
int signo;
|
||||
char *signame;
|
||||
} ngx_http_lua_pipe_signal_t;
|
||||
|
||||
|
||||
#if !(NGX_WIN32) && defined(HAVE_SOCKET_CLOEXEC_PATCH)
|
||||
#define HAVE_NGX_LUA_PIPE 1
|
||||
|
||||
|
||||
void ngx_http_lua_pipe_init(void);
|
||||
ngx_int_t ngx_http_lua_pipe_add_signal_handler(ngx_cycle_t *cycle);
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_PIPE_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* automatically generated from the file dtrace/ngx_lua_provider.d by the
|
||||
* gen-dtrace-probe-header tool in the nginx-devel-utils project:
|
||||
* https://github.com/agentzh/nginx-devel-utils
|
||||
*/
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_PROBE_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_PROBE_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_http.h>
|
||||
|
||||
|
||||
#if defined(NGX_DTRACE) && NGX_DTRACE
|
||||
|
||||
#include <ngx_dtrace_provider.h>
|
||||
|
||||
#define ngx_http_lua_probe_info(s) \
|
||||
NGINX_LUA_HTTP_LUA_INFO(s)
|
||||
|
||||
#define ngx_http_lua_probe_register_preload_package(L, pkg) \
|
||||
NGINX_LUA_HTTP_LUA_REGISTER_PRELOAD_PACKAGE(L, pkg)
|
||||
|
||||
#define ngx_http_lua_probe_req_socket_consume_preread(r, data, len) \
|
||||
NGINX_LUA_HTTP_LUA_REQ_SOCKET_CONSUME_PREREAD(r, data, len)
|
||||
|
||||
#define ngx_http_lua_probe_user_coroutine_create(r, parent, child) \
|
||||
NGINX_LUA_HTTP_LUA_USER_COROUTINE_CREATE(r, parent, child)
|
||||
|
||||
#define ngx_http_lua_probe_user_coroutine_resume(r, parent, child) \
|
||||
NGINX_LUA_HTTP_LUA_USER_COROUTINE_RESUME(r, parent, child)
|
||||
|
||||
#define ngx_http_lua_probe_user_coroutine_yield(r, parent, child) \
|
||||
NGINX_LUA_HTTP_LUA_USER_COROUTINE_YIELD(r, parent, child)
|
||||
|
||||
#define ngx_http_lua_probe_thread_yield(r, L) \
|
||||
NGINX_LUA_HTTP_LUA_THREAD_YIELD(r, L)
|
||||
|
||||
#define ngx_http_lua_probe_socket_tcp_send_start(r, u, data, len) \
|
||||
NGINX_LUA_HTTP_LUA_SOCKET_TCP_SEND_START(r, u, data, len)
|
||||
|
||||
#define ngx_http_lua_probe_socket_tcp_receive_done(r, u, data, len) \
|
||||
NGINX_LUA_HTTP_LUA_SOCKET_TCP_RECEIVE_DONE(r, u, data, len)
|
||||
|
||||
#define ngx_http_lua_probe_socket_tcp_setkeepalive_buf_unread(r, u, data, \
|
||||
len) \
|
||||
NGINX_LUA_HTTP_LUA_SOCKET_TCP_SETKEEPALIVE_BUF_UNREAD(r, u, data, len)
|
||||
|
||||
#define ngx_http_lua_probe_user_thread_spawn(r, creator, newthread) \
|
||||
NGINX_LUA_HTTP_LUA_USER_THREAD_SPAWN(r, creator, newthread)
|
||||
|
||||
#define ngx_http_lua_probe_thread_delete(r, thread, ctx) \
|
||||
NGINX_LUA_HTTP_LUA_THREAD_DELETE(r, thread, ctx)
|
||||
|
||||
#define ngx_http_lua_probe_run_posted_thread(r, thread, status) \
|
||||
NGINX_LUA_HTTP_LUA_RUN_POSTED_THREAD(r, thread, status)
|
||||
|
||||
#define ngx_http_lua_probe_coroutine_done(r, co, success) \
|
||||
NGINX_LUA_HTTP_LUA_COROUTINE_DONE(r, co, success)
|
||||
|
||||
#define ngx_http_lua_probe_user_thread_wait(parent, child) \
|
||||
NGINX_LUA_HTTP_LUA_USER_THREAD_WAIT(parent, child)
|
||||
|
||||
#else /* !(NGX_DTRACE) */
|
||||
|
||||
#define ngx_http_lua_probe_info(s)
|
||||
#define ngx_http_lua_probe_register_preload_package(L, pkg)
|
||||
#define ngx_http_lua_probe_req_socket_consume_preread(r, data, len)
|
||||
#define ngx_http_lua_probe_user_coroutine_create(r, parent, child)
|
||||
#define ngx_http_lua_probe_user_coroutine_resume(r, parent, child)
|
||||
#define ngx_http_lua_probe_user_coroutine_yield(r, parent, child)
|
||||
#define ngx_http_lua_probe_thread_yield(r, L)
|
||||
#define ngx_http_lua_probe_socket_tcp_send_start(r, u, data, len)
|
||||
#define ngx_http_lua_probe_socket_tcp_receive_done(r, u, data, len)
|
||||
#define ngx_http_lua_probe_socket_tcp_setkeepalive_buf_unread(r, u, data, len)
|
||||
#define ngx_http_lua_probe_user_thread_spawn(r, creator, newthread)
|
||||
#define ngx_http_lua_probe_thread_delete(r, thread, ctx)
|
||||
#define ngx_http_lua_probe_run_posted_thread(r, thread, status)
|
||||
#define ngx_http_lua_probe_coroutine_done(r, co, success)
|
||||
#define ngx_http_lua_probe_user_thread_wait(parent, child)
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_PROBE_H_INCLUDED_ */
|
|
@ -0,0 +1,602 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#if (NGX_PCRE)
|
||||
|
||||
#include "ngx_http_lua_pcrefix.h"
|
||||
#include "ngx_http_lua_script.h"
|
||||
#include "ngx_http_lua_util.h"
|
||||
|
||||
|
||||
#if (PCRE_MAJOR >= 6)
|
||||
# define LUA_HAVE_PCRE_DFA 1
|
||||
#else
|
||||
# define LUA_HAVE_PCRE_DFA 0
|
||||
#endif
|
||||
|
||||
|
||||
#define NGX_LUA_RE_MODE_DFA (1<<1)
|
||||
#define NGX_LUA_RE_MODE_JIT (1<<2)
|
||||
#define NGX_LUA_RE_NO_UTF8_CHECK (1<<4)
|
||||
|
||||
#define NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT (100)
|
||||
|
||||
#define NGX_LUA_RE_MIN_JIT_STACK_SIZE 32 * 1024
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_pool_t *pool;
|
||||
u_char *name_table;
|
||||
int name_count;
|
||||
int name_entry_size;
|
||||
|
||||
int ncaptures;
|
||||
int *captures;
|
||||
|
||||
pcre *regex;
|
||||
pcre_extra *regex_sd;
|
||||
|
||||
ngx_http_lua_complex_value_t *replace;
|
||||
|
||||
/* only for (stap) debugging, and may be an invalid pointer */
|
||||
const u_char *pattern;
|
||||
} ngx_http_lua_regex_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t pattern;
|
||||
ngx_pool_t *pool;
|
||||
ngx_int_t options;
|
||||
|
||||
pcre *regex;
|
||||
int captures;
|
||||
ngx_str_t err;
|
||||
} ngx_http_lua_regex_compile_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_http_request_t *request;
|
||||
pcre *regex;
|
||||
pcre_extra *regex_sd;
|
||||
int ncaptures;
|
||||
int *captures;
|
||||
int captures_len;
|
||||
uint8_t flags;
|
||||
} ngx_http_lua_regex_ctx_t;
|
||||
|
||||
|
||||
static void ngx_http_lua_regex_free_study_data(ngx_pool_t *pool,
|
||||
pcre_extra *sd);
|
||||
static ngx_int_t ngx_http_lua_regex_compile(ngx_http_lua_regex_compile_t *rc);
|
||||
|
||||
|
||||
#define ngx_http_lua_regex_exec(re, e, s, start, captures, size, opts) \
|
||||
pcre_exec(re, e, (const char *) (s)->data, (s)->len, start, opts, \
|
||||
captures, size)
|
||||
|
||||
|
||||
#define ngx_http_lua_regex_dfa_exec(re, e, s, start, captures, size, ws, \
|
||||
wscount, opts) \
|
||||
pcre_dfa_exec(re, e, (const char *) (s)->data, (s)->len, start, opts, \
|
||||
captures, size, ws, wscount)
|
||||
|
||||
|
||||
static void
|
||||
ngx_http_lua_regex_free_study_data(ngx_pool_t *pool, pcre_extra *sd)
|
||||
{
|
||||
ngx_pool_t *old_pool;
|
||||
|
||||
old_pool = ngx_http_lua_pcre_malloc_init(pool);
|
||||
|
||||
#if LUA_HAVE_PCRE_JIT
|
||||
pcre_free_study(sd);
|
||||
#else
|
||||
pcre_free(sd);
|
||||
#endif
|
||||
|
||||
ngx_http_lua_pcre_malloc_done(old_pool);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_lua_regex_compile(ngx_http_lua_regex_compile_t *rc)
|
||||
{
|
||||
int n, erroff;
|
||||
char *p;
|
||||
const char *errstr;
|
||||
pcre *re;
|
||||
ngx_pool_t *old_pool;
|
||||
|
||||
old_pool = ngx_http_lua_pcre_malloc_init(rc->pool);
|
||||
|
||||
re = pcre_compile((const char *) rc->pattern.data, (int) rc->options,
|
||||
&errstr, &erroff, NULL);
|
||||
|
||||
ngx_http_lua_pcre_malloc_done(old_pool);
|
||||
|
||||
if (re == NULL) {
|
||||
if ((size_t) erroff == rc->pattern.len) {
|
||||
rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
|
||||
"pcre_compile() failed: %s in \"%V\"",
|
||||
errstr, &rc->pattern)
|
||||
- rc->err.data;
|
||||
|
||||
} else {
|
||||
rc->err.len = ngx_snprintf(rc->err.data, rc->err.len,
|
||||
"pcre_compile() failed: %s in \"%V\" "
|
||||
"at \"%s\"", errstr, &rc->pattern,
|
||||
rc->pattern.data + erroff)
|
||||
- rc->err.data;
|
||||
}
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
rc->regex = re;
|
||||
|
||||
#if 1
|
||||
n = pcre_fullinfo(re, NULL, PCRE_INFO_CAPTURECOUNT, &rc->captures);
|
||||
if (n < 0) {
|
||||
p = "pcre_fullinfo(\"%V\", PCRE_INFO_CAPTURECOUNT) failed: %d";
|
||||
goto failed;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NGX_OK;
|
||||
|
||||
failed:
|
||||
|
||||
rc->err.len = ngx_snprintf(rc->err.data, rc->err.len, p, &rc->pattern, n)
|
||||
- rc->err.data;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_ffi_set_jit_stack_size(int size, u_char *errstr,
|
||||
size_t *errstr_size)
|
||||
{
|
||||
#if LUA_HAVE_PCRE_JIT
|
||||
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
ngx_pool_t *pool, *old_pool;
|
||||
|
||||
lmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle,
|
||||
ngx_http_lua_module);
|
||||
|
||||
ngx_http_lua_assert(lmcf != NULL);
|
||||
|
||||
if (size < NGX_LUA_RE_MIN_JIT_STACK_SIZE) {
|
||||
size = NGX_LUA_RE_MIN_JIT_STACK_SIZE;
|
||||
}
|
||||
|
||||
pool = lmcf->pool;
|
||||
|
||||
dd("server pool %p", lmcf->pool);
|
||||
|
||||
if (lmcf->jit_stack) {
|
||||
old_pool = ngx_http_lua_pcre_malloc_init(pool);
|
||||
|
||||
pcre_jit_stack_free(lmcf->jit_stack);
|
||||
|
||||
ngx_http_lua_pcre_malloc_done(old_pool);
|
||||
}
|
||||
|
||||
old_pool = ngx_http_lua_pcre_malloc_init(pool);
|
||||
|
||||
lmcf->jit_stack = pcre_jit_stack_alloc(NGX_LUA_RE_MIN_JIT_STACK_SIZE,
|
||||
size);
|
||||
|
||||
ngx_http_lua_pcre_malloc_done(old_pool);
|
||||
|
||||
if (lmcf->jit_stack == NULL) {
|
||||
*errstr_size = ngx_snprintf(errstr, *errstr_size,
|
||||
"pcre jit stack allocation failed")
|
||||
- errstr;
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
|
||||
#else /* LUA_HAVE_PCRE_JIT */
|
||||
|
||||
*errstr_size = ngx_snprintf(errstr, *errstr_size,
|
||||
"no pcre jit support found")
|
||||
- errstr;
|
||||
return NGX_ERROR;
|
||||
|
||||
#endif /* LUA_HAVE_PCRE_JIT */
|
||||
}
|
||||
|
||||
|
||||
ngx_http_lua_regex_t *
|
||||
ngx_http_lua_ffi_compile_regex(const unsigned char *pat, size_t pat_len,
|
||||
int flags, int pcre_opts, u_char *errstr,
|
||||
size_t errstr_size)
|
||||
{
|
||||
int *cap = NULL, ovecsize;
|
||||
u_char *p;
|
||||
ngx_int_t rc;
|
||||
const char *msg;
|
||||
ngx_pool_t *pool, *old_pool;
|
||||
pcre_extra *sd = NULL;
|
||||
ngx_http_lua_regex_t *re;
|
||||
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
ngx_http_lua_regex_compile_t re_comp;
|
||||
|
||||
pool = ngx_create_pool(512, ngx_cycle->log);
|
||||
if (pool == NULL) {
|
||||
msg = "no memory";
|
||||
goto error;
|
||||
}
|
||||
|
||||
pool->log = (ngx_log_t *) &ngx_cycle->new_log;
|
||||
|
||||
re = ngx_palloc(pool, sizeof(ngx_http_lua_regex_t));
|
||||
if (re == NULL) {
|
||||
ngx_destroy_pool(pool);
|
||||
pool = NULL;
|
||||
msg = "no memory";
|
||||
goto error;
|
||||
}
|
||||
|
||||
re->pool = pool;
|
||||
|
||||
re_comp.options = pcre_opts;
|
||||
re_comp.pattern.data = (u_char *) pat;
|
||||
re_comp.pattern.len = pat_len;
|
||||
re_comp.err.len = errstr_size - 1;
|
||||
re_comp.err.data = errstr;
|
||||
re_comp.pool = pool;
|
||||
|
||||
old_pool = ngx_http_lua_pcre_malloc_init(pool);
|
||||
rc = ngx_http_lua_regex_compile(&re_comp);
|
||||
ngx_http_lua_pcre_malloc_done(old_pool);
|
||||
|
||||
if (rc != NGX_OK) {
|
||||
re_comp.err.data[re_comp.err.len] = '\0';
|
||||
msg = (char *) re_comp.err.data;
|
||||
goto error;
|
||||
}
|
||||
|
||||
lmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle,
|
||||
ngx_http_lua_module);
|
||||
|
||||
ngx_http_lua_assert(lmcf != NULL);
|
||||
|
||||
#if (LUA_HAVE_PCRE_JIT)
|
||||
|
||||
if (flags & NGX_LUA_RE_MODE_JIT) {
|
||||
|
||||
old_pool = ngx_http_lua_pcre_malloc_init(pool);
|
||||
sd = pcre_study(re_comp.regex, PCRE_STUDY_JIT_COMPILE, &msg);
|
||||
ngx_http_lua_pcre_malloc_done(old_pool);
|
||||
|
||||
# if (NGX_DEBUG)
|
||||
if (msg != NULL) {
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
|
||||
"pcre study failed with PCRE_STUDY_JIT_COMPILE: "
|
||||
"%s (%p)", msg, sd);
|
||||
}
|
||||
|
||||
if (sd != NULL) {
|
||||
int jitted;
|
||||
|
||||
old_pool = ngx_http_lua_pcre_malloc_init(pool);
|
||||
|
||||
pcre_fullinfo(re_comp.regex, sd, PCRE_INFO_JIT, &jitted);
|
||||
|
||||
ngx_http_lua_pcre_malloc_done(old_pool);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
|
||||
"pcre JIT compiling result: %d", jitted);
|
||||
}
|
||||
# endif /* !(NGX_DEBUG) */
|
||||
|
||||
} else {
|
||||
old_pool = ngx_http_lua_pcre_malloc_init(pool);
|
||||
sd = pcre_study(re_comp.regex, 0, &msg);
|
||||
ngx_http_lua_pcre_malloc_done(old_pool);
|
||||
}
|
||||
|
||||
if (sd && lmcf->jit_stack) {
|
||||
pcre_assign_jit_stack(sd, NULL, lmcf->jit_stack);
|
||||
}
|
||||
|
||||
#endif /* LUA_HAVE_PCRE_JIT */
|
||||
|
||||
if (sd
|
||||
&& lmcf && lmcf->regex_match_limit > 0
|
||||
&& !(flags & NGX_LUA_RE_MODE_DFA))
|
||||
{
|
||||
sd->flags |= PCRE_EXTRA_MATCH_LIMIT;
|
||||
sd->match_limit = lmcf->regex_match_limit;
|
||||
}
|
||||
|
||||
if (flags & NGX_LUA_RE_MODE_DFA) {
|
||||
ovecsize = 2;
|
||||
re_comp.captures = 0;
|
||||
|
||||
} else {
|
||||
ovecsize = (re_comp.captures + 1) * 3;
|
||||
}
|
||||
|
||||
dd("allocating cap with size: %d", (int) ovecsize);
|
||||
|
||||
cap = ngx_palloc(pool, ovecsize * sizeof(int));
|
||||
if (cap == NULL) {
|
||||
msg = "no memory";
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (pcre_fullinfo(re_comp.regex, NULL, PCRE_INFO_NAMECOUNT,
|
||||
&re->name_count) != 0)
|
||||
{
|
||||
msg = "cannot acquire named subpattern count";
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (re->name_count > 0) {
|
||||
if (pcre_fullinfo(re_comp.regex, NULL, PCRE_INFO_NAMEENTRYSIZE,
|
||||
&re->name_entry_size) != 0)
|
||||
{
|
||||
msg = "cannot acquire named subpattern entry size";
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (pcre_fullinfo(re_comp.regex, NULL, PCRE_INFO_NAMETABLE,
|
||||
&re->name_table) != 0)
|
||||
{
|
||||
msg = "cannot acquire named subpattern table";
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
re->regex = re_comp.regex;
|
||||
re->regex_sd = sd;
|
||||
re->ncaptures = re_comp.captures;
|
||||
re->captures = cap;
|
||||
re->replace = NULL;
|
||||
|
||||
/* only for (stap) debugging, the pointer might be invalid when the
|
||||
* string is collected later on.... */
|
||||
re->pattern = pat;
|
||||
|
||||
return re;
|
||||
|
||||
error:
|
||||
|
||||
p = ngx_snprintf(errstr, errstr_size - 1, "%s", msg);
|
||||
*p = '\0';
|
||||
|
||||
if (sd) {
|
||||
ngx_http_lua_regex_free_study_data(pool, sd);
|
||||
}
|
||||
|
||||
if (pool) {
|
||||
ngx_destroy_pool(pool);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_exec_regex(ngx_http_lua_regex_t *re, int flags,
|
||||
const u_char *s, size_t len, int pos)
|
||||
{
|
||||
int rc, ovecsize, exec_opts, *cap;
|
||||
ngx_str_t subj;
|
||||
pcre_extra *sd;
|
||||
|
||||
cap = re->captures;
|
||||
sd = re->regex_sd;
|
||||
|
||||
if (flags & NGX_LUA_RE_MODE_DFA) {
|
||||
ovecsize = 2;
|
||||
re->ncaptures = 0;
|
||||
|
||||
} else {
|
||||
ovecsize = (re->ncaptures + 1) * 3;
|
||||
}
|
||||
|
||||
if (flags & NGX_LUA_RE_NO_UTF8_CHECK) {
|
||||
exec_opts = PCRE_NO_UTF8_CHECK;
|
||||
|
||||
} else {
|
||||
exec_opts = 0;
|
||||
}
|
||||
|
||||
subj.data = (u_char *) s;
|
||||
subj.len = len;
|
||||
|
||||
if (flags & NGX_LUA_RE_MODE_DFA) {
|
||||
|
||||
#if LUA_HAVE_PCRE_DFA
|
||||
|
||||
int ws[NGX_LUA_RE_DFA_MODE_WORKSPACE_COUNT];
|
||||
rc = ngx_http_lua_regex_dfa_exec(re->regex, sd, &subj,
|
||||
(int) pos, cap, ovecsize, ws,
|
||||
sizeof(ws)/sizeof(ws[0]), exec_opts);
|
||||
|
||||
#else
|
||||
|
||||
return PCRE_ERROR_BADOPTION;
|
||||
|
||||
#endif /* LUA_HAVE_PCRE_DFA */
|
||||
|
||||
} else {
|
||||
rc = ngx_http_lua_regex_exec(re->regex, sd, &subj, (int) pos, cap,
|
||||
ovecsize, exec_opts);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_http_lua_ffi_destroy_regex(ngx_http_lua_regex_t *re)
|
||||
{
|
||||
ngx_pool_t *old_pool;
|
||||
|
||||
dd("destroy regex called");
|
||||
|
||||
if (re == NULL || re->pool == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (re->regex_sd) {
|
||||
old_pool = ngx_http_lua_pcre_malloc_init(re->pool);
|
||||
#if LUA_HAVE_PCRE_JIT
|
||||
pcre_free_study(re->regex_sd);
|
||||
#else
|
||||
pcre_free(re->regex_sd);
|
||||
#endif
|
||||
ngx_http_lua_pcre_malloc_done(old_pool);
|
||||
re->regex_sd = NULL;
|
||||
}
|
||||
|
||||
ngx_destroy_pool(re->pool);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_compile_replace_template(ngx_http_lua_regex_t *re,
|
||||
const u_char *replace_data, size_t replace_len)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
ngx_str_t tpl;
|
||||
ngx_http_lua_complex_value_t *ctpl;
|
||||
ngx_http_lua_compile_complex_value_t ccv;
|
||||
|
||||
ctpl = ngx_palloc(re->pool, sizeof(ngx_http_lua_complex_value_t));
|
||||
if (ctpl == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (replace_len != 0) {
|
||||
/* copy the string buffer pointed to by tpl.data from Lua VM */
|
||||
tpl.data = ngx_palloc(re->pool, replace_len + 1);
|
||||
if (tpl.data == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_memcpy(tpl.data, replace_data, replace_len);
|
||||
tpl.data[replace_len] = '\0';
|
||||
|
||||
} else {
|
||||
tpl.data = (u_char *) replace_data;
|
||||
}
|
||||
|
||||
tpl.len = replace_len;
|
||||
|
||||
ngx_memzero(&ccv, sizeof(ngx_http_lua_compile_complex_value_t));
|
||||
ccv.pool = re->pool;
|
||||
ccv.log = ngx_cycle->log;
|
||||
ccv.value = &tpl;
|
||||
ccv.complex_value = ctpl;
|
||||
|
||||
rc = ngx_http_lua_compile_complex_value(&ccv);
|
||||
|
||||
re->replace = ctpl;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
ngx_http_lua_script_engine_t *
|
||||
ngx_http_lua_ffi_create_script_engine(void)
|
||||
{
|
||||
return ngx_calloc(sizeof(ngx_http_lua_script_engine_t), ngx_cycle->log);
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
e->log = ngx_cycle->log;
|
||||
e->ncaptures = count * 2;
|
||||
e->captures = compiled->captures;
|
||||
e->captures_data = (u_char *) subj;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_http_lua_ffi_destroy_script_engine(ngx_http_lua_script_engine_t *e)
|
||||
{
|
||||
ngx_free(e);
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
ngx_http_lua_ffi_script_eval_len(ngx_http_lua_script_engine_t *e,
|
||||
ngx_http_lua_complex_value_t *val)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
ngx_http_lua_script_len_code_pt lcode;
|
||||
|
||||
e->ip = val->lengths;
|
||||
len = 0;
|
||||
|
||||
while (*(uintptr_t *) e->ip) {
|
||||
lcode = *(ngx_http_lua_script_len_code_pt *) e->ip;
|
||||
len += lcode(e);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_http_lua_ffi_script_eval_data(ngx_http_lua_script_engine_t *e,
|
||||
ngx_http_lua_complex_value_t *val, u_char *dst)
|
||||
{
|
||||
ngx_http_lua_script_code_pt code;
|
||||
|
||||
e->ip = val->values;
|
||||
e->pos = dst;
|
||||
|
||||
while (*(uintptr_t *) e->ip) {
|
||||
code = *(ngx_http_lua_script_code_pt *) e->ip;
|
||||
code(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t
|
||||
ngx_http_lua_ffi_max_regex_cache_size(void)
|
||||
{
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
lmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle,
|
||||
ngx_http_lua_module);
|
||||
if (lmcf == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (uint32_t) lmcf->regex_cache_max_entries;
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
ngx_http_lua_ffi_pcre_version(void)
|
||||
{
|
||||
return pcre_version();
|
||||
}
|
||||
|
||||
|
||||
#endif /* NGX_PCRE */
|
||||
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,20 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_REQ_BODY_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_REQ_BODY_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
void ngx_http_lua_inject_req_body_api(lua_State *L);
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_REQ_BODY_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,119 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
|
||||
|
||||
#include "ddebug.h"
|
||||
#include "ngx_http_lua_subrequest.h"
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_req_get_method(ngx_http_request_t *r)
|
||||
{
|
||||
if (r->connection->fd == (ngx_socket_t) -1) {
|
||||
return NGX_HTTP_LUA_FFI_BAD_CONTEXT;
|
||||
}
|
||||
|
||||
return r->method;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_req_get_method_name(ngx_http_request_t *r, u_char **name,
|
||||
size_t *len)
|
||||
{
|
||||
if (r->connection->fd == (ngx_socket_t) -1) {
|
||||
return NGX_HTTP_LUA_FFI_BAD_CONTEXT;
|
||||
}
|
||||
|
||||
*name = r->method_name.data;
|
||||
*len = r->method_name.len;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_req_set_method(ngx_http_request_t *r, int method)
|
||||
{
|
||||
if (r->connection->fd == (ngx_socket_t) -1) {
|
||||
return NGX_HTTP_LUA_FFI_BAD_CONTEXT;
|
||||
}
|
||||
|
||||
switch (method) {
|
||||
case NGX_HTTP_GET:
|
||||
r->method_name = ngx_http_lua_get_method;
|
||||
break;
|
||||
|
||||
case NGX_HTTP_POST:
|
||||
r->method_name = ngx_http_lua_post_method;
|
||||
break;
|
||||
|
||||
case NGX_HTTP_PUT:
|
||||
r->method_name = ngx_http_lua_put_method;
|
||||
break;
|
||||
|
||||
case NGX_HTTP_HEAD:
|
||||
r->method_name = ngx_http_lua_head_method;
|
||||
break;
|
||||
|
||||
case NGX_HTTP_DELETE:
|
||||
r->method_name = ngx_http_lua_delete_method;
|
||||
break;
|
||||
|
||||
case NGX_HTTP_OPTIONS:
|
||||
r->method_name = ngx_http_lua_options_method;
|
||||
break;
|
||||
|
||||
case NGX_HTTP_MKCOL:
|
||||
r->method_name = ngx_http_lua_mkcol_method;
|
||||
break;
|
||||
|
||||
case NGX_HTTP_COPY:
|
||||
r->method_name = ngx_http_lua_copy_method;
|
||||
break;
|
||||
|
||||
case NGX_HTTP_MOVE:
|
||||
r->method_name = ngx_http_lua_move_method;
|
||||
break;
|
||||
|
||||
case NGX_HTTP_PROPFIND:
|
||||
r->method_name = ngx_http_lua_propfind_method;
|
||||
break;
|
||||
|
||||
case NGX_HTTP_PROPPATCH:
|
||||
r->method_name = ngx_http_lua_proppatch_method;
|
||||
break;
|
||||
|
||||
case NGX_HTTP_LOCK:
|
||||
r->method_name = ngx_http_lua_lock_method;
|
||||
break;
|
||||
|
||||
case NGX_HTTP_UNLOCK:
|
||||
r->method_name = ngx_http_lua_unlock_method;
|
||||
break;
|
||||
|
||||
case NGX_HTTP_PATCH:
|
||||
r->method_name = ngx_http_lua_patch_method;
|
||||
break;
|
||||
|
||||
case NGX_HTTP_TRACE:
|
||||
r->method_name = ngx_http_lua_trace_method;
|
||||
break;
|
||||
|
||||
default:
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
r->method = method;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,381 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
#include <nginx.h>
|
||||
#include "ngx_http_lua_rewriteby.h"
|
||||
#include "ngx_http_lua_util.h"
|
||||
#include "ngx_http_lua_exception.h"
|
||||
#include "ngx_http_lua_cache.h"
|
||||
|
||||
|
||||
static ngx_int_t ngx_http_lua_rewrite_by_chunk(lua_State *L,
|
||||
ngx_http_request_t *r);
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_rewrite_handler(ngx_http_request_t *r)
|
||||
{
|
||||
ngx_http_lua_loc_conf_t *llcf;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_int_t rc;
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
|
||||
/* XXX we need to take into account ngx_rewrite's location dump */
|
||||
if (r->uri_changed) {
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua rewrite handler, uri:\"%V\" c:%ud", &r->uri,
|
||||
r->main->count);
|
||||
|
||||
lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
|
||||
|
||||
if (!lmcf->postponed_to_rewrite_phase_end) {
|
||||
ngx_http_core_main_conf_t *cmcf;
|
||||
ngx_http_phase_handler_t tmp;
|
||||
ngx_http_phase_handler_t *ph;
|
||||
ngx_http_phase_handler_t *cur_ph;
|
||||
ngx_http_phase_handler_t *last_ph;
|
||||
|
||||
lmcf->postponed_to_rewrite_phase_end = 1;
|
||||
|
||||
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
|
||||
|
||||
ph = cmcf->phase_engine.handlers;
|
||||
cur_ph = &ph[r->phase_handler];
|
||||
last_ph = &ph[cur_ph->next - 1];
|
||||
|
||||
#if 0
|
||||
if (cur_ph == last_ph) {
|
||||
dd("XXX our handler is already the last rewrite phase handler");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cur_ph < last_ph) {
|
||||
dd("swapping the contents of cur_ph and last_ph...");
|
||||
|
||||
tmp = *cur_ph;
|
||||
|
||||
memmove(cur_ph, cur_ph + 1,
|
||||
(last_ph - cur_ph) * sizeof (ngx_http_phase_handler_t));
|
||||
|
||||
*last_ph = tmp;
|
||||
|
||||
r->phase_handler--; /* redo the current ph */
|
||||
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
}
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
|
||||
if (llcf->rewrite_handler == NULL) {
|
||||
dd("no rewrite handler found");
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
|
||||
dd("ctx = %p", ctx);
|
||||
|
||||
if (ctx == NULL) {
|
||||
ctx = ngx_http_lua_create_ctx(r);
|
||||
if (ctx == NULL) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
dd("entered? %d", (int) ctx->entered_rewrite_phase);
|
||||
|
||||
if (ctx->entered_rewrite_phase) {
|
||||
dd("rewriteby: calling wev handler");
|
||||
rc = ctx->resume_handler(r);
|
||||
dd("rewriteby: wev handler returns %d", (int) rc);
|
||||
|
||||
if (rc == NGX_OK) {
|
||||
rc = NGX_DECLINED;
|
||||
}
|
||||
|
||||
if (rc == NGX_DECLINED) {
|
||||
if (r->header_sent) {
|
||||
dd("header already sent");
|
||||
|
||||
/* response header was already generated in rewrite_by_lua*,
|
||||
* so it is no longer safe to proceed to later phases
|
||||
* which may generate responses again */
|
||||
|
||||
if (!ctx->eof) {
|
||||
dd("eof not yet sent");
|
||||
|
||||
rc = ngx_http_lua_send_chain_link(r, ctx, NULL
|
||||
/* indicate last_buf */);
|
||||
if (rc == NGX_ERROR || rc > NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_HTTP_OK;
|
||||
}
|
||||
|
||||
r->write_event_handler = ngx_http_core_run_phases;
|
||||
ctx->entered_rewrite_phase = 0;
|
||||
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (ctx->waiting_more_body) {
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
if (llcf->force_read_body && !ctx->read_body_done) {
|
||||
r->request_body_in_single_buf = 1;
|
||||
r->request_body_in_persistent_file = 1;
|
||||
r->request_body_in_clean_file = 1;
|
||||
|
||||
rc = ngx_http_read_client_request_body(r,
|
||||
ngx_http_lua_generic_phase_post_read);
|
||||
|
||||
if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (rc == NGX_AGAIN) {
|
||||
ctx->waiting_more_body = 1;
|
||||
return NGX_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
dd("calling rewrite handler");
|
||||
return llcf->rewrite_handler(r);
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_rewrite_handler_inline(ngx_http_request_t *r)
|
||||
{
|
||||
lua_State *L;
|
||||
ngx_int_t rc;
|
||||
ngx_http_lua_loc_conf_t *llcf;
|
||||
|
||||
dd("rewrite by lua inline");
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
L = ngx_http_lua_get_lua_vm(r, NULL);
|
||||
|
||||
/* load Lua inline script (w/ cache) sp = 1 */
|
||||
rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L,
|
||||
llcf->rewrite_src.value.data,
|
||||
llcf->rewrite_src.value.len,
|
||||
&llcf->rewrite_src_ref,
|
||||
llcf->rewrite_src_key,
|
||||
(const char *)
|
||||
llcf->rewrite_chunkname);
|
||||
if (rc != NGX_OK) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
return ngx_http_lua_rewrite_by_chunk(L, r);
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_rewrite_handler_file(ngx_http_request_t *r)
|
||||
{
|
||||
lua_State *L;
|
||||
ngx_int_t rc;
|
||||
u_char *script_path;
|
||||
ngx_http_lua_loc_conf_t *llcf;
|
||||
ngx_str_t eval_src;
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
|
||||
if (ngx_http_complex_value(r, &llcf->rewrite_src, &eval_src) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
script_path = ngx_http_lua_rebase_path(r->pool, eval_src.data,
|
||||
eval_src.len);
|
||||
|
||||
if (script_path == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
L = ngx_http_lua_get_lua_vm(r, NULL);
|
||||
|
||||
/* load Lua script file (w/ cache) sp = 1 */
|
||||
rc = ngx_http_lua_cache_loadfile(r->connection->log, L, script_path,
|
||||
&llcf->rewrite_src_ref,
|
||||
llcf->rewrite_src_key);
|
||||
if (rc != NGX_OK) {
|
||||
if (rc < NGX_HTTP_SPECIAL_RESPONSE) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
return ngx_http_lua_rewrite_by_chunk(L, r);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_lua_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r)
|
||||
{
|
||||
int co_ref;
|
||||
lua_State *co;
|
||||
ngx_int_t rc;
|
||||
ngx_uint_t nreqs;
|
||||
ngx_event_t *rev;
|
||||
ngx_connection_t *c;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_pool_cleanup_t *cln;
|
||||
|
||||
ngx_http_lua_loc_conf_t *llcf;
|
||||
|
||||
/* {{{ new coroutine to handle request */
|
||||
co = ngx_http_lua_new_thread(r, L, &co_ref);
|
||||
|
||||
if (co == NULL) {
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"lua: failed to create new coroutine to handle request");
|
||||
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
/* move code closure to new coroutine */
|
||||
lua_xmove(L, co, 1);
|
||||
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
/* set closure's env table to new coroutine's globals table */
|
||||
ngx_http_lua_get_globals_table(co);
|
||||
lua_setfenv(co, -2);
|
||||
#endif
|
||||
|
||||
/* save nginx request in coroutine globals table */
|
||||
ngx_http_lua_set_req(co, r);
|
||||
|
||||
/* {{{ initialize request context */
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
|
||||
dd("ctx = %p", ctx);
|
||||
|
||||
if (ctx == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_http_lua_reset_ctx(r, L, ctx);
|
||||
|
||||
ctx->entered_rewrite_phase = 1;
|
||||
|
||||
ctx->cur_co_ctx = &ctx->entry_co_ctx;
|
||||
ctx->cur_co_ctx->co = co;
|
||||
ctx->cur_co_ctx->co_ref = co_ref;
|
||||
#ifdef NGX_LUA_USE_ASSERT
|
||||
ctx->cur_co_ctx->co_top = 1;
|
||||
#endif
|
||||
|
||||
ngx_http_lua_attach_co_ctx_to_L(co, ctx->cur_co_ctx);
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* {{{ register nginx pool cleanup hooks */
|
||||
if (ctx->cleanup == NULL) {
|
||||
cln = ngx_pool_cleanup_add(r->pool, 0);
|
||||
if (cln == NULL) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
cln->handler = ngx_http_lua_request_cleanup_handler;
|
||||
cln->data = ctx;
|
||||
ctx->cleanup = &cln->handler;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
ctx->context = NGX_HTTP_LUA_CONTEXT_REWRITE;
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
|
||||
if (llcf->check_client_abort) {
|
||||
r->read_event_handler = ngx_http_lua_rd_check_broken_connection;
|
||||
|
||||
#if (NGX_HTTP_V2)
|
||||
if (!r->stream) {
|
||||
#endif
|
||||
|
||||
rev = r->connection->read;
|
||||
|
||||
if (!rev->active) {
|
||||
if (ngx_add_event(rev, NGX_READ_EVENT, 0) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
#if (NGX_HTTP_V2)
|
||||
}
|
||||
#endif
|
||||
|
||||
} else {
|
||||
r->read_event_handler = ngx_http_block_reading;
|
||||
}
|
||||
|
||||
c = r->connection;
|
||||
nreqs = c->requests;
|
||||
|
||||
rc = ngx_http_lua_run_thread(L, r, ctx, 0);
|
||||
|
||||
if (rc == NGX_ERROR || rc > NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (rc == NGX_AGAIN) {
|
||||
rc = ngx_http_lua_run_posted_threads(c, L, r, ctx, nreqs);
|
||||
|
||||
} else if (rc == NGX_DONE) {
|
||||
ngx_http_lua_finalize_request(r, NGX_DONE);
|
||||
rc = ngx_http_lua_run_posted_threads(c, L, r, ctx, nreqs);
|
||||
}
|
||||
|
||||
if (rc == NGX_OK || rc == NGX_DECLINED) {
|
||||
if (r->header_sent) {
|
||||
dd("header already sent");
|
||||
|
||||
/* response header was already generated in rewrite_by_lua*,
|
||||
* so it is no longer safe to proceed to later phases
|
||||
* which may generate responses again */
|
||||
|
||||
if (!ctx->eof) {
|
||||
dd("eof not yet sent");
|
||||
|
||||
rc = ngx_http_lua_send_chain_link(r, ctx, NULL
|
||||
/* indicate last_buf */);
|
||||
if (rc == NGX_ERROR || rc > NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_HTTP_OK;
|
||||
}
|
||||
|
||||
r->write_event_handler = ngx_http_core_run_phases;
|
||||
ctx->entered_rewrite_phase = 0;
|
||||
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_REWRITEBY_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_REWRITEBY_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
ngx_int_t ngx_http_lua_rewrite_handler(ngx_http_request_t *r);
|
||||
ngx_int_t ngx_http_lua_rewrite_handler_inline(ngx_http_request_t *r);
|
||||
ngx_int_t ngx_http_lua_rewrite_handler_file(ngx_http_request_t *r);
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_REWRITEBY_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,538 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_http_lua_script.h"
|
||||
|
||||
|
||||
static void *ngx_http_lua_script_add_code(ngx_array_t *codes, size_t size);
|
||||
static size_t ngx_http_lua_script_copy_len_code(
|
||||
ngx_http_lua_script_engine_t *e);
|
||||
static void ngx_http_lua_script_copy_code(ngx_http_lua_script_engine_t *e);
|
||||
static ngx_int_t ngx_http_lua_script_add_copy_code(
|
||||
ngx_http_lua_script_compile_t *sc, ngx_str_t *value, ngx_uint_t last);
|
||||
static ngx_int_t ngx_http_lua_script_compile(ngx_http_lua_script_compile_t *sc);
|
||||
static ngx_int_t ngx_http_lua_script_add_capture_code(
|
||||
ngx_http_lua_script_compile_t *sc, ngx_uint_t n);
|
||||
static size_t ngx_http_lua_script_copy_capture_len_code(
|
||||
ngx_http_lua_script_engine_t *e);
|
||||
static void ngx_http_lua_script_copy_capture_code(
|
||||
ngx_http_lua_script_engine_t *e);
|
||||
static ngx_int_t ngx_http_lua_script_done(ngx_http_lua_script_compile_t *sc);
|
||||
static ngx_int_t ngx_http_lua_script_init_arrays(
|
||||
ngx_http_lua_script_compile_t *sc);
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_compile_complex_value(ngx_http_lua_compile_complex_value_t *ccv)
|
||||
{
|
||||
ngx_str_t *v;
|
||||
ngx_uint_t i, n, nv;
|
||||
ngx_array_t lengths, values, *pl, *pv;
|
||||
|
||||
ngx_http_lua_script_compile_t sc;
|
||||
|
||||
v = ccv->value;
|
||||
|
||||
nv = 0;
|
||||
|
||||
for (i = 0; i < v->len; i++) {
|
||||
if (v->data[i] == '$') {
|
||||
nv++;
|
||||
}
|
||||
}
|
||||
|
||||
ccv->complex_value->value = *v;
|
||||
ccv->complex_value->lengths = NULL;
|
||||
ccv->complex_value->values = NULL;
|
||||
|
||||
if (nv == 0) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
n = nv * (2 * sizeof(ngx_http_lua_script_copy_code_t)
|
||||
+ sizeof(ngx_http_lua_script_capture_code_t))
|
||||
+ sizeof(uintptr_t);
|
||||
|
||||
if (ngx_array_init(&lengths, ccv->pool, n, 1) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
n = (nv * (2 * sizeof(ngx_http_lua_script_copy_code_t)
|
||||
+ sizeof(ngx_http_lua_script_capture_code_t))
|
||||
+ sizeof(uintptr_t)
|
||||
+ sizeof(uintptr_t) - 1)
|
||||
& ~(sizeof(uintptr_t) - 1);
|
||||
|
||||
if (ngx_array_init(&values, ccv->pool, n, 1) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
pl = &lengths;
|
||||
pv = &values;
|
||||
|
||||
ngx_memzero(&sc, sizeof(ngx_http_lua_script_compile_t));
|
||||
|
||||
sc.pool = ccv->pool;
|
||||
sc.log = ccv->log;
|
||||
sc.source = v;
|
||||
sc.lengths = &pl;
|
||||
sc.values = &pv;
|
||||
sc.complete_lengths = 1;
|
||||
sc.complete_values = 1;
|
||||
|
||||
if (ngx_http_lua_script_compile(&sc) != NGX_OK) {
|
||||
ngx_array_destroy(&lengths);
|
||||
ngx_array_destroy(&values);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ccv->complex_value->lengths = lengths.elts;
|
||||
ccv->complex_value->values = values.elts;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_complex_value(ngx_http_request_t *r, ngx_str_t *subj,
|
||||
size_t offset, ngx_int_t count, int *cap,
|
||||
ngx_http_lua_complex_value_t *val, luaL_Buffer *luabuf)
|
||||
{
|
||||
size_t len;
|
||||
u_char *p;
|
||||
ngx_http_lua_script_code_pt code;
|
||||
ngx_http_lua_script_len_code_pt lcode;
|
||||
ngx_http_lua_script_engine_t e;
|
||||
|
||||
if (val->lengths == NULL) {
|
||||
luaL_addlstring(luabuf, (char *) &subj->data[offset], cap[0] - offset);
|
||||
luaL_addlstring(luabuf, (char *) val->value.data, val->value.len);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_memzero(&e, sizeof(ngx_http_lua_script_engine_t));
|
||||
|
||||
e.log = r->connection->log;
|
||||
e.ncaptures = count * 2;
|
||||
e.captures = cap;
|
||||
e.captures_data = subj->data;
|
||||
|
||||
e.ip = val->lengths;
|
||||
|
||||
len = 0;
|
||||
|
||||
while (*(uintptr_t *) e.ip) {
|
||||
lcode = *(ngx_http_lua_script_len_code_pt *) e.ip;
|
||||
len += lcode(&e);
|
||||
}
|
||||
|
||||
p = ngx_pnalloc(r->pool, len);
|
||||
if (p == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
e.ip = val->values;
|
||||
e.pos = p;
|
||||
|
||||
while (*(uintptr_t *) e.ip) {
|
||||
code = *(ngx_http_lua_script_code_pt *) e.ip;
|
||||
code((ngx_http_lua_script_engine_t *) &e);
|
||||
}
|
||||
|
||||
luaL_addlstring(luabuf, (char *) &subj->data[offset], cap[0] - offset);
|
||||
luaL_addlstring(luabuf, (char *) p, len);
|
||||
|
||||
ngx_pfree(r->pool, p);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_lua_script_compile(ngx_http_lua_script_compile_t *sc)
|
||||
{
|
||||
u_char ch;
|
||||
ngx_str_t name;
|
||||
ngx_uint_t i, bracket;
|
||||
unsigned num_var;
|
||||
ngx_uint_t n = 0;
|
||||
|
||||
if (ngx_http_lua_script_init_arrays(sc) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; i < sc->source->len; /* void */ ) {
|
||||
|
||||
name.len = 0;
|
||||
|
||||
if (sc->source->data[i] == '$') {
|
||||
|
||||
if (++i == sc->source->len) {
|
||||
goto invalid_variable;
|
||||
}
|
||||
|
||||
if (sc->source->data[i] == '$') {
|
||||
name.data = &sc->source->data[i];
|
||||
i++;
|
||||
name.len++;
|
||||
|
||||
if (ngx_http_lua_script_add_copy_code(sc, &name,
|
||||
(i == sc->source->len))
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sc->source->data[i] >= '0' && sc->source->data[i] <= '9') {
|
||||
num_var = 1;
|
||||
n = 0;
|
||||
|
||||
} else {
|
||||
num_var = 0;
|
||||
}
|
||||
|
||||
if (sc->source->data[i] == '{') {
|
||||
bracket = 1;
|
||||
|
||||
if (++i == sc->source->len) {
|
||||
goto invalid_variable;
|
||||
}
|
||||
|
||||
if (sc->source->data[i] >= '0' && sc->source->data[i] <= '9') {
|
||||
num_var = 1;
|
||||
n = 0;
|
||||
}
|
||||
|
||||
name.data = &sc->source->data[i];
|
||||
|
||||
} else {
|
||||
bracket = 0;
|
||||
name.data = &sc->source->data[i];
|
||||
}
|
||||
|
||||
for ( /* void */ ; i < sc->source->len; i++, name.len++) {
|
||||
ch = sc->source->data[i];
|
||||
|
||||
if (ch == '}' && bracket) {
|
||||
i++;
|
||||
bracket = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (num_var) {
|
||||
if (ch >= '0' && ch <= '9') {
|
||||
n = n * 10 + (ch - '0');
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* not a number variable like $1, $2, etc */
|
||||
|
||||
if ((ch >= 'A' && ch <= 'Z')
|
||||
|| (ch >= 'a' && ch <= 'z')
|
||||
|| (ch >= '0' && ch <= '9')
|
||||
|| ch == '_')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (bracket) {
|
||||
ngx_log_error(NGX_LOG_ERR, sc->log, 0,
|
||||
"the closing bracket in \"%V\" "
|
||||
"variable is missing", &name);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (name.len == 0) {
|
||||
goto invalid_variable;
|
||||
}
|
||||
|
||||
if (!num_var) {
|
||||
ngx_log_error(NGX_LOG_ERR, sc->log, 0,
|
||||
"attempt to use named capturing variable "
|
||||
"\"%V\" (named captures not supported yet)",
|
||||
&name);
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
sc->variables++;
|
||||
|
||||
if (ngx_http_lua_script_add_capture_code(sc, n) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
name.data = &sc->source->data[i];
|
||||
|
||||
while (i < sc->source->len) {
|
||||
|
||||
if (sc->source->data[i] == '$') {
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
name.len++;
|
||||
}
|
||||
|
||||
if (ngx_http_lua_script_add_copy_code(sc, &name, (i == sc->source->len))
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return ngx_http_lua_script_done(sc);
|
||||
|
||||
invalid_variable:
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, sc->log, 0,
|
||||
"lua script: invalid capturing variable name found in \"%V\"",
|
||||
sc->source);
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_lua_script_add_copy_code(ngx_http_lua_script_compile_t *sc,
|
||||
ngx_str_t *value, ngx_uint_t last)
|
||||
{
|
||||
size_t size, len;
|
||||
ngx_http_lua_script_copy_code_t *code;
|
||||
|
||||
len = value->len;
|
||||
|
||||
code = ngx_http_lua_script_add_code(*sc->lengths,
|
||||
sizeof(ngx_http_lua_script_copy_code_t));
|
||||
if (code == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
code->code = (ngx_http_lua_script_code_pt) (void *)
|
||||
ngx_http_lua_script_copy_len_code;
|
||||
code->len = len;
|
||||
|
||||
size = (sizeof(ngx_http_lua_script_copy_code_t) + len +
|
||||
sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1);
|
||||
|
||||
code = ngx_http_lua_script_add_code(*sc->values, size);
|
||||
if (code == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
code->code = ngx_http_lua_script_copy_code;
|
||||
code->len = len;
|
||||
|
||||
ngx_memcpy((u_char *) code + sizeof(ngx_http_lua_script_copy_code_t),
|
||||
value->data, value->len);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
ngx_http_lua_script_copy_len_code(ngx_http_lua_script_engine_t *e)
|
||||
{
|
||||
ngx_http_lua_script_copy_code_t *code;
|
||||
|
||||
code = (ngx_http_lua_script_copy_code_t *) e->ip;
|
||||
|
||||
e->ip += sizeof(ngx_http_lua_script_copy_code_t);
|
||||
|
||||
return code->len;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_http_lua_script_copy_code(ngx_http_lua_script_engine_t *e)
|
||||
{
|
||||
u_char *p;
|
||||
ngx_http_lua_script_copy_code_t *code;
|
||||
|
||||
code = (ngx_http_lua_script_copy_code_t *) e->ip;
|
||||
|
||||
p = e->pos;
|
||||
|
||||
if (!e->skip) {
|
||||
e->pos = ngx_copy(p, e->ip + sizeof(ngx_http_lua_script_copy_code_t),
|
||||
code->len);
|
||||
}
|
||||
|
||||
e->ip += sizeof(ngx_http_lua_script_copy_code_t)
|
||||
+ ((code->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1));
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->log, 0,
|
||||
"lua script copy: \"%*s\"", e->pos - p, p);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_lua_script_add_capture_code(ngx_http_lua_script_compile_t *sc,
|
||||
ngx_uint_t n)
|
||||
{
|
||||
ngx_http_lua_script_capture_code_t *code;
|
||||
|
||||
code = ngx_http_lua_script_add_code(*sc->lengths,
|
||||
sizeof(ngx_http_lua_script_capture_code_t));
|
||||
if (code == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
code->code = (ngx_http_lua_script_code_pt) (void *)
|
||||
ngx_http_lua_script_copy_capture_len_code;
|
||||
code->n = 2 * n;
|
||||
|
||||
code = ngx_http_lua_script_add_code(*sc->values,
|
||||
sizeof(ngx_http_lua_script_capture_code_t));
|
||||
if (code == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
code->code = ngx_http_lua_script_copy_capture_code;
|
||||
code->n = 2 * n;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
ngx_http_lua_script_copy_capture_len_code(ngx_http_lua_script_engine_t *e)
|
||||
{
|
||||
int *cap;
|
||||
ngx_uint_t n;
|
||||
ngx_http_lua_script_capture_code_t *code;
|
||||
|
||||
code = (ngx_http_lua_script_capture_code_t *) e->ip;
|
||||
|
||||
e->ip += sizeof(ngx_http_lua_script_capture_code_t);
|
||||
|
||||
n = code->n;
|
||||
|
||||
if (n < e->ncaptures) {
|
||||
cap = e->captures;
|
||||
return cap[n + 1] - cap[n];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_http_lua_script_copy_capture_code(ngx_http_lua_script_engine_t *e)
|
||||
{
|
||||
int *cap;
|
||||
u_char *p, *pos;
|
||||
ngx_uint_t n;
|
||||
ngx_http_lua_script_capture_code_t *code;
|
||||
|
||||
code = (ngx_http_lua_script_capture_code_t *) e->ip;
|
||||
|
||||
e->ip += sizeof(ngx_http_lua_script_capture_code_t);
|
||||
|
||||
n = code->n;
|
||||
|
||||
pos = e->pos;
|
||||
|
||||
if (n < e->ncaptures) {
|
||||
|
||||
cap = e->captures;
|
||||
p = e->captures_data;
|
||||
|
||||
e->pos = ngx_copy(pos, &p[cap[n]], cap[n + 1] - cap[n]);
|
||||
}
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->log, 0,
|
||||
"lua script capture: \"%*s\"", e->pos - pos, pos);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_lua_script_init_arrays(ngx_http_lua_script_compile_t *sc)
|
||||
{
|
||||
ngx_uint_t n;
|
||||
|
||||
if (*sc->lengths == NULL) {
|
||||
n = sc->variables * (2 * sizeof(ngx_http_lua_script_copy_code_t)
|
||||
+ sizeof(ngx_http_lua_script_capture_code_t))
|
||||
+ sizeof(uintptr_t);
|
||||
|
||||
*sc->lengths = ngx_array_create(sc->pool, n, 1);
|
||||
if (*sc->lengths == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (*sc->values == NULL) {
|
||||
n = (sc->variables * (2 * sizeof(ngx_http_lua_script_copy_code_t)
|
||||
+ sizeof(ngx_http_lua_script_capture_code_t))
|
||||
+ sizeof(uintptr_t)
|
||||
+ sizeof(uintptr_t) - 1)
|
||||
& ~(sizeof(uintptr_t) - 1);
|
||||
|
||||
*sc->values = ngx_array_create(sc->pool, n, 1);
|
||||
if (*sc->values == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
sc->variables = 0;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_lua_script_done(ngx_http_lua_script_compile_t *sc)
|
||||
{
|
||||
uintptr_t *code;
|
||||
|
||||
if (sc->complete_lengths) {
|
||||
code = ngx_http_lua_script_add_code(*sc->lengths, sizeof(uintptr_t));
|
||||
if (code == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
*code = (uintptr_t) NULL;
|
||||
}
|
||||
|
||||
if (sc->complete_values) {
|
||||
code = ngx_http_lua_script_add_code(*sc->values, sizeof(uintptr_t));
|
||||
if (code == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
*code = (uintptr_t) NULL;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static void *
|
||||
ngx_http_lua_script_add_code(ngx_array_t *codes, size_t size)
|
||||
{
|
||||
return ngx_array_push_n(codes, size);
|
||||
}
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,86 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_SCRIPT_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_SCRIPT_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_log_t *log;
|
||||
ngx_pool_t *pool;
|
||||
ngx_str_t *source;
|
||||
|
||||
ngx_array_t **lengths;
|
||||
ngx_array_t **values;
|
||||
|
||||
ngx_uint_t variables;
|
||||
|
||||
unsigned complete_lengths:1;
|
||||
unsigned complete_values:1;
|
||||
} ngx_http_lua_script_compile_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t value;
|
||||
void *lengths;
|
||||
void *values;
|
||||
} ngx_http_lua_complex_value_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_log_t *log;
|
||||
ngx_pool_t *pool;
|
||||
ngx_str_t *value;
|
||||
ngx_http_lua_complex_value_t *complex_value;
|
||||
} ngx_http_lua_compile_complex_value_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
u_char *ip;
|
||||
u_char *pos;
|
||||
|
||||
ngx_str_t buf;
|
||||
|
||||
int *captures;
|
||||
ngx_uint_t ncaptures;
|
||||
u_char *captures_data;
|
||||
|
||||
unsigned skip:1;
|
||||
|
||||
ngx_log_t *log;
|
||||
} ngx_http_lua_script_engine_t;
|
||||
|
||||
|
||||
typedef void (*ngx_http_lua_script_code_pt) (ngx_http_lua_script_engine_t *e);
|
||||
typedef size_t (*ngx_http_lua_script_len_code_pt)
|
||||
(ngx_http_lua_script_engine_t *e);
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_http_lua_script_code_pt code;
|
||||
uintptr_t len;
|
||||
} ngx_http_lua_script_copy_code_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_http_lua_script_code_pt code;
|
||||
uintptr_t n;
|
||||
} ngx_http_lua_script_capture_code_t;
|
||||
|
||||
|
||||
ngx_int_t ngx_http_lua_compile_complex_value(
|
||||
ngx_http_lua_compile_complex_value_t *ccv);
|
||||
ngx_int_t ngx_http_lua_complex_value(ngx_http_request_t *r, ngx_str_t *subj,
|
||||
size_t offset, ngx_int_t count, int *cap,
|
||||
ngx_http_lua_complex_value_t *val, luaL_Buffer *luabuf);
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_SCRIPT_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,580 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
* Copyright (C) cuiweixie
|
||||
* I hereby assign copyright in this code to the lua-nginx-module project,
|
||||
* to be licensed under the same terms as the rest of the code.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_http_lua_util.h"
|
||||
#include "ngx_http_lua_semaphore.h"
|
||||
#include "ngx_http_lua_contentby.h"
|
||||
|
||||
|
||||
ngx_int_t ngx_http_lua_sema_mm_init(ngx_conf_t *cf,
|
||||
ngx_http_lua_main_conf_t *lmcf);
|
||||
void ngx_http_lua_sema_mm_cleanup(void *data);
|
||||
static ngx_http_lua_sema_t *ngx_http_lua_alloc_sema(void);
|
||||
static void ngx_http_lua_free_sema(ngx_http_lua_sema_t *sem);
|
||||
static ngx_int_t ngx_http_lua_sema_resume(ngx_http_request_t *r);
|
||||
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_wait(ngx_http_request_t *r,
|
||||
ngx_http_lua_sema_t *sem, int wait_ms, u_char *err, size_t *errlen);
|
||||
static void ngx_http_lua_sema_cleanup(void *data);
|
||||
static void ngx_http_lua_sema_handler(ngx_event_t *ev);
|
||||
static void ngx_http_lua_sema_timeout_handler(ngx_event_t *ev);
|
||||
void ngx_http_lua_ffi_sema_gc(ngx_http_lua_sema_t *sem);
|
||||
|
||||
|
||||
enum {
|
||||
SEMAPHORE_WAIT_SUCC = 0,
|
||||
SEMAPHORE_WAIT_TIMEOUT = 1,
|
||||
};
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_sema_mm_init(ngx_conf_t *cf, ngx_http_lua_main_conf_t *lmcf)
|
||||
{
|
||||
ngx_http_lua_sema_mm_t *mm;
|
||||
|
||||
mm = ngx_palloc(cf->pool, sizeof(ngx_http_lua_sema_mm_t));
|
||||
if (mm == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
lmcf->sema_mm = mm;
|
||||
mm->lmcf = lmcf;
|
||||
|
||||
ngx_queue_init(&mm->free_queue);
|
||||
mm->cur_epoch = 0;
|
||||
mm->total = 0;
|
||||
mm->used = 0;
|
||||
|
||||
/* it's better to be 4096, but it needs some space for
|
||||
* ngx_http_lua_sema_mm_block_t, one is enough, so it is 4095
|
||||
*/
|
||||
mm->num_per_block = 4095;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_http_lua_sema_t *
|
||||
ngx_http_lua_alloc_sema(void)
|
||||
{
|
||||
ngx_uint_t i, n;
|
||||
ngx_queue_t *q;
|
||||
ngx_http_lua_sema_t *sem, *iter;
|
||||
ngx_http_lua_sema_mm_t *mm;
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
ngx_http_lua_sema_mm_block_t *block;
|
||||
|
||||
ngx_http_lua_assert(ngx_cycle && ngx_cycle->conf_ctx);
|
||||
|
||||
lmcf = ngx_http_cycle_get_module_main_conf(ngx_cycle,
|
||||
ngx_http_lua_module);
|
||||
|
||||
ngx_http_lua_assert(lmcf != NULL);
|
||||
|
||||
mm = lmcf->sema_mm;
|
||||
|
||||
if (!ngx_queue_empty(&mm->free_queue)) {
|
||||
q = ngx_queue_head(&mm->free_queue);
|
||||
ngx_queue_remove(q);
|
||||
|
||||
sem = ngx_queue_data(q, ngx_http_lua_sema_t, chain);
|
||||
|
||||
sem->block->used++;
|
||||
|
||||
ngx_memzero(&sem->sem_event, sizeof(ngx_event_t));
|
||||
|
||||
sem->sem_event.handler = ngx_http_lua_sema_handler;
|
||||
sem->sem_event.data = sem;
|
||||
sem->sem_event.log = ngx_cycle->log;
|
||||
|
||||
mm->used++;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
|
||||
"from head of free queue, alloc semaphore: %p", sem);
|
||||
|
||||
return sem;
|
||||
}
|
||||
|
||||
/* free_queue is empty */
|
||||
|
||||
n = sizeof(ngx_http_lua_sema_mm_block_t)
|
||||
+ mm->num_per_block * sizeof(ngx_http_lua_sema_t);
|
||||
|
||||
dd("block size: %d, item size: %d",
|
||||
(int) sizeof(ngx_http_lua_sema_mm_block_t),
|
||||
(int) sizeof(ngx_http_lua_sema_t));
|
||||
|
||||
block = ngx_alloc(n, ngx_cycle->log);
|
||||
if (block == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mm->cur_epoch++;
|
||||
mm->total += mm->num_per_block;
|
||||
mm->used++;
|
||||
|
||||
block->mm = mm;
|
||||
block->epoch = mm->cur_epoch;
|
||||
|
||||
sem = (ngx_http_lua_sema_t *) (block + 1);
|
||||
sem->block = block;
|
||||
sem->block->used = 1;
|
||||
|
||||
ngx_memzero(&sem->sem_event, sizeof(ngx_event_t));
|
||||
|
||||
sem->sem_event.handler = ngx_http_lua_sema_handler;
|
||||
sem->sem_event.data = sem;
|
||||
sem->sem_event.log = ngx_cycle->log;
|
||||
|
||||
for (iter = sem + 1, i = 1; i < mm->num_per_block; i++, iter++) {
|
||||
iter->block = block;
|
||||
ngx_queue_insert_tail(&mm->free_queue, &iter->chain);
|
||||
}
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
|
||||
"new block, alloc semaphore: %p block: %p", sem, block);
|
||||
|
||||
return sem;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_http_lua_sema_mm_cleanup(void *data)
|
||||
{
|
||||
ngx_uint_t i;
|
||||
ngx_queue_t *q;
|
||||
ngx_http_lua_sema_t *sem, *iter;
|
||||
ngx_http_lua_sema_mm_t *mm;
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
ngx_http_lua_sema_mm_block_t *block;
|
||||
|
||||
lmcf = (ngx_http_lua_main_conf_t *) data;
|
||||
mm = lmcf->sema_mm;
|
||||
|
||||
while (!ngx_queue_empty(&mm->free_queue)) {
|
||||
q = ngx_queue_head(&mm->free_queue);
|
||||
|
||||
sem = ngx_queue_data(q, ngx_http_lua_sema_t, chain);
|
||||
block = sem->block;
|
||||
|
||||
ngx_http_lua_assert(block != NULL);
|
||||
|
||||
if (block->used == 0) {
|
||||
iter = (ngx_http_lua_sema_t *) (block + 1);
|
||||
|
||||
for (i = 0; i < block->mm->num_per_block; i++, iter++) {
|
||||
ngx_queue_remove(&iter->chain);
|
||||
}
|
||||
|
||||
dd("free sema block: %p at final", block);
|
||||
|
||||
ngx_free(block);
|
||||
|
||||
} else {
|
||||
/* just return directly when some thing goes wrong */
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
|
||||
"lua sema mm: freeing a block %p that is still "
|
||||
" used by someone", block);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dd("lua sema mm cleanup done");
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_http_lua_free_sema(ngx_http_lua_sema_t *sem)
|
||||
{
|
||||
ngx_http_lua_sema_t *iter;
|
||||
ngx_uint_t i, mid_epoch;
|
||||
ngx_http_lua_sema_mm_block_t *block;
|
||||
ngx_http_lua_sema_mm_t *mm;
|
||||
|
||||
block = sem->block;
|
||||
block->used--;
|
||||
|
||||
mm = block->mm;
|
||||
mm->used--;
|
||||
|
||||
mid_epoch = mm->cur_epoch - ((mm->total / mm->num_per_block) >> 1);
|
||||
|
||||
if (block->epoch < mid_epoch) {
|
||||
ngx_queue_insert_tail(&mm->free_queue, &sem->chain);
|
||||
ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
|
||||
"add to free queue tail semaphore: %p epoch: %d"
|
||||
"mid_epoch: %d cur_epoch: %d", sem, (int) block->epoch,
|
||||
(int) mid_epoch, (int) mm->cur_epoch);
|
||||
|
||||
} else {
|
||||
ngx_queue_insert_head(&mm->free_queue, &sem->chain);
|
||||
ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
|
||||
"add to free queue head semaphore: %p epoch: %d"
|
||||
"mid_epoch: %d cur_epoch: %d", sem, (int) block->epoch,
|
||||
(int) mid_epoch, (int) mm->cur_epoch);
|
||||
}
|
||||
|
||||
dd("used: %d", (int) block->used);
|
||||
|
||||
if (block->used == 0
|
||||
&& mm->used <= (mm->total >> 1)
|
||||
&& block->epoch < mid_epoch)
|
||||
{
|
||||
/* load <= 50% and it's on the older side */
|
||||
iter = (ngx_http_lua_sema_t *) (block + 1);
|
||||
|
||||
for (i = 0; i < mm->num_per_block; i++, iter++) {
|
||||
ngx_queue_remove(&iter->chain);
|
||||
}
|
||||
|
||||
mm->total -= mm->num_per_block;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
|
||||
"free semaphore block: %p", block);
|
||||
|
||||
ngx_free(block);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_lua_sema_resume(ngx_http_request_t *r)
|
||||
{
|
||||
lua_State *vm;
|
||||
ngx_connection_t *c;
|
||||
ngx_int_t rc;
|
||||
ngx_uint_t nreqs;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ctx->resume_handler = ngx_http_lua_wev_handler;
|
||||
|
||||
c = r->connection;
|
||||
vm = ngx_http_lua_get_lua_vm(r, ctx);
|
||||
nreqs = c->requests;
|
||||
|
||||
if (ctx->cur_co_ctx->sem_resume_status == SEMAPHORE_WAIT_SUCC) {
|
||||
lua_pushboolean(ctx->cur_co_ctx->co, 1);
|
||||
lua_pushnil(ctx->cur_co_ctx->co);
|
||||
|
||||
} else {
|
||||
lua_pushboolean(ctx->cur_co_ctx->co, 0);
|
||||
lua_pushliteral(ctx->cur_co_ctx->co, "timeout");
|
||||
}
|
||||
|
||||
rc = ngx_http_lua_run_thread(vm, r, ctx, 2);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua run thread returned %d", rc);
|
||||
|
||||
if (rc == NGX_AGAIN) {
|
||||
return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs);
|
||||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
ngx_http_lua_finalize_request(r, NGX_DONE);
|
||||
return ngx_http_lua_run_posted_threads(c, vm, r, ctx, nreqs);
|
||||
}
|
||||
|
||||
/* rc == NGX_ERROR || rc >= NGX_OK */
|
||||
|
||||
if (ctx->entered_content_phase) {
|
||||
ngx_http_lua_finalize_request(r, rc);
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_sema_new(ngx_http_lua_sema_t **psem,
|
||||
int n, char **errmsg)
|
||||
{
|
||||
ngx_http_lua_sema_t *sem;
|
||||
|
||||
sem = ngx_http_lua_alloc_sema();
|
||||
if (sem == NULL) {
|
||||
*errmsg = "no memory";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_queue_init(&sem->wait_queue);
|
||||
|
||||
sem->resource_count = n;
|
||||
sem->wait_count = 0;
|
||||
*psem = sem;
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
|
||||
"http lua semaphore new: %p, resources: %d",
|
||||
sem, sem->resource_count);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_sema_post(ngx_http_lua_sema_t *sem, int n)
|
||||
{
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
|
||||
"http lua semaphore post: %p, n: %d, resources: %d",
|
||||
sem, n, sem->resource_count);
|
||||
|
||||
sem->resource_count += n;
|
||||
|
||||
if (!ngx_queue_empty(&sem->wait_queue)) {
|
||||
/* we need the extra parentheses around the first argument of
|
||||
* ngx_post_event() just to work around macro issues in nginx
|
||||
* cores older than nginx 1.7.12 (exclusive).
|
||||
*/
|
||||
ngx_post_event((&sem->sem_event), &ngx_posted_events);
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_sema_wait(ngx_http_request_t *r,
|
||||
ngx_http_lua_sema_t *sem, int wait_ms, u_char *err, size_t *errlen)
|
||||
{
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_http_lua_co_ctx_t *wait_co_ctx;
|
||||
ngx_int_t rc;
|
||||
|
||||
ngx_log_debug4(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
|
||||
"http lua semaphore wait: %p, timeout: %d, "
|
||||
"resources: %d, event posted: %d",
|
||||
sem, wait_ms, sem->resource_count,
|
||||
#if (nginx_version >= 1007005)
|
||||
(int) sem->sem_event.posted
|
||||
#else
|
||||
sem->sem_event.prev ? 1 : 0
|
||||
#endif
|
||||
);
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
if (ctx == NULL) {
|
||||
*errlen = ngx_snprintf(err, *errlen, "no request ctx found") - err;
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
rc = ngx_http_lua_ffi_check_context(ctx, NGX_HTTP_LUA_CONTEXT_YIELDABLE,
|
||||
err, errlen);
|
||||
|
||||
if (rc != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
/* we keep the order, will first resume the thread waiting for the
|
||||
* longest time in ngx_http_lua_sema_handler
|
||||
*/
|
||||
|
||||
if (ngx_queue_empty(&sem->wait_queue) && sem->resource_count > 0) {
|
||||
sem->resource_count--;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (wait_ms == 0) {
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
sem->wait_count++;
|
||||
wait_co_ctx = ctx->cur_co_ctx;
|
||||
|
||||
wait_co_ctx->sleep.handler = ngx_http_lua_sema_timeout_handler;
|
||||
wait_co_ctx->sleep.data = ctx->cur_co_ctx;
|
||||
wait_co_ctx->sleep.log = r->connection->log;
|
||||
|
||||
ngx_add_timer(&wait_co_ctx->sleep, (ngx_msec_t) wait_ms);
|
||||
|
||||
dd("ngx_http_lua_ffi_sema_wait add timer coctx:%p wait: %d(ms)",
|
||||
wait_co_ctx, wait_ms);
|
||||
|
||||
ngx_queue_insert_tail(&sem->wait_queue, &wait_co_ctx->sem_wait_queue);
|
||||
|
||||
wait_co_ctx->data = sem;
|
||||
wait_co_ctx->cleanup = ngx_http_lua_sema_cleanup;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
|
||||
"http lua semaphore wait yielding");
|
||||
|
||||
return NGX_AGAIN;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_http_lua_ffi_sema_count(ngx_http_lua_sema_t *sem)
|
||||
{
|
||||
return sem->resource_count - sem->wait_count;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_http_lua_sema_cleanup(void *data)
|
||||
{
|
||||
ngx_http_lua_co_ctx_t *coctx = data;
|
||||
ngx_queue_t *q;
|
||||
ngx_http_lua_sema_t *sem;
|
||||
|
||||
sem = coctx->data;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
|
||||
"http lua semaphore cleanup");
|
||||
|
||||
if (coctx->sleep.timer_set) {
|
||||
ngx_del_timer(&coctx->sleep);
|
||||
}
|
||||
|
||||
q = &coctx->sem_wait_queue;
|
||||
|
||||
ngx_queue_remove(q);
|
||||
sem->wait_count--;
|
||||
coctx->cleanup = NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_http_lua_sema_handler(ngx_event_t *ev)
|
||||
{
|
||||
ngx_http_lua_sema_t *sem;
|
||||
ngx_http_request_t *r;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_http_lua_co_ctx_t *wait_co_ctx;
|
||||
ngx_connection_t *c;
|
||||
ngx_queue_t *q;
|
||||
|
||||
sem = ev->data;
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
|
||||
"semaphore handler: wait queue: %sempty, resource count: %d",
|
||||
ngx_queue_empty(&sem->wait_queue) ? "" : "not ",
|
||||
sem->resource_count);
|
||||
while (!ngx_queue_empty(&sem->wait_queue) && sem->resource_count > 0) {
|
||||
q = ngx_queue_head(&sem->wait_queue);
|
||||
ngx_queue_remove(q);
|
||||
|
||||
sem->wait_count--;
|
||||
|
||||
wait_co_ctx = ngx_queue_data(q, ngx_http_lua_co_ctx_t, sem_wait_queue);
|
||||
wait_co_ctx->cleanup = NULL;
|
||||
|
||||
if (wait_co_ctx->sleep.timer_set) {
|
||||
ngx_del_timer(&wait_co_ctx->sleep);
|
||||
}
|
||||
|
||||
r = ngx_http_lua_get_req(wait_co_ctx->co);
|
||||
c = r->connection;
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
ngx_http_lua_assert(ctx != NULL);
|
||||
|
||||
sem->resource_count--;
|
||||
|
||||
ctx->cur_co_ctx = wait_co_ctx;
|
||||
|
||||
wait_co_ctx->sem_resume_status = SEMAPHORE_WAIT_SUCC;
|
||||
|
||||
if (ctx->entered_content_phase) {
|
||||
(void) ngx_http_lua_sema_resume(r);
|
||||
|
||||
} else {
|
||||
ctx->resume_handler = ngx_http_lua_sema_resume;
|
||||
ngx_http_core_run_phases(r);
|
||||
}
|
||||
|
||||
ngx_http_run_posted_requests(c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_http_lua_sema_timeout_handler(ngx_event_t *ev)
|
||||
{
|
||||
ngx_http_lua_co_ctx_t *wait_co_ctx;
|
||||
ngx_http_request_t *r;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_connection_t *c;
|
||||
ngx_http_lua_sema_t *sem;
|
||||
|
||||
wait_co_ctx = ev->data;
|
||||
wait_co_ctx->cleanup = NULL;
|
||||
|
||||
dd("ngx_http_lua_sema_timeout_handler timeout coctx:%p", wait_co_ctx);
|
||||
|
||||
sem = wait_co_ctx->data;
|
||||
|
||||
ngx_queue_remove(&wait_co_ctx->sem_wait_queue);
|
||||
sem->wait_count--;
|
||||
|
||||
r = ngx_http_lua_get_req(wait_co_ctx->co);
|
||||
c = r->connection;
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
ngx_http_lua_assert(ctx != NULL);
|
||||
|
||||
ctx->cur_co_ctx = wait_co_ctx;
|
||||
|
||||
wait_co_ctx->sem_resume_status = SEMAPHORE_WAIT_TIMEOUT;
|
||||
|
||||
if (ctx->entered_content_phase) {
|
||||
(void) ngx_http_lua_sema_resume(r);
|
||||
|
||||
} else {
|
||||
ctx->resume_handler = ngx_http_lua_sema_resume;
|
||||
ngx_http_core_run_phases(r);
|
||||
}
|
||||
|
||||
ngx_http_run_posted_requests(c);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_http_lua_ffi_sema_gc(ngx_http_lua_sema_t *sem)
|
||||
{
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
|
||||
"in lua gc, semaphore %p", sem);
|
||||
|
||||
if (sem == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ngx_terminate
|
||||
&& !ngx_quit
|
||||
&& !ngx_queue_empty(&sem->wait_queue))
|
||||
{
|
||||
ngx_log_error(NGX_LOG_ERR, ngx_cycle->log, 0,
|
||||
"in lua semaphore gc wait queue is"
|
||||
" not empty while the semaphore %p is being "
|
||||
"destroyed", sem);
|
||||
}
|
||||
|
||||
if (sem->sem_event.posted) {
|
||||
ngx_delete_posted_event(&sem->sem_event);
|
||||
}
|
||||
|
||||
ngx_http_lua_free_sema(sem);
|
||||
}
|
||||
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,51 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
* Copyright (C) cuiweixie
|
||||
* I hereby assign copyright in this code to the lua-nginx-module project,
|
||||
* to be licensed under the same terms as the rest of the code.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_SEMAPHORE_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_SEMAPHORE_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
typedef struct ngx_http_lua_sema_mm_block_s {
|
||||
ngx_uint_t used;
|
||||
ngx_http_lua_sema_mm_t *mm;
|
||||
ngx_uint_t epoch;
|
||||
} ngx_http_lua_sema_mm_block_t;
|
||||
|
||||
|
||||
struct ngx_http_lua_sema_mm_s {
|
||||
ngx_queue_t free_queue;
|
||||
ngx_uint_t total;
|
||||
ngx_uint_t used;
|
||||
ngx_uint_t num_per_block;
|
||||
ngx_uint_t cur_epoch;
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
};
|
||||
|
||||
|
||||
typedef struct ngx_http_lua_sema_s {
|
||||
ngx_queue_t wait_queue;
|
||||
ngx_queue_t chain;
|
||||
ngx_event_t sem_event;
|
||||
ngx_http_lua_sema_mm_block_t *block;
|
||||
int resource_count;
|
||||
unsigned wait_count;
|
||||
} ngx_http_lua_sema_t;
|
||||
|
||||
|
||||
void ngx_http_lua_sema_mm_cleanup(void *data);
|
||||
ngx_int_t ngx_http_lua_sema_mm_init(ngx_conf_t *cf,
|
||||
ngx_http_lua_main_conf_t *lmcf);
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_SEMAPHORE_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,339 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
#include <nginx.h>
|
||||
#include "ngx_http_lua_server_rewriteby.h"
|
||||
#include "ngx_http_lua_util.h"
|
||||
#include "ngx_http_lua_exception.h"
|
||||
#include "ngx_http_lua_cache.h"
|
||||
|
||||
static ngx_int_t ngx_http_lua_server_rewrite_by_chunk(lua_State *L,
|
||||
ngx_http_request_t *r);
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_server_rewrite_handler(ngx_http_request_t *r)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
lua_State *L;
|
||||
ngx_http_lua_srv_conf_t *lscf;
|
||||
ngx_http_lua_loc_conf_t *llcf;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
|
||||
/* XXX we need to take into account ngx_rewrite's location dump */
|
||||
if (r->uri_changed) {
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||
"lua server rewrite handler, uri:\"%V\" c:%ud", &r->uri,
|
||||
r->main->count);
|
||||
|
||||
lscf = ngx_http_get_module_srv_conf(r, ngx_http_lua_module);
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
L = ngx_http_lua_get_lua_vm(r, NULL);
|
||||
|
||||
if (lscf->srv.server_rewrite_handler == NULL) {
|
||||
dd("no rewrite handler found");
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
|
||||
dd("ctx = %p", ctx);
|
||||
|
||||
if (ctx == NULL) {
|
||||
ctx = ngx_http_lua_create_ctx(r);
|
||||
if (ctx == NULL) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
dd("entered? %d", (int) ctx->entered_server_rewrite_phase);
|
||||
|
||||
if (ctx->entered_server_rewrite_phase) {
|
||||
dd("rewriteby: calling wev handler");
|
||||
rc = ctx->resume_handler(r);
|
||||
dd("rewriteby: wev handler returns %d", (int) rc);
|
||||
|
||||
if (rc == NGX_OK) {
|
||||
rc = NGX_DECLINED;
|
||||
}
|
||||
|
||||
if (rc == NGX_DECLINED) {
|
||||
if (r->header_sent) {
|
||||
dd("header already sent");
|
||||
|
||||
/* response header was already generated in rewrite_by_lua*,
|
||||
* so it is no longer safe to proceed to later phases
|
||||
* which may generate responses again */
|
||||
|
||||
if (!ctx->eof) {
|
||||
dd("eof not yet sent");
|
||||
|
||||
rc = ngx_http_lua_send_chain_link(r, ctx, NULL
|
||||
/* indicate last_buf */);
|
||||
if (rc == NGX_ERROR || rc > NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_HTTP_OK;
|
||||
}
|
||||
|
||||
r->write_event_handler = ngx_http_core_run_phases;
|
||||
ctx->entered_server_rewrite_phase = 0;
|
||||
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (ctx->waiting_more_body) {
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
/* TODO: lscf do not have force_read_body */
|
||||
if (llcf->force_read_body && !ctx->read_body_done) {
|
||||
r->request_body_in_single_buf = 1;
|
||||
r->request_body_in_persistent_file = 1;
|
||||
r->request_body_in_clean_file = 1;
|
||||
|
||||
rc = ngx_http_read_client_request_body(r,
|
||||
ngx_http_lua_generic_phase_post_read);
|
||||
|
||||
if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (rc == NGX_AGAIN) {
|
||||
ctx->waiting_more_body = 1;
|
||||
return NGX_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
dd("calling server rewrite handler");
|
||||
return lscf->srv.server_rewrite_handler(r, lscf, L);
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_server_rewrite_handler_inline(ngx_http_request_t *r,
|
||||
ngx_http_lua_srv_conf_t *lscf, lua_State *L)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
|
||||
dd("server_rewrite by lua inline");
|
||||
|
||||
|
||||
/* load Lua inline script (w/ cache) sp = 1 */
|
||||
rc = ngx_http_lua_cache_loadbuffer(r->connection->log, L,
|
||||
lscf->srv.server_rewrite_src.value.data,
|
||||
lscf->srv.server_rewrite_src.value.len,
|
||||
&lscf->srv.server_rewrite_src_ref,
|
||||
lscf->srv.server_rewrite_src_key,
|
||||
(const char *)
|
||||
lscf->srv.server_rewrite_chunkname);
|
||||
if (rc != NGX_OK) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
return ngx_http_lua_server_rewrite_by_chunk(L, r);
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_server_rewrite_handler_file(ngx_http_request_t *r,
|
||||
ngx_http_lua_srv_conf_t *lscf, lua_State *L)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
u_char *script_path;
|
||||
ngx_str_t eval_src;
|
||||
|
||||
|
||||
if (ngx_http_complex_value(r, &lscf->srv.server_rewrite_src,
|
||||
&eval_src) != NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
script_path = ngx_http_lua_rebase_path(r->pool, eval_src.data,
|
||||
eval_src.len);
|
||||
|
||||
if (script_path == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
/* load Lua script file (w/ cache) sp = 1 */
|
||||
rc = ngx_http_lua_cache_loadfile(r->connection->log, L, script_path,
|
||||
&lscf->srv.server_rewrite_src_ref,
|
||||
lscf->srv.server_rewrite_src_key);
|
||||
if (rc != NGX_OK) {
|
||||
if (rc < NGX_HTTP_SPECIAL_RESPONSE) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
return ngx_http_lua_server_rewrite_by_chunk(L, r);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_http_lua_server_rewrite_by_chunk(lua_State *L, ngx_http_request_t *r)
|
||||
{
|
||||
int co_ref;
|
||||
lua_State *co;
|
||||
ngx_int_t rc;
|
||||
ngx_uint_t nreqs;
|
||||
ngx_event_t *rev;
|
||||
ngx_connection_t *c;
|
||||
ngx_http_lua_ctx_t *ctx;
|
||||
ngx_pool_cleanup_t *cln;
|
||||
|
||||
ngx_http_lua_loc_conf_t *llcf;
|
||||
|
||||
/* {{{ new coroutine to handle request */
|
||||
co = ngx_http_lua_new_thread(r, L, &co_ref);
|
||||
|
||||
if (co == NULL) {
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"lua: failed to create new coroutine to handle request");
|
||||
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
/* move code closure to new coroutine */
|
||||
lua_xmove(L, co, 1);
|
||||
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
/* set closure's env table to new coroutine's globals table */
|
||||
ngx_http_lua_get_globals_table(co);
|
||||
lua_setfenv(co, -2);
|
||||
#endif
|
||||
|
||||
/* save nginx request in coroutine globals table */
|
||||
ngx_http_lua_set_req(co, r);
|
||||
|
||||
/* {{{ initialize request context */
|
||||
ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module);
|
||||
|
||||
dd("ctx = %p", ctx);
|
||||
|
||||
if (ctx == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_http_lua_reset_ctx(r, L, ctx);
|
||||
|
||||
ctx->entered_server_rewrite_phase = 1;
|
||||
|
||||
ctx->cur_co_ctx = &ctx->entry_co_ctx;
|
||||
ctx->cur_co_ctx->co = co;
|
||||
ctx->cur_co_ctx->co_ref = co_ref;
|
||||
#ifdef NGX_LUA_USE_ASSERT
|
||||
ctx->cur_co_ctx->co_top = 1;
|
||||
#endif
|
||||
|
||||
ngx_http_lua_attach_co_ctx_to_L(co, ctx->cur_co_ctx);
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* {{{ register request cleanup hooks */
|
||||
if (ctx->cleanup == NULL) {
|
||||
cln = ngx_pool_cleanup_add(r->pool, 0);
|
||||
if (cln == NULL) {
|
||||
return NGX_HTTP_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
cln->handler = ngx_http_lua_request_cleanup_handler;
|
||||
cln->data = ctx;
|
||||
ctx->cleanup = &cln->handler;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
ctx->context = NGX_HTTP_LUA_CONTEXT_SERVER_REWRITE;
|
||||
|
||||
llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module);
|
||||
|
||||
if (llcf->check_client_abort) {
|
||||
r->read_event_handler = ngx_http_lua_rd_check_broken_connection;
|
||||
|
||||
#if (NGX_HTTP_V2)
|
||||
if (!r->stream) {
|
||||
#endif
|
||||
|
||||
rev = r->connection->read;
|
||||
|
||||
if (!rev->active) {
|
||||
if (ngx_add_event(rev, NGX_READ_EVENT, 0) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
#if (NGX_HTTP_V2)
|
||||
}
|
||||
#endif
|
||||
|
||||
} else {
|
||||
r->read_event_handler = ngx_http_block_reading;
|
||||
}
|
||||
|
||||
c = r->connection;
|
||||
nreqs = c->requests;
|
||||
|
||||
rc = ngx_http_lua_run_thread(L, r, ctx, 0);
|
||||
|
||||
if (rc == NGX_ERROR || rc > NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (rc == NGX_AGAIN) {
|
||||
rc = ngx_http_lua_run_posted_threads(c, L, r, ctx, nreqs);
|
||||
|
||||
} else if (rc == NGX_DONE) {
|
||||
ngx_http_lua_finalize_request(r, NGX_DONE);
|
||||
rc = ngx_http_lua_run_posted_threads(c, L, r, ctx, nreqs);
|
||||
}
|
||||
|
||||
if (rc == NGX_OK || rc == NGX_DECLINED) {
|
||||
if (r->header_sent) {
|
||||
dd("header already sent");
|
||||
|
||||
/* response header was already generated in rewrite_by_lua*,
|
||||
* so it is no longer safe to proceed to later phases
|
||||
* which may generate responses again */
|
||||
|
||||
if (!ctx->eof) {
|
||||
dd("eof not yet sent");
|
||||
|
||||
rc = ngx_http_lua_send_chain_link(r, ctx, NULL
|
||||
/* indicate last_buf */);
|
||||
if (rc == NGX_ERROR || rc > NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_HTTP_OK;
|
||||
}
|
||||
|
||||
r->write_event_handler = ngx_http_core_run_phases;
|
||||
ctx->entered_server_rewrite_phase = 0;
|
||||
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
#ifndef _NGX_HTTP_LUA_SERVER_REWRITEBY_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_SERVER_REWRITEBY_H_INCLUDED_
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
ngx_int_t ngx_http_lua_server_rewrite_handler(ngx_http_request_t *r);
|
||||
ngx_int_t ngx_http_lua_server_rewrite_handler_inline(ngx_http_request_t *r,
|
||||
ngx_http_lua_srv_conf_t *lscf, lua_State *L);
|
||||
ngx_int_t ngx_http_lua_server_rewrite_handler_file(ngx_http_request_t *r,
|
||||
ngx_http_lua_srv_conf_t *lscf, lua_State *L);
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_SERVER_REWRITEBY_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,207 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_http_lua_setby.h"
|
||||
#include "ngx_http_lua_exception.h"
|
||||
#include "ngx_http_lua_util.h"
|
||||
#include "ngx_http_lua_pcrefix.h"
|
||||
#include "ngx_http_lua_log.h"
|
||||
#include "ngx_http_lua_string.h"
|
||||
#include "ngx_http_lua_misc.h"
|
||||
#include "ngx_http_lua_consts.h"
|
||||
#include "ngx_http_lua_shdict.h"
|
||||
#include "ngx_http_lua_util.h"
|
||||
|
||||
|
||||
static void ngx_http_lua_set_by_lua_env(lua_State *L, ngx_http_request_t *r,
|
||||
size_t nargs, ngx_http_variable_value_t *args);
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_http_lua_set_by_chunk(lua_State *L, ngx_http_request_t *r, ngx_str_t *val,
|
||||
ngx_http_variable_value_t *args, size_t nargs, ngx_str_t *script)
|
||||
{
|
||||
size_t i;
|
||||
ngx_int_t rc;
|
||||
u_char *err_msg;
|
||||
size_t len;
|
||||
u_char *data;
|
||||
#if (NGX_PCRE)
|
||||
ngx_pool_t *old_pool;
|
||||
#endif
|
||||
|
||||
dd("nargs: %d", (int) nargs);
|
||||
|
||||
dd("set Lua VM panic handler");
|
||||
|
||||
lua_atpanic(L, ngx_http_lua_atpanic);
|
||||
|
||||
NGX_LUA_EXCEPTION_TRY {
|
||||
dd("initialize nginx context in Lua VM, code chunk at "
|
||||
"stack top sp = 1");
|
||||
ngx_http_lua_set_by_lua_env(L, r, nargs, args);
|
||||
|
||||
/* passing directive arguments to the user code */
|
||||
for (i = 0; i < nargs; i++) {
|
||||
lua_pushlstring(L, (const char *) args[i].data, args[i].len);
|
||||
}
|
||||
|
||||
#if (NGX_PCRE)
|
||||
/* XXX: work-around to nginx regex subsystem */
|
||||
old_pool = ngx_http_lua_pcre_malloc_init(r->pool);
|
||||
#endif
|
||||
|
||||
lua_pushcfunction(L, ngx_http_lua_traceback);
|
||||
lua_insert(L, 1); /* put it under chunk and args */
|
||||
|
||||
dd("protected call user code");
|
||||
|
||||
rc = lua_pcall(L, nargs, 1, 1);
|
||||
|
||||
dd("after protected call user code");
|
||||
|
||||
lua_remove(L, 1); /* remove traceback function */
|
||||
|
||||
#if (NGX_PCRE)
|
||||
/* XXX: work-around to nginx regex subsystem */
|
||||
ngx_http_lua_pcre_malloc_done(old_pool);
|
||||
#endif
|
||||
|
||||
if (rc != 0) {
|
||||
/* error occurred when running loaded code */
|
||||
err_msg = (u_char *) lua_tolstring(L, -1, &len);
|
||||
|
||||
if (err_msg == NULL) {
|
||||
err_msg = (u_char *) "unknown reason";
|
||||
len = sizeof("unknown reason") - 1;
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"failed to run set_by_lua*: %*s", len, err_msg);
|
||||
|
||||
lua_settop(L, 0); /* clear remaining elems on stack */
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
data = (u_char *) lua_tolstring(L, -1, &len);
|
||||
|
||||
if (data) {
|
||||
val->data = ngx_palloc(r->pool, len);
|
||||
if (val->data == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_memcpy(val->data, data, len);
|
||||
val->len = len;
|
||||
|
||||
} else {
|
||||
val->data = NULL;
|
||||
val->len = 0;
|
||||
}
|
||||
|
||||
} NGX_LUA_EXCEPTION_CATCH {
|
||||
|
||||
dd("nginx execution restored");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
/* clear Lua stack */
|
||||
lua_settop(L, 0);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_http_lua_ffi_get_setby_param(ngx_http_request_t *r, int idx,
|
||||
u_char **data_p, size_t *len_p)
|
||||
{
|
||||
int n;
|
||||
|
||||
ngx_http_variable_value_t *v;
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
|
||||
idx--;
|
||||
|
||||
lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
|
||||
|
||||
/* get number of args from lmcf */
|
||||
n = lmcf->setby_nargs;
|
||||
|
||||
/* get args from lmcf */
|
||||
v = lmcf->setby_args;
|
||||
|
||||
if (idx < 0 || idx > n - 1) {
|
||||
*len_p = 0;
|
||||
|
||||
} else {
|
||||
*data_p = v[idx].data;
|
||||
*len_p = v[idx].len;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set environment table for the given code closure.
|
||||
*
|
||||
* Before:
|
||||
* | code closure | <- top
|
||||
* | ... |
|
||||
*
|
||||
* After:
|
||||
* | code closure | <- top
|
||||
* | ... |
|
||||
* */
|
||||
static void
|
||||
ngx_http_lua_set_by_lua_env(lua_State *L, ngx_http_request_t *r, size_t nargs,
|
||||
ngx_http_variable_value_t *args)
|
||||
{
|
||||
ngx_http_lua_main_conf_t *lmcf;
|
||||
|
||||
ngx_http_lua_set_req(L, r);
|
||||
|
||||
lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module);
|
||||
|
||||
lmcf->setby_nargs = nargs;
|
||||
lmcf->setby_args = args;
|
||||
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
/**
|
||||
* we want to create empty environment for current script
|
||||
*
|
||||
* newt = {}
|
||||
* newt["_G"] = newt
|
||||
* setmetatable(newt, {__index = _G})
|
||||
*
|
||||
* if a function or symbol is not defined in our env, __index will lookup
|
||||
* in the global env.
|
||||
*
|
||||
* all variables created in the script-env will be thrown away at the end
|
||||
* of the script run.
|
||||
* */
|
||||
ngx_http_lua_create_new_globals_table(L, 0 /* narr */, 1 /* nrec */);
|
||||
|
||||
/* {{{ make new env inheriting main thread's globals table */
|
||||
/* the metatable for the new env */
|
||||
lua_createtable(L, 0 /* narr */, 1 /* nrec */);
|
||||
ngx_http_lua_get_globals_table(L);
|
||||
lua_setfield(L, -2, "__index");
|
||||
lua_setmetatable(L, -2); /* setmetatable(newt, {__index = _G}) */
|
||||
/* }}} */
|
||||
|
||||
lua_setfenv(L, -2); /* set new running env for the code closure */
|
||||
#endif
|
||||
}
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef _NGX_HTTP_LUA_SET_BY_H_INCLUDED_
|
||||
#define _NGX_HTTP_LUA_SET_BY_H_INCLUDED_
|
||||
|
||||
#include "ngx_http_lua_common.h"
|
||||
|
||||
|
||||
ngx_int_t ngx_http_lua_set_by_chunk(lua_State *L, ngx_http_request_t *r,
|
||||
ngx_str_t *val, ngx_http_variable_value_t *args, size_t nargs,
|
||||
ngx_str_t *script);
|
||||
|
||||
|
||||
#endif /* _NGX_HTTP_LUA_SET_BY_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue