Squashed 'src/deps/src/stream-lua-nginx-module/' content from commit 309198abf
git-subtree-dir: src/deps/src/stream-lua-nginx-module git-subtree-split: 309198abf26266f1a3e53c71388ed7bb9d1e5ea2
This commit is contained in:
commit
2ab324a69f
|
@ -0,0 +1 @@
|
|||
*.t linguist-language=Text
|
|
@ -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,78 @@
|
|||
*~
|
||||
*.swp
|
||||
*.swo
|
||||
*.bak
|
||||
nginx
|
||||
buildroot/
|
||||
lua
|
||||
tags
|
||||
build19
|
||||
ctags
|
||||
*.tags
|
||||
src/contentby.[ch]
|
||||
src/common.h
|
||||
src/util.[ch]
|
||||
src/directive.[ch]
|
||||
src/lex.[ch]
|
||||
src/module.c
|
||||
src/cache.[ch]
|
||||
src/clfactory.[ch]
|
||||
src/tcp.[ch]
|
||||
src/exception.[ch]
|
||||
src/pcrefix.[ch]
|
||||
src/uthread.[ch]
|
||||
src/coroutine.[ch]
|
||||
src/semaphore.[ch]
|
||||
src/output.[ch]
|
||||
src/consts.[ch]
|
||||
src/string.[ch]
|
||||
src/log.[ch]
|
||||
src/time.[ch]
|
||||
src/control.[ch]
|
||||
src/sleep.[ch]
|
||||
src/phase.[ch]
|
||||
src/ctx.[ch]
|
||||
src/regex.[ch]
|
||||
src/script.[ch]
|
||||
src/shdict.[ch]
|
||||
src/udp.[ch]
|
||||
src/timer.[ch]
|
||||
src/config.[ch]
|
||||
src/worker.[ch]
|
||||
src/misc.[ch]
|
||||
src/initby.[ch]
|
||||
src/shdict.[ch]
|
||||
src/initworkerby.[ch]
|
||||
src/variable.[ch]
|
||||
src/args.[ch]
|
||||
echo
|
||||
reindex
|
||||
go
|
||||
t/servroot*
|
||||
*.plist
|
||||
Makefile
|
||||
t/*.t_
|
||||
html_out/
|
||||
ebooks.sh
|
||||
*.pdf
|
||||
*.patch
|
||||
src/ngx_stream_lua_autoconf.h
|
||||
src/api.c
|
||||
src/autoconf.h
|
||||
src/balancer.c
|
||||
src/balancer.h
|
||||
src/certby.c
|
||||
src/certby.h
|
||||
src/filters.c
|
||||
src/filters.h
|
||||
src/logby.c
|
||||
src/logby.h
|
||||
src/prereadby.c
|
||||
src/prereadby.h
|
||||
src/probe.h
|
||||
src/request.c
|
||||
src/request.h
|
||||
src/ringbuf.c
|
||||
src/ringbuf.h
|
||||
src/ssl.c
|
||||
src/ssl.h
|
|
@ -0,0 +1,104 @@
|
|||
sudo: required
|
||||
dist: focal
|
||||
|
||||
branches:
|
||||
only:
|
||||
- "master"
|
||||
|
||||
os: linux
|
||||
|
||||
language: c
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages: [ axel, cpanminus, libgd-dev, libtest-base-perl, libtext-diff-perl, liburi-perl, libwww-perl, libtest-longstring-perl, liblist-moreutils-perl, dnsutils ]
|
||||
|
||||
cache:
|
||||
apt: true
|
||||
directories:
|
||||
- download-cache
|
||||
|
||||
env:
|
||||
global:
|
||||
- LUAJIT_PREFIX=/opt/luajit21
|
||||
- LUAJIT_LIB=$LUAJIT_PREFIX/lib
|
||||
- LD_LIBRARY_PATH=$LUAJIT_LIB:$LD_LIBRARY_PATH
|
||||
- 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
|
||||
- JOBS=3
|
||||
- NGX_BUILD_JOBS=$JOBS
|
||||
- TEST_NGINX_SLEEP=0.006
|
||||
matrix:
|
||||
- NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.0l
|
||||
- NGINX_VERSION=1.21.4 OPENSSL_VER=1.1.1s
|
||||
|
||||
services:
|
||||
- memcache
|
||||
- redis-server
|
||||
|
||||
install:
|
||||
- sudo apt update
|
||||
- sudo apt install --only-upgrade ca-certificates
|
||||
- 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/openresty-devel-utils.git
|
||||
- git clone https://github.com/openresty/lua-cjson.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/simpl/ngx_devel_kit.git ../ndk-nginx-module
|
||||
- git clone https://github.com/openresty/mockeagain.git
|
||||
- git clone https://github.com/openresty/test-nginx.git
|
||||
- git clone -b v2.1-agentzh https://github.com/openresty/luajit2.git
|
||||
- git clone https://github.com/openresty/lua-nginx-module.git ../lua-nginx-module
|
||||
- git clone https://github.com/openresty/echo-nginx-module.git ../echo-nginx-module
|
||||
- git clone https://github.com/openresty/memc-nginx-module.git ../memc-nginx-module
|
||||
- git clone https://github.com/openresty/headers-more-nginx-module.git ../headers-more-nginx-module
|
||||
- git clone https://github.com/openresty/lua-resty-lrucache.git ../lua-resty-lrucache
|
||||
- git clone https://github.com/openresty/lua-resty-core.git ../lua-resty-core
|
||||
|
||||
script:
|
||||
- sudo iptables -I OUTPUT 1 -p udp --dport 10086 -j REJECT
|
||||
- sudo iptables -A OUTPUT -p tcp --dst 127.0.0.2 --dport 12345 -j DROP
|
||||
- sudo iptables -A OUTPUT -p udp --dst 127.0.0.2 --dport 12345 -j DROP
|
||||
- sudo ip addr add 10.254.254.1/24 dev lo
|
||||
- sudo ip addr add 10.254.254.2/24 dev lo
|
||||
- sudo ip route add prohibit 0.0.0.1/32
|
||||
- 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 ..
|
||||
- cd luajit2
|
||||
- make -j$JOBS CCDEBUG=-g Q= PREFIX=$LUAJIT_PREFIX CC=$CC XCFLAGS='-DLUA_USE_APICHECK -DLUA_USE_ASSERT' > 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 ../test-nginx && sudo cpanm . && cd ..
|
||||
- cd lua-cjson/ && make -j$JOBS && sudo make install && cd ..
|
||||
- cd mockeagain/ && make CC=$CC -j$JOBS && cd ..
|
||||
- tar zxf download-cache/openssl-$OPENSSL_VER.tar.gz
|
||||
- cd openssl-$OPENSSL_VER/
|
||||
- ./config no-threads shared enable-ssl3 enable-ssl3-method -g --prefix=$OPENSSL_PREFIX -DPURIFY > build.log 2>&1 || (cat build.log && exit 1)
|
||||
- make -j$JOBS > build.log 2>&1 || (cat build.log && exit 1)
|
||||
- sudo make PATH=$PATH install_sw > build.log 2>&1 || (cat build.log && exit 1)
|
||||
- cd ..
|
||||
- export PATH=$PWD/work/nginx/sbin:$PWD/openresty-devel-utils:$PATH
|
||||
- export NGX_BUILD_CC=$CC
|
||||
- sh util/build.sh $NGINX_VERSION > build.log 2>&1 || (cat build.log && exit 1)
|
||||
- nginx -V
|
||||
- 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 @$TEST_NGINX_RESOLVER openresty.org || exit 0
|
||||
- dig +short @$TEST_NGINX_RESOLVER agentzh.org || exit 0
|
||||
- prove -I. -r t
|
|
@ -0,0 +1,32 @@
|
|||
**DO NOT EDIT THIS REPO DIRECTLY, CODE ARE AUTOMATICALLY GENERATED FROM TEMPLATES**
|
||||
|
||||
# Install
|
||||
|
||||
There are some quirks when compiling the refactored stream module.
|
||||
|
||||
You will need NGINX 1.13.x for it to work as we targeted the refactor toward
|
||||
that version only. The [1.13.x branch](https://github.com/openresty/openresty/tree/1.13.x)
|
||||
of OpenResty should serve this well.
|
||||
|
||||
You need to turn off FFI when compiling (for the time being) as not all FFI functions got
|
||||
their respective guard.
|
||||
|
||||
Here is what I use for compiling:
|
||||
|
||||
```shell
|
||||
./configure --prefix=/home/datong/openresty-stream-build \
|
||||
--with-stream --with-stream_ssl_module
|
||||
--add-module=/home/datong/orinc/stream-lua-nginx-module
|
||||
-j4 --with-cc-opt='-DNGX_LUA_NO_FFI_API' --with-debug
|
||||
```
|
||||
|
||||
# Status
|
||||
The project can run simple "Hello, World" without any problem or Valgrind warnings.
|
||||
|
||||
I have also tested timer and variable support and they appears to work as well.
|
||||
|
||||
The only feature that has not been ported is the cosocket API due to it's
|
||||
complexity. This does makes the module somewhat useless as input from user can not be read by
|
||||
Lua programs right now. I will spend some time to sort this out shortly.
|
||||
|
||||
I will spend some time debugging and get the test suite running next.
|
|
@ -0,0 +1,683 @@
|
|||
|
||||
Name
|
||||
====
|
||||
|
||||
ngx_stream_lua_module - Embed the power of Lua into Nginx stream/TCP Servers.
|
||||
|
||||
This module is a core component of OpenResty. If you are using this module,
|
||||
then you are essentially using OpenResty.
|
||||
|
||||
*This module is not distributed with the Nginx source.* See [the installation
|
||||
instructions](#installation).
|
||||
|
||||
Table of Contents
|
||||
=================
|
||||
|
||||
* [Name](#name)
|
||||
* [Status](#status)
|
||||
* [Version](#version)
|
||||
* [Synopsis](#synopsis)
|
||||
* [Description](#description)
|
||||
* [Directives](#directives)
|
||||
* [Nginx API for Lua](#nginx-api-for-lua)
|
||||
* [TODO](#todo)
|
||||
* [Nginx Compatibility](#nginx-compatibility)
|
||||
* [Installation](#installation)
|
||||
* [Community](#community)
|
||||
* [English Mailing List](#english-mailing-list)
|
||||
* [Chinese Mailing List](#chinese-mailing-list)
|
||||
* [Code Repository](#code-repository)
|
||||
* [Bugs and Patches](#bugs-and-patches)
|
||||
* [Acknowledgments](#acknowledgments)
|
||||
* [Copyright and License](#copyright-and-license)
|
||||
* [See Also](#see-also)
|
||||
|
||||
Status
|
||||
======
|
||||
|
||||
Production ready.
|
||||
|
||||
Version
|
||||
=======
|
||||
|
||||
This document describes ngx_stream_lua
|
||||
[v0.0.8](https://github.com/openresty/stream-lua-nginx-module/tags), which was released
|
||||
on 2 July, 2020.
|
||||
|
||||
Synopsis
|
||||
========
|
||||
|
||||
```nginx
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
stream {
|
||||
# define a TCP server listening on the port 1234:
|
||||
server {
|
||||
listen 1234;
|
||||
|
||||
content_by_lua_block {
|
||||
ngx.say("Hello, Lua!")
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Set up as an SSL TCP server:
|
||||
|
||||
```nginx
|
||||
stream {
|
||||
server {
|
||||
listen 4343 ssl;
|
||||
|
||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
||||
ssl_ciphers AES128-SHA:AES256-SHA:RC4-SHA:DES-CBC3-SHA:RC4-MD5;
|
||||
ssl_certificate /path/to/cert.pem;
|
||||
ssl_certificate_key /path/to/cert.key;
|
||||
ssl_session_cache shared:SSL:10m;
|
||||
ssl_session_timeout 10m;
|
||||
|
||||
content_by_lua_block {
|
||||
local sock = assert(ngx.req.socket(true))
|
||||
local data = sock:receive() -- read a line from downstream
|
||||
if data == "thunder!" then
|
||||
ngx.say("flash!") -- output data
|
||||
else
|
||||
ngx.say("boom!")
|
||||
end
|
||||
ngx.say("the end...")
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Listening on a UNIX domain socket is also supported:
|
||||
|
||||
```nginx
|
||||
stream {
|
||||
server {
|
||||
listen unix:/tmp/nginx.sock;
|
||||
|
||||
content_by_lua_block {
|
||||
ngx.say("What's up?")
|
||||
ngx.flush(true) -- flush any pending output and wait
|
||||
ngx.sleep(3) -- sleeping for 3 sec
|
||||
ngx.say("Bye bye...")
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
[Back to TOC](#table-of-contents)
|
||||
|
||||
Description
|
||||
===========
|
||||
|
||||
This is a port of the
|
||||
[ngx_http_lua_module](https://github.com/openresty/lua-nginx-module#readme) to
|
||||
the Nginx "stream" subsystem so as to support generic stream/TCP clients.
|
||||
|
||||
The available Lua APIs and Nginx directives remain the same as those of the
|
||||
ngx_http_lua module.
|
||||
|
||||
[Back to TOC](#table-of-contents)
|
||||
|
||||
Directives
|
||||
----------
|
||||
|
||||
The following directives are ported directly from ngx_http_lua. Please check
|
||||
the documentation of ngx_http_lua for more details about their usage and
|
||||
behavior.
|
||||
|
||||
* [lua_load_resty_core](https://github.com/openresty/lua-nginx-module#lua_load_resty_core)
|
||||
* [lua_code_cache](https://github.com/openresty/lua-nginx-module#lua_code_cache)
|
||||
* [lua_regex_cache_max_entries](https://github.com/openresty/lua-nginx-module#lua_regex_cache_max_entries)
|
||||
* [lua_package_path](https://github.com/openresty/lua-nginx-module#lua_package_path)
|
||||
* [lua_package_cpath](https://github.com/openresty/lua-nginx-module#lua_package_cpath)
|
||||
* [init_by_lua_block](https://github.com/openresty/lua-nginx-module#init_by_lua_block)
|
||||
* [init_by_lua_file](https://github.com/openresty/lua-nginx-module#init_by_lua_file)
|
||||
* [init_worker_by_lua_block](https://github.com/openresty/lua-nginx-module#init_worker_by_lua_block)
|
||||
* [init_worker_by_lua_file](https://github.com/openresty/lua-nginx-module#init_worker_by_lua_file)
|
||||
* [preread_by_lua_block](#preread_by_lua_block)
|
||||
* [preread_by_lua_file](#preread_by_lua_file)
|
||||
* [content_by_lua_block](https://github.com/openresty/lua-nginx-module#content_by_lua_block)
|
||||
* [content_by_lua_file](https://github.com/openresty/lua-nginx-module#content_by_lua_file)
|
||||
* [balancer_by_lua_block](https://github.com/openresty/lua-nginx-module#balancer_by_lua_block)
|
||||
* [balancer_by_lua_file](https://github.com/openresty/lua-nginx-module#balancer_by_lua_file)
|
||||
* [log_by_lua_block](#log_by_lua_block)
|
||||
* [log_by_lua_file](#log_by_lua_file)
|
||||
* [ssl_client_hello_by_lua_block](https://github.com/openresty/lua-nginx-module#ssl_client_hello_by_lua_block)
|
||||
* [ssl_client_hello_by_lua_file](https://github.com/openresty/lua-nginx-module#ssl_client_hello_by_lua_file)
|
||||
* [ssl_certificate_by_lua_block](https://github.com/openresty/lua-nginx-module#ssl_certificate_by_lua_block)
|
||||
* [ssl_certificate_by_lua_file](https://github.com/openresty/lua-nginx-module#ssl_certificate_by_lua_file)
|
||||
* [lua_shared_dict](https://github.com/openresty/lua-nginx-module#lua_shared_dict)
|
||||
* [lua_socket_connect_timeout](https://github.com/openresty/lua-nginx-module#lua_socket_connect_timeout)
|
||||
* [lua_socket_buffer_size](https://github.com/openresty/lua-nginx-module#lua_socket_buffer_size)
|
||||
* [lua_socket_pool_size](https://github.com/openresty/lua-nginx-module#lua_socket_pool_size)
|
||||
* [lua_socket_keepalive_timeout](https://github.com/openresty/lua-nginx-module#lua_socket_keepalive_timeout)
|
||||
* [lua_socket_log_errors](https://github.com/openresty/lua-nginx-module#lua_socket_log_errors)
|
||||
* [lua_ssl_ciphers](https://github.com/openresty/lua-nginx-module#lua_ssl_ciphers)
|
||||
* [lua_ssl_crl](https://github.com/openresty/lua-nginx-module#lua_ssl_crl)
|
||||
* [lua_ssl_protocols](https://github.com/openresty/lua-nginx-module#lua_ssl_protocols)
|
||||
* [lua_ssl_trusted_certificate](https://github.com/openresty/lua-nginx-module#lua_ssl_trusted_certificate)
|
||||
* [lua_ssl_verify_depth](https://github.com/openresty/lua-nginx-module#lua_ssl_verify_depth)
|
||||
* [lua_ssl_conf_command](https://github.com/openresty/lua-nginx-module#lua_ssl_conf_command)
|
||||
* [lua_check_client_abort](https://github.com/openresty/lua-nginx-module#lua_check_client_abort)
|
||||
* [lua_max_pending_timers](https://github.com/openresty/lua-nginx-module#lua_max_pending_timers)
|
||||
* [lua_max_running_timers](https://github.com/openresty/lua-nginx-module#lua_max_running_timers)
|
||||
* [lua_sa_restart](https://github.com/openresty/lua-nginx-module#lua_sa_restart)
|
||||
* [lua_add_variable](#lua_add_variable)
|
||||
* [lua_capture_error_log](https://github.com/openresty/lua-nginx-module#lua_capture_error_log)
|
||||
* [preread_by_lua_no_postpone](#preread_by_lua_no_postpone)
|
||||
|
||||
The [send_timeout](https://nginx.org/r/send_timeout) directive in the Nginx
|
||||
"http" subsystem is missing in the "stream" subsystem. As such,
|
||||
ngx_stream_lua_module uses the `lua_socket_send_timeout` directive for this
|
||||
purpose instead.
|
||||
|
||||
**Note:** the lingering close directive that used to exist in older version of
|
||||
`stream_lua_nginx_module` has been removed and can now be simulated with the
|
||||
newly added [tcpsock:shutdown](#tcpsockshutdown) API if necessary.
|
||||
|
||||
[Back to TOC](#table-of-contents)
|
||||
|
||||
preread_by_lua_block
|
||||
--------------------
|
||||
|
||||
**syntax:** *preread_by_lua_block { lua-script }*
|
||||
|
||||
**context:** *stream, server*
|
||||
|
||||
**phase:** *preread*
|
||||
|
||||
Acts as a `preread` phase handler and executes Lua code string specified in `lua-script` for every connection
|
||||
(or packet in datagram mode).
|
||||
The Lua code may make [API calls](#nginx-api-for-lua) and is executed as a new spawned coroutine in an independent global environment (i.e. a sandbox).
|
||||
|
||||
It is possible to acquire the raw request socket using [ngx.req.socket](https://github.com/openresty/lua-nginx-module#ngxreqsocket)
|
||||
and receive data from or send data to the client. However, keep in mind that calling the `receive()` method
|
||||
of the request socket will consume the data from the buffer and such consumed data will not be seen by handlers
|
||||
further down the chain.
|
||||
|
||||
The `preread_by_lua_block` code will always run at the end of the `preread` processing phase unless
|
||||
[preread\_by\_lua\_no\_postpone](#preread_by_lua_no_postpone) is turned on.
|
||||
|
||||
This directive was first introduced in the `v0.0.3` release.
|
||||
|
||||
[Back to TOC](#directives)
|
||||
|
||||
preread_by_lua_file
|
||||
-------------------
|
||||
|
||||
**syntax:** *preread_by_lua_file <path-to-lua-script-file>*
|
||||
|
||||
**context:** *stream, server*
|
||||
|
||||
**phase:** *preread*
|
||||
|
||||
Equivalent to [preread_by_lua_block](#preread_by_lua_block), except that the file specified by `<path-to-lua-script-file>` contains the Lua code
|
||||
or LuaJIT bytecode to be executed.
|
||||
|
||||
Nginx variables can be used in the `<path-to-lua-script-file>` string to provide flexibility. This however carries some risks and is not ordinarily recommended.
|
||||
|
||||
When a relative path like `foo/bar.lua` is given, it will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option given when starting the Nginx server.
|
||||
|
||||
When the Lua code cache is turned on (by default), the user code is loaded once at the first connection and cached. The Nginx config must be reloaded each time the Lua source file is modified. The Lua code cache can be temporarily disabled during development by switching [lua_code_cache](#lua_code_cache) `off` in `nginx.conf` to avoid having to reload Nginx.
|
||||
|
||||
This directive was first introduced in the `v0.0.3` release.
|
||||
|
||||
[Back to TOC](#directives)
|
||||
|
||||
log_by_lua_block
|
||||
----------------
|
||||
|
||||
**syntax:** *log_by_lua_block { lua-script }*
|
||||
|
||||
**context:** *stream, server*
|
||||
|
||||
**phase:** *log*
|
||||
|
||||
Runs the Lua source code specified as `<lua-script>` during the `log` request processing phase. This does not replace the current access logs, but runs before.
|
||||
|
||||
Yielding APIs such as `ngx.req.socket`, `ngx.socket.*`, `ngx.sleep`, or `ngx.say` are **not** available in this phase.
|
||||
|
||||
This directive was first introduced in the `v0.0.3` release.
|
||||
|
||||
[Back to TOC](#directives)
|
||||
|
||||
log_by_lua_file
|
||||
---------------
|
||||
|
||||
**syntax:** *log_by_lua_file <path-to-lua-script-file>*
|
||||
|
||||
**context:** *stream, server*
|
||||
|
||||
**phase:** *log*
|
||||
|
||||
Equivalent to [log_by_lua_block](#log_by_lua_block), except that the file specified by `<path-to-lua-script-file>` contains the Lua code
|
||||
or LuaJIT bytecode to be executed.
|
||||
|
||||
Nginx variables can be used in the `<path-to-lua-script-file>` string to provide flexibility. This however carries some risks and is not ordinarily recommended.
|
||||
|
||||
When a relative path like `foo/bar.lua` is given, it will be turned into the absolute path relative to the `server prefix` path determined by the `-p PATH` command-line option given when starting the Nginx server.
|
||||
|
||||
When the Lua code cache is turned on (by default), the user code is loaded once at the first connection and cached. The Nginx config must be reloaded each time the Lua source file is modified. The Lua code cache can be temporarily disabled during development by switching [lua_code_cache](#lua_code_cache) `off` in `nginx.conf` to avoid having to reload Nginx.
|
||||
|
||||
This directive was first introduced in the `v0.0.3` release.
|
||||
|
||||
[Back to TOC](#directives)
|
||||
|
||||
lua_add_variable
|
||||
----------------
|
||||
|
||||
**syntax:** *lua_add_variable $var*
|
||||
|
||||
**context:** *stream*
|
||||
|
||||
Add the variable `$var` to the "stream" subsystem and makes it changeable. If `$var` already exists,
|
||||
this directive will do nothing.
|
||||
|
||||
By default, variables added using this directive are considered "not found" and reading them
|
||||
using `ngx.var` will return `nil`. However, they could be re-assigned via the `ngx.var.VARIABLE` API at any time.
|
||||
|
||||
This directive was first introduced in the `v0.0.4` release.
|
||||
|
||||
[Back to TOC](#directives)
|
||||
|
||||
preread_by_lua_no_postpone
|
||||
--------------------------
|
||||
|
||||
**syntax:** *preread_by_lua_no_postpone on|off*
|
||||
|
||||
**context:** *stream*
|
||||
|
||||
Controls whether or not to disable postponing [preread\_by\_lua*](#preread_by_lua_block) directives
|
||||
to run at the end of the `preread` processing phase. By default, this directive is turned off
|
||||
and the Lua code is postponed to run at the end of the `preread` phase.
|
||||
|
||||
This directive was first introduced in the `v0.0.4` release.
|
||||
|
||||
[Back to TOC](#directives)
|
||||
|
||||
Nginx API for Lua
|
||||
-----------------
|
||||
|
||||
Many Lua API functions are ported from ngx_http_lua. Check out the official
|
||||
manual of ngx_http_lua for more details on these Lua API functions.
|
||||
|
||||
* [ngx.var.VARIABLE](https://github.com/openresty/lua-nginx-module#ngxvarvariable)
|
||||
|
||||
This module fully supports the new variable subsystem inside the Nginx stream core. You may access any
|
||||
[built-in variables](https://nginx.org/en/docs/stream/ngx_stream_core_module.html#variables) provided by the stream core or
|
||||
other stream modules.
|
||||
* [Core constants](https://github.com/openresty/lua-nginx-module#core-constants)
|
||||
|
||||
`ngx.OK`, `ngx.ERROR`, and etc.
|
||||
* [Nginx log level constants](https://github.com/openresty/lua-nginx-module#nginx-log-level-constants)
|
||||
|
||||
`ngx.ERR`, `ngx.WARN`, and etc.
|
||||
* [print](https://github.com/openresty/lua-nginx-module#print)
|
||||
* [ngx.ctx](https://github.com/openresty/lua-nginx-module#ngxctx)
|
||||
* [ngx.balancer](https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/balancer.md)
|
||||
|
||||
* [ngx.req.socket](https://github.com/openresty/lua-nginx-module#ngxreqsocket)
|
||||
|
||||
Only raw request sockets are supported, for obvious reasons. The `raw` argument value
|
||||
is ignored and the raw request socket is always returned. Unlike ngx_http_lua,
|
||||
you can still call output API functions like `ngx.say`, `ngx.print`, and `ngx.flush`
|
||||
after acquiring the raw request socket via this function.
|
||||
|
||||
When the stream server is in UDP mode, reading from the downstream socket returned by the
|
||||
`ngx.req.socket` call will only return the content of a single packet. Therefore
|
||||
the reading call will never block and will return `nil, "no more data"` when all the
|
||||
data from the datagram has been consumed. However, you may choose to send multiple UDP
|
||||
packets back to the client using the downstream socket.
|
||||
|
||||
The raw TCP sockets returned by this module will contain the following extra method:
|
||||
|
||||
[Back to TOC](#directives)
|
||||
|
||||
reqsock:receiveany
|
||||
------------------
|
||||
|
||||
**syntax:** *data, err = reqsock:receiveany(max)*
|
||||
|
||||
**context:** *content_by_lua*, ngx.timer.*, ssl_certificate_by_lua**
|
||||
|
||||
This method is similar to [tcpsock:receiveany](https://github.com/openresty/lua-nginx-module#tcpsockreceiveany) method
|
||||
|
||||
This method was introduced into `stream-lua-nginx-module` since `v0.0.8`.
|
||||
|
||||
[Back to TOC](#directives)
|
||||
|
||||
tcpsock:shutdown
|
||||
----------------
|
||||
|
||||
**syntax:** *ok, err = tcpsock:shutdown("send")*
|
||||
|
||||
**context:** *content_by_lua**
|
||||
|
||||
Shuts down the write part of the request socket, prevents all further writing to the client
|
||||
and sends TCP FIN, while keeping the reading half open.
|
||||
|
||||
Currently only the `"send"` direction is supported. Using any parameters other than "send" will return
|
||||
an error.
|
||||
|
||||
If you called any output functions (like [ngx.say](https://github.com/openresty/lua-nginx-module#ngxsay))
|
||||
before calling this method, consider use `ngx.flush(true)` to make sure all busy buffers are complely
|
||||
flushed before shutting down the socket. If any busy buffers were detected, this method will return `nil`
|
||||
will error message `"socket busy writing"`.
|
||||
|
||||
This feature is particularly useful for protocols that generate a response before actually
|
||||
finishing consuming all incoming data. Normally, the kernel will send RST to the client when
|
||||
[tcpsock:close](https://github.com/openresty/lua-nginx-module#tcpsockclose) is called without
|
||||
emptying the receiving buffer first. Calling this method will allow you to keep reading from
|
||||
the receiving buffer and prevents RST from being sent.
|
||||
|
||||
You can also use this method to simulate lingering close similar to that
|
||||
[provided by the ngx_http_core_module](https://nginx.org/en/docs/http/ngx_http_core_module.html#lingering_close)
|
||||
for protocols in need of such behavior. Here is an example:
|
||||
|
||||
```lua
|
||||
local LINGERING_TIME = 30 -- 30 seconds
|
||||
local LINGERING_TIMEOUT = 5000 -- 5 seconds
|
||||
|
||||
local ok, err = sock:shutdown("send")
|
||||
if not ok then
|
||||
ngx.log(ngx.ERR, "failed to shutdown: ", err)
|
||||
return
|
||||
end
|
||||
|
||||
local deadline = ngx.time() + LINGERING_TIME
|
||||
|
||||
sock:settimeouts(nil, nil, LINGERING_TIMEOUT)
|
||||
|
||||
repeat
|
||||
local data, _, partial = sock:receive(1024)
|
||||
until (not data and not partial) or ngx.time() >= deadline
|
||||
```
|
||||
|
||||
[Back to TOC](#directives)
|
||||
|
||||
reqsock:peek
|
||||
------------
|
||||
|
||||
**syntax:** *ok, err = reqsock:peek(size)*
|
||||
|
||||
**context:** *preread_by_lua**
|
||||
|
||||
Peeks into the [preread](https://nginx.org/en/docs/stream/stream_processing.html#preread_phase)
|
||||
buffer that contains downstream data sent by the client without consuming them.
|
||||
That is, data returned by this API will still be forwarded upstream in later phases.
|
||||
|
||||
This function takes a single required argument, `size`, which is the number of bytes to be peeked.
|
||||
Repeated calls to this function always returns data from the beginning of the preread buffer.
|
||||
|
||||
Note that preread phase happens after the TLS handshake. If the stream server was configured with
|
||||
TLS enabled, the returned data will be in clear text.
|
||||
|
||||
If preread buffer does not have the requested amount of data, then the current Lua thread will
|
||||
be yielded until more data is available, [`preread_buffer_size`](https://nginx.org/en/docs/stream/ngx_stream_core_module.html#preread_buffer_size)
|
||||
has been exceeded, or [`preread_timeout`](https://nginx.org/en/docs/stream/ngx_stream_core_module.html#preread_timeout)
|
||||
has elapsed. Successful calls always return the requested amounts of data, that is, no partial
|
||||
data will be returned.
|
||||
|
||||
When [`preread_buffer_size`](https://nginx.org/en/docs/stream/ngx_stream_core_module.html#preread_buffer_size)
|
||||
has been exceeded, the current stream session will be terminated with the
|
||||
[session status code](https://nginx.org/en/docs/stream/ngx_stream_core_module.html#var_status) `400`
|
||||
immediately by the stream core module, with error message `"preread buffer full"` that will be printed to the error log.
|
||||
|
||||
When [`preread_timeout`](https://nginx.org/en/docs/stream/ngx_stream_core_module.html#preread_timeout) has been exceeded,
|
||||
the current stream session will be terminated with the
|
||||
[session status code](https://nginx.org/en/docs/stream/ngx_stream_core_module.html#var_status) `200` immediately by the stream core module.
|
||||
|
||||
In both cases, no further processing on the session is possible (except `log_by_lua*`). The connection will be closed by the
|
||||
stream core module automatically.
|
||||
|
||||
Note that this API cannot be used if consumption of client data has occurred. For example, after calling
|
||||
`reqsock:receive`. If such an attempt was made, the Lua error `"attempt to peek on a consumed socket"` will
|
||||
be thrown. Consuming client data after calling this API is allowed and safe.
|
||||
|
||||
Here is an example of using this API:
|
||||
|
||||
```lua
|
||||
local sock = assert(ngx.req.socket())
|
||||
|
||||
local data = assert(sock:peek(1)) -- peek the first 1 byte that contains the length
|
||||
data = string.byte(data)
|
||||
|
||||
data = assert(sock:peek(data + 1)) -- peek the length + the size byte
|
||||
|
||||
local payload = data:sub(2) -- trim the length byte to get actual payload
|
||||
|
||||
ngx.log(ngx.INFO, "payload is: ", payload)
|
||||
```
|
||||
|
||||
This API was first introduced in the `v0.0.6` release.
|
||||
|
||||
[Back to TOC](#directives)
|
||||
|
||||
* [ngx.print](https://github.com/openresty/lua-nginx-module#ngxprint)
|
||||
* [ngx.say](https://github.com/openresty/lua-nginx-module#ngxsay)
|
||||
* [ngx.log](https://github.com/openresty/lua-nginx-module#ngxlog)
|
||||
* [ngx.flush](https://github.com/openresty/lua-nginx-module#ngxflush)
|
||||
|
||||
This call currently ignores the `wait` argument and always wait for all the pending
|
||||
output to be completely flushed out (to the system socket send buffers).
|
||||
* [ngx.exit](https://github.com/openresty/lua-nginx-module#ngxexit)
|
||||
* [ngx.eof](https://github.com/openresty/lua-nginx-module#ngxeof)
|
||||
* [ngx.sleep](https://github.com/openresty/lua-nginx-module#ngxsleep)
|
||||
* [ngx.escape_uri](https://github.com/openresty/lua-nginx-module#ngxescape_uri)
|
||||
* [ngx.unescape_uri](https://github.com/openresty/lua-nginx-module#ngxunescape_uri)
|
||||
* [ngx.encode_args](https://github.com/openresty/lua-nginx-module#ngxencode_args)
|
||||
* [ngx.decode_args](https://github.com/openresty/lua-nginx-module#ngxdecode_args)
|
||||
* [ngx.encode_base64](https://github.com/openresty/lua-nginx-module#ngxencode_base64)
|
||||
* [ngx.decode_base64](https://github.com/openresty/lua-nginx-module#ngxdecode_base64)
|
||||
* [ngx.crc32_short](https://github.com/openresty/lua-nginx-module#ngxcrc32_short)
|
||||
* [ngx.crc32_long](https://github.com/openresty/lua-nginx-module#ngxcrc32_long)
|
||||
* [ngx.hmac_sha1](https://github.com/openresty/lua-nginx-module#ngxhmac_sha1)
|
||||
* [ngx.md5](https://github.com/openresty/lua-nginx-module#ngxmd5)
|
||||
* [ngx.md5_bin](https://github.com/openresty/lua-nginx-module#ngxmd5_bin)
|
||||
* [ngx.sha1_bin](https://github.com/openresty/lua-nginx-module#ngxsha1_bin)
|
||||
* [ngx.quote_sql_str](https://github.com/openresty/lua-nginx-module#ngxquote_sql_str)
|
||||
* [ngx.today](https://github.com/openresty/lua-nginx-module#ngxtoday)
|
||||
* [ngx.time](https://github.com/openresty/lua-nginx-module#ngxtime)
|
||||
* [ngx.now](https://github.com/openresty/lua-nginx-module#ngxnow)
|
||||
* [ngx.update_time](https://github.com/openresty/lua-nginx-module#ngxupdate_time)
|
||||
* [ngx.localtime](https://github.com/openresty/lua-nginx-module#ngxlocaltime)
|
||||
* [ngx.utctime](https://github.com/openresty/lua-nginx-module#ngxutctime)
|
||||
* [ngx.re.match](https://github.com/openresty/lua-nginx-module#ngxrematch)
|
||||
* [ngx.re.find](https://github.com/openresty/lua-nginx-module#ngxrefind)
|
||||
* [ngx.re.gmatch](https://github.com/openresty/lua-nginx-module#ngxregmatch)
|
||||
* [ngx.re.sub](https://github.com/openresty/lua-nginx-module#ngxresub)
|
||||
* [ngx.re.gsub](https://github.com/openresty/lua-nginx-module#ngxregsub)
|
||||
* [ngx.shared.DICT](https://github.com/openresty/lua-nginx-module#ngxshareddict)
|
||||
* [ngx.socket.tcp](https://github.com/openresty/lua-nginx-module#ngxsockettcp)
|
||||
* [ngx.socket.udp](https://github.com/openresty/lua-nginx-module#ngxsocketudp)
|
||||
* [ngx.socket.connect](https://github.com/openresty/lua-nginx-module#ngxsocketconnect)
|
||||
* [ngx.get_phase](https://github.com/openresty/lua-nginx-module#ngxget_phase)
|
||||
* [ngx.thread.spawn](https://github.com/openresty/lua-nginx-module#ngxthreadspawn)
|
||||
* [ngx.thread.wait](https://github.com/openresty/lua-nginx-module#ngxthreadwait)
|
||||
* [ngx.thread.kill](https://github.com/openresty/lua-nginx-module#ngxthreadkill)
|
||||
* [ngx.on_abort](https://github.com/openresty/lua-nginx-module#ngxon_abort)
|
||||
* [ngx.timer.at](https://github.com/openresty/lua-nginx-module#ngxtimerat)
|
||||
* [ngx.timer.running_count](https://github.com/openresty/lua-nginx-module#ngxtimerrunning_count)
|
||||
* [ngx.timer.pending_count](https://github.com/openresty/lua-nginx-module#ngxtimerpending_count)
|
||||
* [ngx.config.debug](https://github.com/openresty/lua-nginx-module#ngxconfigdebug)
|
||||
* [ngx.config.subsystem](https://github.com/openresty/lua-nginx-module#ngxconfigsubsystem)
|
||||
|
||||
Always takes the Lua string value `"stream"` in this module.
|
||||
* [ngx.config.prefix](https://github.com/openresty/lua-nginx-module#ngxconfigprefix)
|
||||
* [ngx.config.nginx_version](https://github.com/openresty/lua-nginx-module#ngxconfignginx_version)
|
||||
* [ngx.config.nginx_configure](https://github.com/openresty/lua-nginx-module#ngxconfignginx_configure)
|
||||
* [ngx.config.ngx_lua_version](https://github.com/openresty/lua-nginx-module#ngxconfigngx_lua_version)
|
||||
* [ngx.worker.exiting](https://github.com/openresty/lua-nginx-module#ngxworkerexiting)
|
||||
* [ngx.worker.pid](https://github.com/openresty/lua-nginx-module#ngxworkerpid)
|
||||
* [ngx.worker.pids](https://github.com/openresty/lua-nginx-module#ngxworkerpids)
|
||||
* [ngx.worker.count](https://github.com/openresty/lua-nginx-module#ngxworkercount)
|
||||
* [ngx.worker.id](https://github.com/openresty/lua-nginx-module#ngxworkerid)
|
||||
* [coroutine.create](https://github.com/openresty/lua-nginx-module#coroutinecreate)
|
||||
* [coroutine.resume](https://github.com/openresty/lua-nginx-module#coroutineresume)
|
||||
* [coroutine.yield](https://github.com/openresty/lua-nginx-module#coroutineyield)
|
||||
* [coroutine.wrap](https://github.com/openresty/lua-nginx-module#coroutinewrap)
|
||||
* [coroutine.running](https://github.com/openresty/lua-nginx-module#coroutinerunning)
|
||||
* [coroutine.status](https://github.com/openresty/lua-nginx-module#coroutinestatus)
|
||||
|
||||
[Back to TOC](#table-of-contents)
|
||||
|
||||
TODO
|
||||
====
|
||||
|
||||
* Add new directives `access_by_lua_block` and `access_by_lua_file`.
|
||||
* Add `lua_postpone_output` to emulate the [postpone_output](https://nginx.org/r/postpone_output) directive.
|
||||
|
||||
[Back to TOC](#table-of-contents)
|
||||
|
||||
Nginx Compatibility
|
||||
===================
|
||||
|
||||
The latest version of this module is compatible with the following versions of Nginx:
|
||||
|
||||
* 1.19.x (last tested: 1.19.3)
|
||||
* 1.17.x (last tested: 1.17.8)
|
||||
* 1.15.x (last tested: 1.15.8)
|
||||
* 1.13.x (last tested: 1.13.6)
|
||||
|
||||
Nginx cores older than 1.13.6 (exclusive) are *not* tested and may or may not
|
||||
work. Use at your own risk!
|
||||
|
||||
[Back to TOC](#table-of-contents)
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
It is *highly* recommended to use [OpenResty releases](https://openresty.org)
|
||||
which bundle Nginx, ngx_http_lua, ngx_stream_lua, (this module), LuaJIT, as
|
||||
well as other powerful companion Nginx modules and Lua libraries.
|
||||
|
||||
It is discouraged to build this module with Nginx yourself since it is tricky
|
||||
to set up exactly right.
|
||||
|
||||
Note that Nginx, LuaJIT, and OpenSSL official releases have various limitations
|
||||
and long standing bugs that can cause some of this module's features to be
|
||||
disabled, not work properly, or run slower. Official OpenResty releases are
|
||||
recommended because they bundle [OpenResty's optimized LuaJIT 2.1 fork](https://github.com/openresty/luajit2) and
|
||||
[Nginx/OpenSSL
|
||||
patches](https://github.com/openresty/openresty/tree/master/patches).
|
||||
|
||||
Alternatively, ngx_stream_lua can be manually compiled into Nginx:
|
||||
|
||||
1. LuaJIT can be downloaded from the [latest release of OpenResty's LuaJIT fork](https://github.com/openresty/luajit2/releases). The official LuaJIT 2.x releases are also supported, although performance will be significantly lower for reasons elaborated above
|
||||
1. Download the latest version of ngx_stream_lua [HERE](https://github.com/openresty/stream-lua-nginx-module/tags)
|
||||
1. Download the latest supported version of Nginx [HERE](https://nginx.org/) (See [Nginx Compatibility](#nginx-compatibility))
|
||||
|
||||
Build the source with this module:
|
||||
|
||||
```bash
|
||||
wget 'https://nginx.org/download/nginx-1.13.6.tar.gz'
|
||||
tar -xzvf nginx-1.13.6.tar.gz
|
||||
cd nginx-1.13.6/
|
||||
|
||||
# tell nginx's build system where to find LuaJIT 2.1:
|
||||
export LUAJIT_LIB=/path/to/luajit/lib
|
||||
export LUAJIT_INC=/path/to/luajit/include/luajit-2.1
|
||||
|
||||
# Here we assume Nginx is to be installed under /opt/nginx/.
|
||||
./configure --prefix=/opt/nginx \
|
||||
--with-ld-opt="-Wl,-rpath,/path/to/luajit-or-lua/lib" \
|
||||
--with-stream \
|
||||
--with-stream_ssl_module \
|
||||
--add-module=/path/to/stream-lua-nginx-module
|
||||
|
||||
# Build and install
|
||||
make -j4
|
||||
make install
|
||||
```
|
||||
|
||||
You may use `--without-http` if you do not wish to use this module with the
|
||||
"http" subsystem. ngx_stream_lua will work perfectly fine without the "http"
|
||||
subsystem.
|
||||
|
||||
[Back to TOC](#table-of-contents)
|
||||
|
||||
Community
|
||||
=========
|
||||
|
||||
[Back to TOC](#table-of-contents)
|
||||
|
||||
English Mailing List
|
||||
--------------------
|
||||
|
||||
The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers.
|
||||
|
||||
[Back to TOC](#table-of-contents)
|
||||
|
||||
Chinese Mailing List
|
||||
--------------------
|
||||
|
||||
The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers.
|
||||
|
||||
[Back to TOC](#table-of-contents)
|
||||
|
||||
Code Repository
|
||||
===============
|
||||
|
||||
The code repository of this project is hosted on GitHub at
|
||||
[openresty/stream-lua-nginx-module](https://github.com/openresty/stream-lua-nginx-module).
|
||||
|
||||
[Back to TOC](#table-of-contents)
|
||||
|
||||
Bugs and Patches
|
||||
================
|
||||
|
||||
Please submit bug reports, wishlists, or patches by
|
||||
|
||||
1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/stream-lua-nginx-module/issues),
|
||||
1. or posting to the [OpenResty community](#community).
|
||||
|
||||
[Back to TOC](#table-of-contents)
|
||||
|
||||
Acknowledgments
|
||||
===============
|
||||
|
||||
We appreciate [Kong Inc.](https://konghq.com/) for kindly sponsoring [OpenResty Inc.](https://openresty.com/) on the following
|
||||
work:
|
||||
* Compatibility with Nginx core 1.13.3.
|
||||
* Development of [meta-lua-nginx-module](https://github.com/openresty/meta-lua-nginx-module)
|
||||
to make code sharing between this module and [lua-nginx-module](https://github.com/openresty/lua-nginx-module) possible.
|
||||
* `balancer_by_lua_*`, `preread_by_lua_*`, `log_by_lua_*` and `ssl_certby_lua*` phases support.
|
||||
* [`reqsock:peek`](#reqsockpeek) API support.
|
||||
|
||||
[Back to TOC](#table-of-contents)
|
||||
|
||||
Copyright and License
|
||||
=====================
|
||||
|
||||
This module is licensed under the BSD license.
|
||||
|
||||
Copyright (C) 2009-2019, by Yichun "agentzh" Zhang (章亦春) <agentzh@gmail.com>, OpenResty Inc.
|
||||
|
||||
Copyright (C) 2009-2016, by Xiaozhe Wang (chaoslawful) <chaoslawful@gmail.com>.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
[Back to TOC](#table-of-contents)
|
||||
|
||||
See Also
|
||||
========
|
||||
|
||||
* [ngx_http_lua_module](https://github.com/openresty/lua-nginx-module)
|
||||
* [ngx_stream_echo_module](https://github.com/openresty/stream-echo-nginx-module)
|
||||
* [OpenResty](https://openresty.org/)
|
||||
|
||||
[Back to TOC](#table-of-contents)
|
||||
|
|
@ -0,0 +1,455 @@
|
|||
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_stream_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_stream_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_stream_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_stream_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_stream_lua_module requires LuaJIT with FFI enabled.
|
||||
END
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ----------------------------------------
|
||||
|
||||
ngx_addon_name=ngx_stream_lua_module
|
||||
STREAM_LUA_SRCS=" \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_api.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_request.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_module.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_directive.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_lex.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_contentby.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_util.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_cache.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_clfactory.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_exception.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_pcrefix.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_uthread.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_coroutine.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_output.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_consts.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_log.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_time.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_string.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_control.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_sleep.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_phase.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_ctx.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_regex.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_script.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_shdict.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_variable.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_timer.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_config.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_worker.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_misc.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_initby.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_initworkerby.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_socket_tcp.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_socket_udp.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_args.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_ssl.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_balancer.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_logby.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_prereadby.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_semaphore.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_ssl_client_helloby.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_ssl_certby.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_log_ringbuf.c \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_input_filters.c \
|
||||
"
|
||||
|
||||
STREAM_LUA_DEPS=" \
|
||||
$ngx_addon_dir/src/ddebug.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_autoconf.h \
|
||||
$ngx_addon_dir/src/api/ngx_stream_lua_api.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_request.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_common.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_lex.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_contentby.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_util.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_cache.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_clfactory.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_pcrefix.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_uthread.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_coroutine.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_output.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_consts.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_log.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_string.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_control.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_sleep.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_phase.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_ctx.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_script.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_shdict.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_timer.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_config.h \
|
||||
$ngx_addon_dir/src/api/ngx_stream_lua_api.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_misc.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_initby.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_initworkerby.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_socket_tcp.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_socket_udp.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_args.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_ssl.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_balancer.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_logby.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_prereadby.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_semaphore.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_ssl_client_helloby.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_ssl_certby.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_log_ringbuf.h \
|
||||
$ngx_addon_dir/src/ngx_stream_lua_input_filters.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_STREAM_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_STREAM_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
|
||||
|
||||
# ----------------------------------------
|
||||
|
||||
if [ -n "$ngx_module_link" ]; then
|
||||
ngx_module_type=STREAM
|
||||
ngx_module_name=$ngx_addon_name
|
||||
ngx_module_deps="$STREAM_LUA_DEPS"
|
||||
ngx_module_srcs="$STREAM_LUA_SRCS"
|
||||
|
||||
. auto/module
|
||||
else
|
||||
STREAM_MODULES="$STREAM_MODULES $ngx_addon_name"
|
||||
NGX_ADDON_SRCS="$NGX_ADDON_SRCS $STREAM_LUA_SRCS"
|
||||
NGX_ADDON_DEPS="$NGX_ADDON_DEPS $STREAM_LUA_DEPS"
|
||||
|
||||
CORE_INCS="$CORE_INCS $ngx_module_incs"
|
||||
CORE_LIBS="$CORE_LIBS $ngx_module_libs"
|
||||
fi
|
||||
|
||||
# ----------------------------------------
|
||||
|
||||
if [ $USE_PCRE = YES -o $PCRE != NONE ] && [ $PCRE != NO -a $PCRE != YES ]; then
|
||||
# force pcre_version symbol to be required when PCRE is statically linked
|
||||
case "$NGX_PLATFORM" in
|
||||
Darwin:*)
|
||||
ngx_feature="require defined symbols (-u)"
|
||||
ngx_feature_name=
|
||||
ngx_feature_path=
|
||||
ngx_feature_libs="-Wl,-u,_strerror"
|
||||
ngx_feature_run=no
|
||||
ngx_feature_incs="#include <stdio.h>"
|
||||
ngx_feature_test='printf("hello");'
|
||||
|
||||
. auto/feature
|
||||
|
||||
if [ $ngx_found = yes ]; then
|
||||
CORE_LIBS="-Wl,-u,_pcre_version $CORE_LIBS"
|
||||
fi
|
||||
;;
|
||||
|
||||
*)
|
||||
ngx_feature="require defined symbols (--require-defined)"
|
||||
ngx_feature_name=
|
||||
ngx_feature_path=
|
||||
ngx_feature_libs="-Wl,--require-defined=strerror"
|
||||
ngx_feature_run=no
|
||||
ngx_feature_incs="#include <stdio.h>"
|
||||
ngx_feature_test='printf("hello");'
|
||||
|
||||
. auto/feature
|
||||
|
||||
if [ $ngx_found = yes ]; then
|
||||
CORE_LIBS="-Wl,--require-defined=pcre_version $CORE_LIBS"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
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"
|
||||
|
||||
echo "/* DO NOT EDIT! This file was automatically generated by config */" > "$ngx_addon_dir/src/ngx_stream_lua_autoconf.h"
|
|
@ -0,0 +1,72 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/api/ngx_subsys_lua_api.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_API_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_API_H_INCLUDED_
|
||||
|
||||
|
||||
#include <nginx.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
|
||||
|
||||
#include <lua.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/* Public API for other Nginx modules */
|
||||
|
||||
|
||||
#define ngx_stream_lua_version 13
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint8_t type;
|
||||
|
||||
union {
|
||||
int b; /* boolean */
|
||||
lua_Number n; /* number */
|
||||
ngx_str_t s; /* string */
|
||||
} value;
|
||||
|
||||
} ngx_stream_lua_value_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
int len;
|
||||
/* this padding hole on 64-bit systems is expected */
|
||||
u_char *data;
|
||||
} ngx_stream_lua_ffi_str_t;
|
||||
|
||||
|
||||
lua_State *ngx_stream_lua_get_global_state(ngx_conf_t *cf);
|
||||
|
||||
|
||||
ngx_int_t ngx_stream_lua_add_package_preload(ngx_conf_t *cf,
|
||||
const char *package, lua_CFunction func);
|
||||
|
||||
ngx_int_t ngx_stream_lua_shared_dict_get(ngx_shm_zone_t *shm_zone,
|
||||
u_char *key_data, size_t key_len, ngx_stream_lua_value_t *value);
|
||||
|
||||
ngx_shm_zone_t *ngx_stream_lua_find_zone(u_char *name_data,
|
||||
size_t name_len);
|
||||
|
||||
ngx_shm_zone_t *ngx_stream_lua_shared_memory_add(ngx_conf_t *cf,
|
||||
ngx_str_t *name, size_t size, void *tag);
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_API_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,93 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ddebug.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* 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,221 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_api.c.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
#include "api/ngx_stream_lua_api.h"
|
||||
#include "ngx_stream_lua_shdict.h"
|
||||
#include "ngx_stream_lua_util.h"
|
||||
|
||||
|
||||
lua_State *
|
||||
ngx_stream_lua_get_global_state(ngx_conf_t *cf)
|
||||
{
|
||||
ngx_stream_lua_main_conf_t *lmcf;
|
||||
|
||||
lmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_lua_module);
|
||||
|
||||
return lmcf->lua;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static ngx_int_t ngx_stream_lua_shared_memory_init(ngx_shm_zone_t *shm_zone,
|
||||
void *data);
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_lua_add_package_preload(ngx_conf_t *cf, const char *package,
|
||||
lua_CFunction func)
|
||||
{
|
||||
lua_State *L;
|
||||
|
||||
ngx_stream_lua_main_conf_t *lmcf;
|
||||
ngx_stream_lua_preload_hook_t *hook;
|
||||
|
||||
lmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_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_stream_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_stream_lua_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name,
|
||||
size_t size, void *tag)
|
||||
{
|
||||
ngx_stream_lua_main_conf_t *lmcf;
|
||||
ngx_stream_lua_shm_zone_ctx_t *ctx;
|
||||
|
||||
ngx_shm_zone_t **zp;
|
||||
ngx_shm_zone_t *zone;
|
||||
ngx_int_t n;
|
||||
|
||||
lmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_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_stream_lua_shm_zone_ctx_t *) zone->data;
|
||||
return &ctx->zone;
|
||||
}
|
||||
|
||||
n = sizeof(ngx_stream_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_stream_lua_shared_memory_init;
|
||||
zone->data = ctx;
|
||||
|
||||
lmcf->requires_shm = 1;
|
||||
|
||||
return &ctx->zone;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_stream_lua_shared_memory_init(ngx_shm_zone_t *shm_zone, void *data)
|
||||
{
|
||||
ngx_stream_lua_shm_zone_ctx_t *octx = data;
|
||||
ngx_stream_lua_main_conf_t *lmcf;
|
||||
ngx_stream_lua_shm_zone_ctx_t *ctx;
|
||||
|
||||
ngx_shm_zone_t *ozone;
|
||||
void *odata;
|
||||
ngx_int_t rc;
|
||||
volatile ngx_cycle_t *saved_cycle;
|
||||
ngx_shm_zone_t *zone;
|
||||
|
||||
ctx = (ngx_stream_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 defined(nginx_version) && 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;
|
||||
}
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,161 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_args.c.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_stream_lua_args.h"
|
||||
#include "ngx_stream_lua_util.h"
|
||||
|
||||
|
||||
|
||||
|
||||
int
|
||||
ngx_stream_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_stream_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_stream_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_stream_lua_set_multi_value_table(L, top);
|
||||
}
|
||||
|
||||
if (max > 0 && ++count == max) {
|
||||
lua_pushliteral(L, "truncated");
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, ngx_cycle->log, 0,
|
||||
"stream lua hit query args limit %d",
|
||||
max);
|
||||
return 2;
|
||||
}
|
||||
|
||||
} else {
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
if (p != q || parsing_value) {
|
||||
src = q; dst = q;
|
||||
|
||||
ngx_stream_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_stream_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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_args.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_ARGS_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_ARGS_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
|
||||
int ngx_stream_lua_parse_args(lua_State *L, u_char *buf, u_char *last, int max);
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_ARGS_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,755 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_balancer.c.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_stream_lua_cache.h"
|
||||
#include "ngx_stream_lua_balancer.h"
|
||||
#include "ngx_stream_lua_util.h"
|
||||
#include "ngx_stream_lua_directive.h"
|
||||
|
||||
|
||||
struct ngx_stream_lua_balancer_peer_data_s {
|
||||
/* the round robin data must be first */
|
||||
ngx_stream_upstream_rr_peer_data_t rrp;
|
||||
|
||||
ngx_stream_lua_srv_conf_t *conf;
|
||||
ngx_stream_lua_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 (NGX_STREAM_SSL && HAVE_NGX_STREAM_BALANCER_EXPORT_PATCH)
|
||||
static ngx_int_t ngx_stream_lua_balancer_set_session(ngx_peer_connection_t *pc,
|
||||
void *data);
|
||||
static void ngx_stream_lua_balancer_save_session(ngx_peer_connection_t *pc,
|
||||
void *data);
|
||||
#endif
|
||||
static ngx_int_t ngx_stream_lua_balancer_init(ngx_conf_t *cf,
|
||||
ngx_stream_upstream_srv_conf_t *us);
|
||||
|
||||
|
||||
static ngx_int_t ngx_stream_lua_balancer_init_peer(ngx_stream_session_t *s,
|
||||
ngx_stream_upstream_srv_conf_t *us);
|
||||
|
||||
|
||||
#if (HAS_NGX_STREAM_PROXY_GET_NEXT_UPSTREAM_TRIES_PATCH)
|
||||
ngx_uint_t
|
||||
ngx_stream_proxy_get_next_upstream_tries(ngx_stream_session_t *s);
|
||||
#endif
|
||||
|
||||
|
||||
static ngx_int_t ngx_stream_lua_balancer_get_peer(ngx_peer_connection_t *pc,
|
||||
void *data);
|
||||
static ngx_int_t ngx_stream_lua_balancer_by_chunk(lua_State *L,
|
||||
ngx_stream_lua_request_t *r);
|
||||
void ngx_stream_lua_balancer_free_peer(ngx_peer_connection_t *pc, void *data,
|
||||
ngx_uint_t state);
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_lua_balancer_handler_file(ngx_stream_lua_request_t *r,
|
||||
ngx_stream_lua_srv_conf_t *lscf, lua_State *L)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
|
||||
rc = ngx_stream_lua_cache_loadfile(r->connection->log, L,
|
||||
lscf->balancer.src.data,
|
||||
lscf->balancer.src_key);
|
||||
if (rc != NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* make sure we have a valid code chunk */
|
||||
ngx_stream_lua_assert(lua_isfunction(L, -1));
|
||||
|
||||
return ngx_stream_lua_balancer_by_chunk(L, r);
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_lua_balancer_handler_inline(ngx_stream_lua_request_t *r,
|
||||
ngx_stream_lua_srv_conf_t *lscf, lua_State *L)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
|
||||
rc = ngx_stream_lua_cache_loadbuffer(r->connection->log, L,
|
||||
lscf->balancer.src.data,
|
||||
lscf->balancer.src.len,
|
||||
lscf->balancer.src_key,
|
||||
"=balancer_by_lua");
|
||||
if (rc != NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* make sure we have a valid code chunk */
|
||||
ngx_stream_lua_assert(lua_isfunction(L, -1));
|
||||
|
||||
return ngx_stream_lua_balancer_by_chunk(L, r);
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
ngx_stream_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_stream_lua_balancer_by_lua;
|
||||
cf->handler_conf = conf;
|
||||
|
||||
rv = ngx_stream_lua_conf_lua_block_parse(cf, cmd);
|
||||
|
||||
*cf = save;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
ngx_stream_lua_balancer_by_lua(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf)
|
||||
{
|
||||
u_char *p;
|
||||
u_char *name;
|
||||
ngx_str_t *value;
|
||||
|
||||
ngx_stream_lua_srv_conf_t *lscf = conf;
|
||||
ngx_stream_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_stream_lua_srv_conf_handler_pt) cmd->post;
|
||||
|
||||
if (cmd->post == ngx_stream_lua_balancer_handler_file) {
|
||||
/* Lua code in an external file */
|
||||
|
||||
name = ngx_stream_lua_rebase_path(cf->pool, value[1].data,
|
||||
value[1].len);
|
||||
if (name == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
lscf->balancer.src.data = name;
|
||||
lscf->balancer.src.len = ngx_strlen(name);
|
||||
|
||||
p = ngx_palloc(cf->pool, NGX_STREAM_LUA_FILE_KEY_LEN + 1);
|
||||
if (p == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
lscf->balancer.src_key = p;
|
||||
|
||||
p = ngx_copy(p, NGX_STREAM_LUA_FILE_TAG,
|
||||
NGX_STREAM_LUA_FILE_TAG_LEN);
|
||||
p = ngx_stream_lua_digest_hex(p, value[1].data, value[1].len);
|
||||
*p = '\0';
|
||||
|
||||
} else {
|
||||
/* inlined Lua code */
|
||||
|
||||
lscf->balancer.src = value[1];
|
||||
|
||||
p = ngx_palloc(cf->pool,
|
||||
sizeof("balancer_by_lua") + NGX_STREAM_LUA_INLINE_KEY_LEN);
|
||||
if (p == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
lscf->balancer.src_key = p;
|
||||
|
||||
p = ngx_copy(p, "balancer_by_lua", sizeof("balancer_by_lua") - 1);
|
||||
p = ngx_copy(p, NGX_STREAM_LUA_INLINE_TAG,
|
||||
NGX_STREAM_LUA_INLINE_TAG_LEN);
|
||||
p = ngx_stream_lua_digest_hex(p, value[1].data, value[1].len);
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
uscf = ngx_stream_conf_get_module_srv_conf(cf, ngx_stream_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_stream_lua_balancer_init;
|
||||
|
||||
uscf->flags = NGX_STREAM_UPSTREAM_CREATE
|
||||
|NGX_STREAM_UPSTREAM_WEIGHT
|
||||
|NGX_STREAM_UPSTREAM_MAX_FAILS
|
||||
|NGX_STREAM_UPSTREAM_FAIL_TIMEOUT
|
||||
|NGX_STREAM_UPSTREAM_DOWN;
|
||||
|
||||
return NGX_CONF_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_stream_lua_balancer_init(ngx_conf_t *cf,
|
||||
ngx_stream_upstream_srv_conf_t *us)
|
||||
{
|
||||
if (ngx_stream_upstream_init_round_robin(cf, us) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
/* this callback is called upon individual requests */
|
||||
us->peer.init = ngx_stream_lua_balancer_init_peer;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_stream_lua_balancer_init_peer(ngx_stream_session_t *s,
|
||||
ngx_stream_upstream_srv_conf_t *us)
|
||||
{
|
||||
ngx_stream_lua_srv_conf_t *bcf;
|
||||
ngx_stream_lua_balancer_peer_data_t *bp;
|
||||
ngx_stream_upstream_t *upstream;
|
||||
|
||||
ngx_stream_lua_request_t *r;
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
|
||||
ctx = ngx_stream_get_module_ctx(s, ngx_stream_lua_module);
|
||||
if (ctx == NULL) {
|
||||
ctx = ngx_stream_lua_create_ctx(s);
|
||||
|
||||
if (ctx == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
r = ctx->request;
|
||||
|
||||
upstream = s->upstream;
|
||||
|
||||
|
||||
bp = ngx_pcalloc(r->pool, sizeof(ngx_stream_lua_balancer_peer_data_t));
|
||||
if (bp == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
upstream->peer.data = &bp->rrp;
|
||||
|
||||
if (ngx_stream_upstream_init_round_robin_peer(s, us) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
upstream->peer.get = ngx_stream_lua_balancer_get_peer;
|
||||
upstream->peer.free = ngx_stream_lua_balancer_free_peer;
|
||||
|
||||
upstream->peer.notify = NULL;
|
||||
|
||||
#if (NGX_STREAM_SSL && HAVE_NGX_STREAM_BALANCER_EXPORT_PATCH)
|
||||
upstream->peer.set_session = ngx_stream_lua_balancer_set_session;
|
||||
upstream->peer.save_session = ngx_stream_lua_balancer_save_session;
|
||||
#endif
|
||||
|
||||
bcf = ngx_stream_conf_upstream_srv_conf(us, ngx_stream_lua_module);
|
||||
|
||||
bp->conf = bcf;
|
||||
bp->request = r;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_stream_lua_balancer_get_peer(ngx_peer_connection_t *pc, void *data)
|
||||
{
|
||||
lua_State *L;
|
||||
ngx_int_t rc;
|
||||
ngx_stream_lua_request_t *r;
|
||||
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
ngx_stream_lua_srv_conf_t *lscf;
|
||||
ngx_stream_lua_main_conf_t *lmcf;
|
||||
ngx_stream_lua_balancer_peer_data_t *bp = data;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, pc->log, 0,
|
||||
"lua balancer peer, tries: %ui", pc->tries);
|
||||
|
||||
lscf = bp->conf;
|
||||
|
||||
r = bp->request;
|
||||
|
||||
ngx_stream_lua_assert(lscf->balancer.handler && r);
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
|
||||
if (ctx == NULL) {
|
||||
|
||||
ctx = ngx_stream_lua_create_ctx(r->session);
|
||||
|
||||
if (ctx == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
L = ngx_stream_lua_get_lua_vm(r, ctx);
|
||||
|
||||
} else {
|
||||
L = ngx_stream_lua_get_lua_vm(r, ctx);
|
||||
|
||||
dd("reset ctx");
|
||||
ngx_stream_lua_reset_ctx(r, L, ctx);
|
||||
}
|
||||
|
||||
ctx->context = NGX_STREAM_LUA_CONTEXT_BALANCER;
|
||||
|
||||
bp->sockaddr = NULL;
|
||||
bp->socklen = 0;
|
||||
bp->more_tries = 0;
|
||||
bp->total_tries++;
|
||||
|
||||
lmcf = ngx_stream_lua_get_module_main_conf(r, ngx_stream_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_STREAM_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->session->upstream->peer.tries += bp->more_tries;
|
||||
}
|
||||
|
||||
dd("tries: %d", (int) r->session->upstream->peer.tries);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
return ngx_stream_upstream_get_round_robin_peer(pc, &bp->rrp);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_stream_lua_balancer_by_chunk(lua_State *L, ngx_stream_lua_request_t *r)
|
||||
{
|
||||
u_char *err_msg;
|
||||
size_t len;
|
||||
ngx_int_t rc;
|
||||
|
||||
/* init nginx context in Lua VM */
|
||||
ngx_stream_lua_set_req(L, r);
|
||||
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
ngx_stream_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_stream_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_stream_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;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_balancer_free_peer(ngx_peer_connection_t *pc, void *data,
|
||||
ngx_uint_t state)
|
||||
{
|
||||
ngx_stream_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_stream_upstream_free_round_robin_peer(pc, data, state);
|
||||
}
|
||||
|
||||
|
||||
#if (NGX_STREAM_SSL && HAVE_NGX_STREAM_BALANCER_EXPORT_PATCH)
|
||||
static ngx_int_t
|
||||
ngx_stream_lua_balancer_set_session(ngx_peer_connection_t *pc, void *data)
|
||||
{
|
||||
ngx_stream_lua_balancer_peer_data_t *bp = data;
|
||||
|
||||
if (bp->sockaddr && bp->socklen) {
|
||||
/* TODO */
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
return ngx_stream_upstream_set_round_robin_peer_session(pc, &bp->rrp);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_stream_lua_balancer_save_session(ngx_peer_connection_t *pc, void *data)
|
||||
{
|
||||
ngx_stream_lua_balancer_peer_data_t *bp = data;
|
||||
|
||||
if (bp->sockaddr && bp->socklen) {
|
||||
/* TODO */
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_stream_upstream_save_round_robin_peer_session(pc, &bp->rrp);
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
int
|
||||
ngx_stream_lua_ffi_balancer_set_current_peer(ngx_stream_lua_request_t *r,
|
||||
const u_char *addr, size_t addr_len, int port, char **err)
|
||||
{
|
||||
ngx_url_t url;
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
ngx_stream_upstream_t *u;
|
||||
|
||||
ngx_stream_lua_main_conf_t *lmcf;
|
||||
ngx_stream_lua_balancer_peer_data_t *bp;
|
||||
|
||||
if (r == NULL) {
|
||||
*err = "no request found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
u = r->session->upstream;
|
||||
|
||||
if (u == NULL) {
|
||||
*err = "no upstream found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
if (ctx == NULL) {
|
||||
*err = "no ctx found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if ((ctx->context & NGX_STREAM_LUA_CONTEXT_BALANCER) == 0) {
|
||||
*err = "API disabled in the current context";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
lmcf = ngx_stream_lua_get_module_main_conf(r, ngx_stream_lua_module);
|
||||
|
||||
/* we cannot read r->upstream->peer.data here directly because
|
||||
* it could be overridden by other modules like
|
||||
* ngx_stream_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;
|
||||
}
|
||||
|
||||
|
||||
#if (NGX_STREAM_HAVE_PROXY_TIMEOUT_FIELDS_PATCH)
|
||||
int
|
||||
ngx_stream_lua_ffi_balancer_set_timeouts(ngx_stream_lua_request_t *r,
|
||||
long connect_timeout, long timeout,
|
||||
char **err)
|
||||
{
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
ngx_stream_proxy_ctx_t *pctx;
|
||||
|
||||
if (r == NULL) {
|
||||
*err = "no request found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
if (ctx == NULL) {
|
||||
*err = "no ctx found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if ((ctx->context & NGX_STREAM_LUA_CONTEXT_BALANCER) == 0) {
|
||||
*err = "API disabled in the current context";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
pctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_proxy_module);
|
||||
ngx_stream_lua_assert(pctx != NULL);
|
||||
if (pctx == NULL) {
|
||||
*err = "no proxy ctx found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (connect_timeout > 0) {
|
||||
pctx->connect_timeout = connect_timeout;
|
||||
}
|
||||
|
||||
if (timeout > 0) {
|
||||
pctx->timeout = timeout;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
#else
|
||||
int
|
||||
ngx_stream_lua_ffi_balancer_set_timeouts(ngx_stream_lua_request_t *r,
|
||||
long connect_timeout, long timeout,
|
||||
char **err)
|
||||
{
|
||||
*err = "required Nginx patch not present, API disabled";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int
|
||||
ngx_stream_lua_ffi_balancer_set_more_tries(ngx_stream_lua_request_t *r,
|
||||
int count, char **err)
|
||||
{
|
||||
#if (HAS_NGX_STREAM_PROXY_GET_NEXT_UPSTREAM_TRIES_PATCH)
|
||||
ngx_uint_t max_tries, total;
|
||||
#endif
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
ngx_stream_upstream_t *u;
|
||||
|
||||
ngx_stream_lua_main_conf_t *lmcf;
|
||||
ngx_stream_lua_balancer_peer_data_t *bp;
|
||||
|
||||
if (r == NULL) {
|
||||
*err = "no request found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
u = r->session->upstream;
|
||||
|
||||
if (u == NULL) {
|
||||
*err = "no upstream found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
if (ctx == NULL) {
|
||||
*err = "no ctx found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if ((ctx->context & NGX_STREAM_LUA_CONTEXT_BALANCER) == 0) {
|
||||
*err = "API disabled in the current context";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
lmcf = ngx_stream_lua_get_module_main_conf(r, ngx_stream_lua_module);
|
||||
|
||||
bp = lmcf->balancer_peer_data;
|
||||
if (bp == NULL) {
|
||||
*err = "no upstream peer data found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
#if (HAS_NGX_STREAM_PROXY_GET_NEXT_UPSTREAM_TRIES_PATCH)
|
||||
max_tries = ngx_stream_proxy_get_next_upstream_tries(r->session);
|
||||
total = bp->total_tries + u->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_stream_lua_ffi_balancer_get_last_failure(ngx_stream_lua_request_t *r,
|
||||
int *status, char **err)
|
||||
{
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
ngx_stream_upstream_t *u;
|
||||
ngx_stream_lua_balancer_peer_data_t *bp;
|
||||
ngx_stream_lua_main_conf_t *lmcf;
|
||||
|
||||
if (r == NULL) {
|
||||
*err = "no request found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
u = r->session->upstream;
|
||||
|
||||
if (u == NULL) {
|
||||
*err = "no upstream found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
if (ctx == NULL) {
|
||||
*err = "no ctx found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if ((ctx->context & NGX_STREAM_LUA_CONTEXT_BALANCER) == 0) {
|
||||
*err = "API disabled in the current context";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
lmcf = ngx_stream_lua_get_module_main_conf(r, ngx_stream_lua_module);
|
||||
|
||||
bp = lmcf->balancer_peer_data;
|
||||
if (bp == NULL) {
|
||||
*err = "no upstream peer data found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
*status = 0;
|
||||
|
||||
return bp->last_peer_state;
|
||||
}
|
||||
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,35 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_balancer.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_BALANCER_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_BALANCER_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
ngx_int_t ngx_stream_lua_balancer_handler_inline(ngx_stream_lua_request_t *r,
|
||||
ngx_stream_lua_srv_conf_t *lscf, lua_State *L);
|
||||
|
||||
ngx_int_t ngx_stream_lua_balancer_handler_file(ngx_stream_lua_request_t *r,
|
||||
ngx_stream_lua_srv_conf_t *lscf, lua_State *L);
|
||||
|
||||
char *ngx_stream_lua_balancer_by_lua(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
|
||||
char *ngx_stream_lua_balancer_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_BALANCER_H_INCLUDED_ */
|
|
@ -0,0 +1,319 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_cache.c.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* 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_stream_lua_common.h"
|
||||
#include "ngx_stream_lua_cache.h"
|
||||
#include "ngx_stream_lua_clfactory.h"
|
||||
#include "ngx_stream_lua_util.h"
|
||||
|
||||
|
||||
/**
|
||||
* 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_stream_lua_cache_load_code(ngx_log_t *log, lua_State *L,
|
||||
const char *key)
|
||||
{
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
int rc;
|
||||
u_char *err;
|
||||
#endif
|
||||
|
||||
/* get code cache table */
|
||||
lua_pushlightuserdata(L, ngx_stream_lua_lightudata_mask(
|
||||
code_cache_key));
|
||||
lua_rawget(L, LUA_REGISTRYINDEX); /* sp++ */
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
lua_getfield(L, -1, key); /* sp++ */
|
||||
|
||||
if (lua_isfunction(L, -1)) {
|
||||
#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 */
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
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_stream_lua_cache_store_code(lua_State *L, const char *key)
|
||||
{
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
int rc;
|
||||
#endif
|
||||
|
||||
/* get code cache table */
|
||||
lua_pushlightuserdata(L, ngx_stream_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;
|
||||
}
|
||||
|
||||
lua_pushvalue(L, -2); /* closure cache closure */
|
||||
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_stream_lua_cache_loadbuffer(ngx_log_t *log, lua_State *L,
|
||||
const u_char *src, size_t src_len, const u_char *cache_key,
|
||||
const char *name)
|
||||
{
|
||||
int n;
|
||||
ngx_int_t rc;
|
||||
const char *err = NULL;
|
||||
|
||||
n = lua_gettop(L);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, log, 0,
|
||||
"looking up Lua code cache with key '%s'", cache_key);
|
||||
|
||||
rc = ngx_stream_lua_cache_load_code(log, L, (char *) cache_key);
|
||||
if (rc == NGX_OK) {
|
||||
/* code chunk loaded from cache, sp++ */
|
||||
dd("Code cache hit! cache key='%s', stack top=%d, script='%.*s'",
|
||||
cache_key, lua_gettop(L), (int) src_len, src);
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
/* rc == NGX_DECLINED */
|
||||
|
||||
dd("Code cache missed! cache key='%s', stack top=%d, script='%.*s'",
|
||||
cache_key, lua_gettop(L), (int) src_len, src);
|
||||
|
||||
/* load closure factory of inline script to the top of lua stack, sp++ */
|
||||
rc = ngx_stream_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_stream_lua_cache_store_code(L, (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_stream_lua_cache_loadfile(ngx_log_t *log, lua_State *L,
|
||||
const u_char *script, const u_char *cache_key)
|
||||
{
|
||||
int n;
|
||||
ngx_int_t rc, errcode = NGX_ERROR;
|
||||
u_char *p;
|
||||
u_char buf[NGX_STREAM_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");
|
||||
p = ngx_copy(buf, NGX_STREAM_LUA_FILE_TAG, NGX_STREAM_LUA_FILE_TAG_LEN);
|
||||
|
||||
p = ngx_stream_lua_digest_hex(p, script, ngx_strlen(script));
|
||||
|
||||
*p = '\0';
|
||||
cache_key = buf;
|
||||
|
||||
} else {
|
||||
dd("CACHE file key already pre-calculated");
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, log, 0,
|
||||
"looking up Lua code cache with key '%s'", cache_key);
|
||||
|
||||
rc = ngx_stream_lua_cache_load_code(log, L, (char *) cache_key);
|
||||
if (rc == NGX_OK) {
|
||||
/* code chunk loaded from cache, sp++ */
|
||||
dd("Code cache hit! cache key='%s', stack top=%d, file path='%s'",
|
||||
cache_key, lua_gettop(L), script);
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
/* rc == NGX_DECLINED */
|
||||
|
||||
dd("Code cache missed! cache key='%s', stack top=%d, file path='%s'",
|
||||
cache_key, lua_gettop(L), script);
|
||||
|
||||
/* load closure factory of script file to the top of lua stack, sp++ */
|
||||
rc = ngx_stream_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:
|
||||
errcode = NGX_STREAM_INTERNAL_SERVER_ERROR;
|
||||
/* 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_stream_lua_cache_store_code(L, (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;
|
||||
}
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,32 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_cache.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_CACHE_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_CACHE_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
ngx_int_t ngx_stream_lua_cache_loadbuffer(ngx_log_t *log, lua_State *L,
|
||||
const u_char *src, size_t src_len, const u_char *cache_key,
|
||||
const char *name);
|
||||
ngx_int_t ngx_stream_lua_cache_loadfile(ngx_log_t *log, lua_State *L,
|
||||
const u_char *script, const u_char *cache_key);
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_CACHE_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,937 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_clfactory.c.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include <nginx.h>
|
||||
#include "ngx_stream_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 dubug 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 lcoal 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_stream_lua_clfactory_file_type_e;
|
||||
|
||||
|
||||
enum {
|
||||
NGX_LUA_READER_BUFSIZE = 4096
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_stream_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_stream_lua_clfactory_file_ctx_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
int sent_begin;
|
||||
int sent_end;
|
||||
#endif
|
||||
const char *s;
|
||||
size_t size;
|
||||
} ngx_stream_lua_clfactory_buffer_ctx_t;
|
||||
|
||||
|
||||
static const char *ngx_stream_lua_clfactory_getF(lua_State *L, void *ud,
|
||||
size_t *size);
|
||||
static int ngx_stream_lua_clfactory_errfile(lua_State *L, const char *what,
|
||||
int fname_index);
|
||||
static const char *ngx_stream_lua_clfactory_getS(lua_State *L, void *ud,
|
||||
size_t *size);
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
static long ngx_stream_lua_clfactory_file_size(FILE *f);
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
int
|
||||
ngx_stream_lua_clfactory_bytecode_prepare(lua_State *L,
|
||||
ngx_stream_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_stream_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_stream_lua_clfactory_loadfile(lua_State *L, const char *filename)
|
||||
{
|
||||
int c, status, readstatus;
|
||||
ngx_flag_t sharp;
|
||||
|
||||
ngx_stream_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_stream_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_stream_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_stream_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_stream_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_stream_lua_clfactory_errfile(L, "read", fname_index);
|
||||
}
|
||||
|
||||
lua_remove(L, fname_index);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_lua_clfactory_loadbuffer(lua_State *L, const char *buff,
|
||||
size_t size, const char *name)
|
||||
{
|
||||
ngx_stream_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_stream_lua_clfactory_getS, &ls, name);
|
||||
}
|
||||
|
||||
|
||||
static const char *
|
||||
ngx_stream_lua_clfactory_getF(lua_State *L, void *ud, size_t *size)
|
||||
{
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
char *buf;
|
||||
#endif
|
||||
size_t num;
|
||||
|
||||
ngx_stream_lua_clfactory_file_ctx_t *lf;
|
||||
|
||||
lf = (ngx_stream_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_stream_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_stream_lua_clfactory_getS(lua_State *L, void *ud, size_t *size)
|
||||
{
|
||||
ngx_stream_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_stream_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,30 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_clfactory.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_CLFACTORY_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_CLFACTORY_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
ngx_int_t ngx_stream_lua_clfactory_loadfile(lua_State *L, const char *filename);
|
||||
ngx_int_t ngx_stream_lua_clfactory_loadbuffer(lua_State *L, const char *buff,
|
||||
size_t size, const char *name);
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_CLFACTORY_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,530 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_common.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_COMMON_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_COMMON_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_autoconf.h"
|
||||
|
||||
#include <nginx.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_stream.h>
|
||||
#include <ngx_md5.h>
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <luajit.h>
|
||||
#include <lualib.h>
|
||||
#include <lauxlib.h>
|
||||
|
||||
|
||||
#include "ngx_stream_lua_request.h"
|
||||
|
||||
|
||||
#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 !defined(nginx_version) || nginx_version < 1013006
|
||||
#error at least nginx 1.13.6 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_STREAM_LUA_USE_OCSP 1
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef NGX_HAVE_SHA1
|
||||
# if defined(nginx_version) && nginx_version >= 1011002
|
||||
# define NGX_HAVE_SHA1 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef MD5_DIGEST_LENGTH
|
||||
#define MD5_DIGEST_LENGTH 16
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef NGX_LUA_USE_ASSERT
|
||||
# include <assert.h>
|
||||
# define ngx_stream_lua_assert(a) assert(a)
|
||||
#else
|
||||
# define ngx_stream_lua_assert(a)
|
||||
#endif
|
||||
|
||||
|
||||
/* Nginx HTTP Lua Inline tag prefix */
|
||||
|
||||
#define NGX_STREAM_LUA_INLINE_TAG "nhli_"
|
||||
|
||||
#define NGX_STREAM_LUA_INLINE_TAG_LEN \
|
||||
(sizeof(NGX_STREAM_LUA_INLINE_TAG) - 1)
|
||||
|
||||
#define NGX_STREAM_LUA_INLINE_KEY_LEN \
|
||||
(NGX_STREAM_LUA_INLINE_TAG_LEN + 2 * MD5_DIGEST_LENGTH)
|
||||
|
||||
/* Nginx HTTP Lua File tag prefix */
|
||||
|
||||
#define NGX_STREAM_LUA_FILE_TAG "nhlf_"
|
||||
|
||||
#define NGX_STREAM_LUA_FILE_TAG_LEN \
|
||||
(sizeof(NGX_STREAM_LUA_FILE_TAG) - 1)
|
||||
|
||||
#define NGX_STREAM_LUA_FILE_KEY_LEN \
|
||||
(NGX_STREAM_LUA_FILE_TAG_LEN + 2 * MD5_DIGEST_LENGTH)
|
||||
|
||||
|
||||
#define NGX_STREAM_CLIENT_CLOSED_REQUEST 499
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef NGX_STREAM_LUA_MAX_ARGS
|
||||
#define NGX_STREAM_LUA_MAX_ARGS 100
|
||||
#endif
|
||||
|
||||
|
||||
/* must be within 16 bit */
|
||||
#define NGX_STREAM_LUA_CONTEXT_CONTENT 0x0001
|
||||
#define NGX_STREAM_LUA_CONTEXT_LOG 0x0002
|
||||
#define NGX_STREAM_LUA_CONTEXT_TIMER 0x0004
|
||||
#define NGX_STREAM_LUA_CONTEXT_INIT_WORKER 0x0008
|
||||
#define NGX_STREAM_LUA_CONTEXT_BALANCER 0x0010
|
||||
#define NGX_STREAM_LUA_CONTEXT_PREREAD 0x0020
|
||||
#define NGX_STREAM_LUA_CONTEXT_SSL_CERT 0x0040
|
||||
#define NGX_STREAM_LUA_CONTEXT_SSL_CLIENT_HELLO 0x0080
|
||||
|
||||
|
||||
#define NGX_STREAM_LUA_FFI_NO_REQ_CTX -100
|
||||
#define NGX_STREAM_LUA_FFI_BAD_CONTEXT -101
|
||||
|
||||
|
||||
#if (NGX_PTR_SIZE >= 8 && !defined(_WIN64))
|
||||
#define ngx_stream_lua_lightudata_mask(ludata) \
|
||||
((void *) ((uintptr_t) (&ngx_stream_lua_##ludata) & ((1UL << 47) - 1)))
|
||||
|
||||
#else
|
||||
#define ngx_stream_lua_lightudata_mask(ludata) \
|
||||
(&ngx_stream_lua_##ludata)
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct ngx_stream_lua_main_conf_s ngx_stream_lua_main_conf_t;
|
||||
typedef struct ngx_stream_lua_srv_conf_s ngx_stream_lua_srv_conf_t;
|
||||
|
||||
|
||||
typedef struct ngx_stream_lua_balancer_peer_data_s
|
||||
ngx_stream_lua_balancer_peer_data_t;
|
||||
|
||||
|
||||
typedef struct ngx_stream_lua_sema_mm_s ngx_stream_lua_sema_mm_t;
|
||||
|
||||
|
||||
typedef ngx_int_t (*ngx_stream_lua_main_conf_handler_pt)(ngx_log_t *log,
|
||||
ngx_stream_lua_main_conf_t *lmcf, lua_State *L);
|
||||
typedef ngx_int_t (*ngx_stream_lua_srv_conf_handler_pt)(
|
||||
ngx_stream_lua_request_t *r, ngx_stream_lua_srv_conf_t *lscf, lua_State *L);
|
||||
|
||||
|
||||
typedef struct {
|
||||
u_char *package;
|
||||
lua_CFunction loader;
|
||||
} ngx_stream_lua_preload_hook_t;
|
||||
|
||||
|
||||
struct ngx_stream_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 */
|
||||
|
||||
#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_stream_lua_preload_hook_t */
|
||||
|
||||
ngx_flag_t postponed_to_preread_phase_end;
|
||||
|
||||
ngx_stream_lua_main_conf_handler_pt init_handler;
|
||||
ngx_str_t init_src;
|
||||
|
||||
ngx_stream_lua_main_conf_handler_pt init_worker_handler;
|
||||
ngx_str_t init_worker_src;
|
||||
|
||||
ngx_stream_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_uint_t shm_zones_inited;
|
||||
|
||||
ngx_stream_lua_sema_mm_t *sema_mm;
|
||||
|
||||
ngx_uint_t malloc_trim_cycle; /* a cycle is defined as the number
|
||||
of reqeusts */
|
||||
ngx_uint_t malloc_trim_req_count;
|
||||
|
||||
|
||||
ngx_flag_t set_sa_restart;
|
||||
|
||||
unsigned requires_preread:1;
|
||||
|
||||
unsigned requires_log:1;
|
||||
unsigned requires_shm:1;
|
||||
unsigned requires_capture_log:1;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct ngx_stream_lua_srv_conf_s {
|
||||
#if (NGX_STREAM_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
|
||||
|
||||
struct {
|
||||
ngx_stream_lua_srv_conf_handler_pt ssl_cert_handler;
|
||||
ngx_str_t ssl_cert_src;
|
||||
u_char *ssl_cert_src_key;
|
||||
|
||||
ngx_stream_lua_srv_conf_handler_pt ssl_client_hello_handler;
|
||||
ngx_str_t ssl_client_hello_src;
|
||||
u_char *ssl_client_hello_src_key;
|
||||
} srv;
|
||||
#endif
|
||||
|
||||
ngx_flag_t enable_code_cache; /* whether to enable
|
||||
code cache */
|
||||
|
||||
ngx_stream_lua_handler_pt preread_handler;
|
||||
|
||||
ngx_stream_lua_handler_pt content_handler;
|
||||
ngx_stream_lua_handler_pt log_handler;
|
||||
|
||||
u_char *preread_chunkname;
|
||||
ngx_stream_complex_value_t preread_src; /* access_by_lua
|
||||
inline script/script
|
||||
file path */
|
||||
|
||||
u_char *preread_src_key; /* cached key for access_src */
|
||||
|
||||
u_char *content_chunkname;
|
||||
|
||||
ngx_stream_complex_value_t content_src;
|
||||
/* content_by_lua
|
||||
* inline script/script
|
||||
* file path */
|
||||
|
||||
u_char *content_src_key; /* cached key for content_src */
|
||||
|
||||
u_char *log_chunkname;
|
||||
ngx_stream_complex_value_t log_src;
|
||||
/* log_by_lua inline script/script
|
||||
* file path */
|
||||
|
||||
u_char *log_src_key;
|
||||
/* cached key for log_src */
|
||||
|
||||
|
||||
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 log_socket_errors;
|
||||
ngx_flag_t check_client_abort;
|
||||
|
||||
|
||||
struct {
|
||||
ngx_str_t src;
|
||||
u_char *src_key;
|
||||
|
||||
ngx_stream_lua_srv_conf_handler_pt handler;
|
||||
} balancer;
|
||||
|
||||
};
|
||||
|
||||
typedef ngx_stream_lua_srv_conf_t ngx_stream_lua_loc_conf_t;
|
||||
|
||||
|
||||
typedef enum {
|
||||
NGX_STREAM_LUA_USER_CORO_NOP = 0,
|
||||
NGX_STREAM_LUA_USER_CORO_RESUME = 1,
|
||||
NGX_STREAM_LUA_USER_CORO_YIELD = 2,
|
||||
NGX_STREAM_LUA_USER_THREAD_RESUME = 3
|
||||
} ngx_stream_lua_user_coro_op_t;
|
||||
|
||||
|
||||
typedef enum {
|
||||
NGX_STREAM_LUA_CO_RUNNING = 0, /* coroutine running */
|
||||
NGX_STREAM_LUA_CO_SUSPENDED = 1, /* coroutine suspended */
|
||||
NGX_STREAM_LUA_CO_NORMAL = 2, /* coroutine normal */
|
||||
NGX_STREAM_LUA_CO_DEAD = 3, /* coroutine dead */
|
||||
NGX_STREAM_LUA_CO_ZOMBIE = 4, /* coroutine zombie */
|
||||
} ngx_stream_lua_co_status_t;
|
||||
|
||||
|
||||
typedef struct ngx_stream_lua_co_ctx_s ngx_stream_lua_co_ctx_t;
|
||||
|
||||
typedef struct ngx_stream_lua_posted_thread_s ngx_stream_lua_posted_thread_t;
|
||||
|
||||
struct ngx_stream_lua_posted_thread_s {
|
||||
ngx_stream_lua_co_ctx_t *co_ctx;
|
||||
ngx_stream_lua_posted_thread_t *next;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct ngx_stream_lua_co_ctx_s {
|
||||
void *data; /* user state for cosockets */
|
||||
|
||||
lua_State *co;
|
||||
ngx_stream_lua_co_ctx_t *parent_co_ctx;
|
||||
|
||||
ngx_stream_lua_posted_thread_t *zombie_child_threads;
|
||||
|
||||
ngx_stream_lua_cleanup_pt cleanup;
|
||||
|
||||
|
||||
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_stream_lua_vm_state_t;
|
||||
|
||||
|
||||
typedef struct ngx_stream_lua_ctx_s {
|
||||
/* for lua_coce_cache off: */
|
||||
ngx_stream_lua_vm_state_t *vm_state;
|
||||
|
||||
ngx_stream_lua_request_t *request;
|
||||
ngx_stream_lua_handler_pt resume_handler;
|
||||
|
||||
ngx_stream_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_stream_lua_co_ctx_t entry_co_ctx; /* coroutine context for the
|
||||
entry coroutine */
|
||||
|
||||
ngx_stream_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_stream_lua_cleanup_pt *cleanup;
|
||||
ngx_stream_lua_cleanup_t *free_cleanup; /* free list of cleanup records */
|
||||
|
||||
|
||||
|
||||
ngx_int_t exit_code;
|
||||
|
||||
void *downstream;
|
||||
/* can be either
|
||||
* ngx_stream_lua_socket_tcp_upstream_t
|
||||
* or ngx_stream_lua_co_ctx_t */
|
||||
|
||||
|
||||
ngx_stream_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 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 entered_preread_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;
|
||||
unsigned peek_needs_more_data:1; /* whether req socket is waiting
|
||||
for more data in preread buf */
|
||||
} ngx_stream_lua_ctx_t;
|
||||
|
||||
|
||||
|
||||
|
||||
extern ngx_module_t ngx_stream_lua_module;
|
||||
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_COMMON_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,78 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_config.c.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_stream_lua_config.h"
|
||||
#include "api/ngx_stream_lua_api.h"
|
||||
|
||||
|
||||
static int ngx_stream_lua_config_prefix(lua_State *L);
|
||||
static int ngx_stream_lua_config_configure(lua_State *L);
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_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_stream_lua_config_prefix);
|
||||
lua_setfield(L, -2, "prefix");
|
||||
|
||||
lua_pushinteger(L, nginx_version);
|
||||
lua_setfield(L, -2, "nginx_version");
|
||||
|
||||
lua_pushinteger(L, ngx_stream_lua_version);
|
||||
lua_setfield(L, -2, "ngx_lua_version");
|
||||
|
||||
lua_pushcfunction(L, ngx_stream_lua_config_configure);
|
||||
lua_setfield(L, -2, "nginx_configure");
|
||||
|
||||
lua_pushliteral(L, "stream");
|
||||
lua_setfield(L, -2, "subsystem");
|
||||
|
||||
lua_setfield(L, -2, "config");
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_stream_lua_config_prefix(lua_State *L)
|
||||
{
|
||||
lua_pushlstring(L, (char *) ngx_cycle->prefix.data,
|
||||
ngx_cycle->prefix.len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_stream_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,27 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_config.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_CONFIG_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_CONFIG_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
void ngx_stream_lua_inject_config_api(lua_State *L);
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_CONFIG_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,51 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_consts.c.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_stream_lua_consts.h"
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_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");
|
||||
/* }}} */
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_consts.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_CONSTS_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_CONSTS_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
|
||||
|
||||
void ngx_stream_lua_inject_core_consts(lua_State *L);
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_CONSTS_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,353 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_contentby.c.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_stream_lua_contentby.h"
|
||||
#include "ngx_stream_lua_util.h"
|
||||
#include "ngx_stream_lua_exception.h"
|
||||
#include "ngx_stream_lua_cache.h"
|
||||
#include "ngx_stream_lua_probe.h"
|
||||
|
||||
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_lua_content_by_chunk(lua_State *L, ngx_stream_lua_request_t *r)
|
||||
{
|
||||
int co_ref;
|
||||
ngx_int_t rc;
|
||||
lua_State *co;
|
||||
ngx_event_t *rev;
|
||||
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
ngx_stream_lua_cleanup_t *cln;
|
||||
ngx_stream_lua_loc_conf_t *llcf;
|
||||
|
||||
dd("content by chunk");
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
|
||||
ngx_stream_lua_assert(ctx != NULL);
|
||||
|
||||
dd("reset ctx");
|
||||
ngx_stream_lua_reset_ctx(r, L, ctx);
|
||||
|
||||
ctx->entered_content_phase = 1;
|
||||
|
||||
/* {{{ new coroutine to handle request */
|
||||
co = ngx_stream_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_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_stream_lua_get_globals_table(co);
|
||||
lua_setfenv(co, -2);
|
||||
#endif
|
||||
|
||||
/* save nginx request in coroutine globals table */
|
||||
ngx_stream_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
|
||||
|
||||
/* {{{ register request cleanup hooks */
|
||||
if (ctx->cleanup == NULL) {
|
||||
cln = ngx_stream_lua_cleanup_add(r, 0);
|
||||
if (cln == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
cln->handler = ngx_stream_lua_request_cleanup_handler;
|
||||
cln->data = ctx;
|
||||
ctx->cleanup = &cln->handler;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
ctx->context = NGX_STREAM_LUA_CONTEXT_CONTENT;
|
||||
|
||||
llcf = ngx_stream_lua_get_module_loc_conf(r, ngx_stream_lua_module);
|
||||
|
||||
r->connection->read->handler = ngx_stream_lua_request_handler;
|
||||
r->connection->write->handler = ngx_stream_lua_request_handler;
|
||||
|
||||
if (llcf->check_client_abort) {
|
||||
r->read_event_handler = ngx_stream_lua_rd_check_broken_connection;
|
||||
|
||||
|
||||
rev = r->connection->read;
|
||||
|
||||
if (!rev->active) {
|
||||
if (ngx_add_event(rev, NGX_READ_EVENT, 0) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
r->read_event_handler = ngx_stream_lua_block_reading;
|
||||
}
|
||||
|
||||
rc = ngx_stream_lua_run_thread(L, r, ctx, 0);
|
||||
|
||||
if (rc == NGX_ERROR || rc >= NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (rc == NGX_AGAIN) {
|
||||
return ngx_stream_lua_content_run_posted_threads(L, r, ctx, 0);
|
||||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
return ngx_stream_lua_content_run_posted_threads(L, r, ctx, 1);
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_content_wev_handler(ngx_stream_lua_request_t *r)
|
||||
{
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, r->connection->log, 0,
|
||||
"lua ngx_stream_lua_content_wev_handler");
|
||||
|
||||
(void) ctx->resume_handler(r);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_content_handler(ngx_stream_session_t *s)
|
||||
{
|
||||
ngx_stream_lua_srv_conf_t *lscf;
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
ngx_int_t rc;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
|
||||
"stream lua content handler");
|
||||
|
||||
lscf = ngx_stream_get_module_srv_conf(s, ngx_stream_lua_module);
|
||||
|
||||
if (lscf->content_handler == NULL) {
|
||||
dd("no content handler found");
|
||||
ngx_stream_finalize_session(s, NGX_DECLINED);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ctx = ngx_stream_get_module_ctx(s, ngx_stream_lua_module);
|
||||
|
||||
dd("ctx = %p", ctx);
|
||||
|
||||
if (ctx == NULL) {
|
||||
ctx = ngx_stream_lua_create_ctx(s);
|
||||
if (ctx == NULL) {
|
||||
ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
dd("entered? %d", (int) ctx->entered_content_phase);
|
||||
|
||||
if (ctx->entered_content_phase) {
|
||||
dd("calling wev handler");
|
||||
rc = ctx->resume_handler(ctx->request);
|
||||
dd("wev handler returns %d", (int) rc);
|
||||
|
||||
ngx_stream_lua_finalize_request(ctx->request, rc);
|
||||
return;
|
||||
}
|
||||
|
||||
dd("setting entered");
|
||||
|
||||
ctx->entered_content_phase = 1;
|
||||
|
||||
dd("calling content handler");
|
||||
ngx_stream_lua_finalize_request(ctx->request,
|
||||
lscf->content_handler(ctx->request));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_lua_content_handler_file(ngx_stream_lua_request_t *r)
|
||||
{
|
||||
lua_State *L;
|
||||
ngx_int_t rc;
|
||||
u_char *script_path;
|
||||
ngx_str_t eval_src;
|
||||
|
||||
ngx_stream_lua_loc_conf_t *llcf;
|
||||
|
||||
llcf = ngx_stream_lua_get_module_loc_conf(r, ngx_stream_lua_module);
|
||||
|
||||
if (ngx_stream_complex_value(r->session, &llcf->content_src, &eval_src)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
script_path = ngx_stream_lua_rebase_path(r->pool, eval_src.data,
|
||||
eval_src.len);
|
||||
|
||||
if (script_path == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
L = ngx_stream_lua_get_lua_vm(r, NULL);
|
||||
|
||||
/* load Lua script file (w/ cache) sp = 1 */
|
||||
rc = ngx_stream_lua_cache_loadfile(r->connection->log, L, script_path,
|
||||
llcf->content_src_key);
|
||||
if (rc != NGX_OK) {
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* make sure we have a valid code chunk */
|
||||
ngx_stream_lua_assert(lua_isfunction(L, -1));
|
||||
|
||||
return ngx_stream_lua_content_by_chunk(L, r);
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_lua_content_handler_inline(ngx_stream_lua_request_t *r)
|
||||
{
|
||||
lua_State *L;
|
||||
ngx_int_t rc;
|
||||
|
||||
ngx_stream_lua_loc_conf_t *llcf;
|
||||
|
||||
llcf = ngx_stream_lua_get_module_loc_conf(r, ngx_stream_lua_module);
|
||||
|
||||
L = ngx_stream_lua_get_lua_vm(r, NULL);
|
||||
|
||||
/* load Lua inline script (w/ cache) sp = 1 */
|
||||
rc = ngx_stream_lua_cache_loadbuffer(r->connection->log, L,
|
||||
llcf->content_src.value.data,
|
||||
llcf->content_src.value.len,
|
||||
llcf->content_src_key,
|
||||
(const char *)
|
||||
llcf->content_chunkname);
|
||||
if (rc != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return ngx_stream_lua_content_by_chunk(L, r);
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_lua_content_run_posted_threads(lua_State *L,
|
||||
ngx_stream_lua_request_t *r, ngx_stream_lua_ctx_t *ctx, int n)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
|
||||
ngx_stream_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_stream_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_STREAM_LUA_CO_RUNNING) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ctx->cur_co_ctx = pt->co_ctx;
|
||||
|
||||
rc = ngx_stream_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_stream_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) {
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
/* n > 1 */
|
||||
|
||||
do {
|
||||
ngx_stream_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,37 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_contentby.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_CONTENT_BY_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_CONTENT_BY_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
ngx_int_t ngx_stream_lua_content_by_chunk(lua_State *L,
|
||||
ngx_stream_lua_request_t *r);
|
||||
void ngx_stream_lua_content_wev_handler(ngx_stream_lua_request_t *r);
|
||||
ngx_int_t ngx_stream_lua_content_handler_file(ngx_stream_lua_request_t *r);
|
||||
ngx_int_t ngx_stream_lua_content_handler_inline(ngx_stream_lua_request_t *r);
|
||||
|
||||
void ngx_stream_lua_content_handler(ngx_stream_session_t *r);
|
||||
|
||||
ngx_int_t ngx_stream_lua_content_run_posted_threads(lua_State *L,
|
||||
ngx_stream_lua_request_t *r, ngx_stream_lua_ctx_t *ctx, int n);
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_CONTENT_BY_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,164 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_control.c.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_stream_lua_control.h"
|
||||
#include "ngx_stream_lua_util.h"
|
||||
#include "ngx_stream_lua_coroutine.h"
|
||||
|
||||
|
||||
|
||||
|
||||
static int ngx_stream_lua_on_abort(lua_State *L);
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_inject_control_api(ngx_log_t *log, lua_State *L)
|
||||
{
|
||||
|
||||
/* ngx.on_abort */
|
||||
|
||||
lua_pushcfunction(L, ngx_stream_lua_on_abort);
|
||||
lua_setfield(L, -2, "on_abort");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static int
|
||||
ngx_stream_lua_on_abort(lua_State *L)
|
||||
{
|
||||
ngx_stream_lua_request_t *r;
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
ngx_stream_lua_co_ctx_t *coctx = NULL;
|
||||
ngx_stream_lua_loc_conf_t *llcf;
|
||||
|
||||
r = ngx_stream_lua_get_req(L);
|
||||
if (r == NULL) {
|
||||
return luaL_error(L, "no request found");
|
||||
}
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return luaL_error(L, "no request ctx found");
|
||||
}
|
||||
|
||||
ngx_stream_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_stream_lua_get_module_loc_conf(r, ngx_stream_lua_module);
|
||||
if (!llcf->check_client_abort) {
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "lua_check_client_abort is off");
|
||||
return 2;
|
||||
}
|
||||
|
||||
ngx_stream_lua_coroutine_create_helper(L, r, ctx, &coctx);
|
||||
|
||||
lua_pushlightuserdata(L, ngx_stream_lua_lightudata_mask(
|
||||
coroutines_key));
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_pushvalue(L, -2);
|
||||
|
||||
dd("on_wait thread 1: %p", lua_tothread(L, -1));
|
||||
|
||||
coctx->co_ref = luaL_ref(L, -2);
|
||||
lua_pop(L, 1);
|
||||
|
||||
coctx->is_uthread = 1;
|
||||
ctx->on_abort_co_ctx = coctx;
|
||||
|
||||
dd("on_wait thread 2: %p", coctx->co);
|
||||
|
||||
coctx->co_status = NGX_STREAM_LUA_CO_SUSPENDED;
|
||||
coctx->parent_co_ctx = ctx->cur_co_ctx;
|
||||
|
||||
lua_pushinteger(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_stream_lua_ffi_exit(ngx_stream_lua_request_t *r, int status, u_char *err,
|
||||
size_t *errlen)
|
||||
{
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
if (ctx == NULL) {
|
||||
*errlen = ngx_snprintf(err, *errlen, "no request ctx found") - err;
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
|
||||
if (ngx_stream_lua_ffi_check_context(ctx, NGX_STREAM_LUA_CONTEXT_CONTENT
|
||||
| NGX_STREAM_LUA_CONTEXT_TIMER
|
||||
| NGX_STREAM_LUA_CONTEXT_BALANCER
|
||||
| NGX_STREAM_LUA_CONTEXT_SSL_CLIENT_HELLO
|
||||
| NGX_STREAM_LUA_CONTEXT_SSL_CERT
|
||||
| NGX_STREAM_LUA_CONTEXT_PREREAD,
|
||||
err, errlen) != NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ctx->context & (NGX_STREAM_LUA_CONTEXT_SSL_CERT
|
||||
| NGX_STREAM_LUA_CONTEXT_SSL_CLIENT_HELLO ))
|
||||
{
|
||||
|
||||
#if (NGX_STREAM_SSL)
|
||||
|
||||
ctx->exit_code = status;
|
||||
ctx->exited = 1;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, r->connection->log, 0,
|
||||
"lua exit with code %d", status);
|
||||
|
||||
|
||||
return NGX_OK;
|
||||
|
||||
#else
|
||||
|
||||
return NGX_ERROR;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
ctx->exit_code = status;
|
||||
ctx->exited = 1;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, r->connection->log, 0,
|
||||
"lua exit with code %i", ctx->exit_code);
|
||||
|
||||
if (ctx->context & NGX_STREAM_LUA_CONTEXT_BALANCER) {
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_control.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_CONTROL_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_CONTROL_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
void ngx_stream_lua_inject_control_api(ngx_log_t *log, lua_State *L);
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_CONTROL_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,449 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_coroutine.c.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_stream_lua_coroutine.h"
|
||||
#include "ngx_stream_lua_util.h"
|
||||
#include "ngx_stream_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_stream_lua_coroutine_create(lua_State *L);
|
||||
static int ngx_stream_lua_coroutine_wrap(lua_State *L);
|
||||
static int ngx_stream_lua_coroutine_resume(lua_State *L);
|
||||
static int ngx_stream_lua_coroutine_yield(lua_State *L);
|
||||
static int ngx_stream_lua_coroutine_status(lua_State *L);
|
||||
|
||||
|
||||
static const ngx_str_t
|
||||
ngx_stream_lua_co_status_names[] =
|
||||
{
|
||||
ngx_string("running"),
|
||||
ngx_string("suspended"),
|
||||
ngx_string("normal"),
|
||||
ngx_string("dead"),
|
||||
ngx_string("zombie")
|
||||
};
|
||||
|
||||
|
||||
|
||||
static int
|
||||
ngx_stream_lua_coroutine_create(lua_State *L)
|
||||
{
|
||||
ngx_stream_lua_request_t *r;
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
|
||||
r = ngx_stream_lua_get_req(L);
|
||||
if (r == NULL) {
|
||||
return luaL_error(L, "no request found");
|
||||
}
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return luaL_error(L, "no request ctx found");
|
||||
}
|
||||
|
||||
return ngx_stream_lua_coroutine_create_helper(L, r, ctx, NULL);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_stream_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_stream_lua_coroutine_resume(L);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_stream_lua_coroutine_wrap(lua_State *L)
|
||||
{
|
||||
ngx_stream_lua_request_t *r;
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
ngx_stream_lua_co_ctx_t *coctx = NULL;
|
||||
|
||||
r = ngx_stream_lua_get_req(L);
|
||||
if (r == NULL) {
|
||||
return luaL_error(L, "no request found");
|
||||
}
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return luaL_error(L, "no request ctx found");
|
||||
}
|
||||
|
||||
ngx_stream_lua_coroutine_create_helper(L, r, ctx, &coctx);
|
||||
|
||||
coctx->is_wrap = 1;
|
||||
|
||||
lua_pushcclosure(L, ngx_stream_lua_coroutine_wrap_runner, 1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_stream_lua_coroutine_create_helper(lua_State *L,
|
||||
ngx_stream_lua_request_t *r, ngx_stream_lua_ctx_t *ctx,
|
||||
ngx_stream_lua_co_ctx_t **pcoctx)
|
||||
{
|
||||
lua_State *vm; /* the Lua VM */
|
||||
lua_State *co; /* new coroutine to be created */
|
||||
|
||||
/* co ctx for the new coroutine */
|
||||
ngx_stream_lua_co_ctx_t *coctx;
|
||||
|
||||
luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1,
|
||||
"Lua function expected");
|
||||
|
||||
ngx_stream_lua_check_context(L, ctx, NGX_STREAM_LUA_CONTEXT_YIELDABLE);
|
||||
|
||||
vm = ngx_stream_lua_get_lua_vm(r, ctx);
|
||||
|
||||
/* create new coroutine on root Lua state, so it always yields
|
||||
* to main Lua thread
|
||||
*/
|
||||
co = lua_newthread(vm);
|
||||
|
||||
ngx_stream_lua_probe_user_coroutine_create(r, L, co);
|
||||
|
||||
coctx = ngx_stream_lua_get_co_ctx(co, ctx);
|
||||
if (coctx == NULL) {
|
||||
coctx = ngx_stream_lua_create_co_ctx(r, ctx);
|
||||
if (coctx == NULL) {
|
||||
return luaL_error(L, "no memory");
|
||||
}
|
||||
|
||||
} else {
|
||||
ngx_memzero(coctx, sizeof(ngx_stream_lua_co_ctx_t));
|
||||
coctx->co_ref = LUA_NOREF;
|
||||
}
|
||||
|
||||
coctx->co = co;
|
||||
coctx->co_status = NGX_STREAM_LUA_CO_SUSPENDED;
|
||||
|
||||
#ifdef OPENRESTY_LUAJIT
|
||||
ngx_stream_lua_set_req(co, r);
|
||||
#else
|
||||
/* make new coroutine share globals of the parent coroutine.
|
||||
* NOTE: globals don't have to be separated! */
|
||||
ngx_stream_lua_get_globals_table(L);
|
||||
lua_xmove(L, co, 1);
|
||||
ngx_stream_lua_set_globals_table(co);
|
||||
#endif
|
||||
|
||||
lua_xmove(vm, L, 1); /* move coroutine from main thread to L */
|
||||
|
||||
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_stream_lua_coroutine_resume(lua_State *L)
|
||||
{
|
||||
lua_State *co;
|
||||
ngx_stream_lua_request_t *r;
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
ngx_stream_lua_co_ctx_t *coctx;
|
||||
ngx_stream_lua_co_ctx_t *p_coctx; /* parent co ctx */
|
||||
|
||||
co = lua_tothread(L, 1);
|
||||
|
||||
luaL_argcheck(L, co, 1, "coroutine expected");
|
||||
|
||||
r = ngx_stream_lua_get_req(L);
|
||||
if (r == NULL) {
|
||||
return luaL_error(L, "no request found");
|
||||
}
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return luaL_error(L, "no request ctx found");
|
||||
}
|
||||
|
||||
ngx_stream_lua_check_context(L, ctx, NGX_STREAM_LUA_CONTEXT_CONTENT
|
||||
| NGX_STREAM_LUA_CONTEXT_TIMER
|
||||
| NGX_STREAM_LUA_CONTEXT_SSL_CLIENT_HELLO
|
||||
| NGX_STREAM_LUA_CONTEXT_SSL_CERT
|
||||
| NGX_STREAM_LUA_CONTEXT_PREREAD
|
||||
);
|
||||
|
||||
p_coctx = ctx->cur_co_ctx;
|
||||
if (p_coctx == NULL) {
|
||||
return luaL_error(L, "no parent co ctx found");
|
||||
}
|
||||
|
||||
coctx = ngx_stream_lua_get_co_ctx(co, ctx);
|
||||
if (coctx == NULL) {
|
||||
return luaL_error(L, "no co ctx found");
|
||||
}
|
||||
|
||||
ngx_stream_lua_probe_user_coroutine_resume(r, L, co);
|
||||
|
||||
if (coctx->co_status != NGX_STREAM_LUA_CO_SUSPENDED) {
|
||||
dd("coroutine resume: %d", coctx->co_status);
|
||||
|
||||
lua_pushboolean(L, 0);
|
||||
lua_pushfstring(L, "cannot resume %s coroutine",
|
||||
ngx_stream_lua_co_status_names[coctx->co_status].data);
|
||||
return 2;
|
||||
}
|
||||
|
||||
p_coctx->co_status = NGX_STREAM_LUA_CO_NORMAL;
|
||||
|
||||
coctx->parent_co_ctx = p_coctx;
|
||||
|
||||
dd("set coroutine to running");
|
||||
coctx->co_status = NGX_STREAM_LUA_CO_RUNNING;
|
||||
|
||||
ctx->co_op = NGX_STREAM_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_stream_lua_coroutine_yield(lua_State *L)
|
||||
{
|
||||
ngx_stream_lua_request_t *r;
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
ngx_stream_lua_co_ctx_t *coctx;
|
||||
|
||||
r = ngx_stream_lua_get_req(L);
|
||||
if (r == NULL) {
|
||||
return luaL_error(L, "no request found");
|
||||
}
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return luaL_error(L, "no request ctx found");
|
||||
}
|
||||
|
||||
ngx_stream_lua_check_context(L, ctx, NGX_STREAM_LUA_CONTEXT_CONTENT
|
||||
| NGX_STREAM_LUA_CONTEXT_TIMER
|
||||
| NGX_STREAM_LUA_CONTEXT_SSL_CLIENT_HELLO
|
||||
| NGX_STREAM_LUA_CONTEXT_SSL_CERT
|
||||
| NGX_STREAM_LUA_CONTEXT_PREREAD
|
||||
);
|
||||
|
||||
coctx = ctx->cur_co_ctx;
|
||||
|
||||
coctx->co_status = NGX_STREAM_LUA_CO_SUSPENDED;
|
||||
|
||||
ctx->co_op = NGX_STREAM_LUA_USER_CORO_YIELD;
|
||||
|
||||
if (!coctx->is_uthread && coctx->parent_co_ctx) {
|
||||
dd("set coroutine to running");
|
||||
coctx->parent_co_ctx->co_status = NGX_STREAM_LUA_CO_RUNNING;
|
||||
|
||||
ngx_stream_lua_probe_user_coroutine_yield(r,
|
||||
coctx->parent_co_ctx->co, L);
|
||||
|
||||
} else {
|
||||
ngx_stream_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_stream_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_stream_lua_coroutine_create);
|
||||
lua_setfield(L, -2, "__create");
|
||||
|
||||
lua_pushcfunction(L, ngx_stream_lua_coroutine_wrap);
|
||||
lua_setfield(L, -2, "__wrap");
|
||||
|
||||
lua_pushcfunction(L, ngx_stream_lua_coroutine_resume);
|
||||
lua_setfield(L, -2, "__resume");
|
||||
|
||||
lua_pushcfunction(L, ngx_stream_lua_coroutine_yield);
|
||||
lua_setfield(L, -2, "__yield");
|
||||
|
||||
lua_pushcfunction(L, ngx_stream_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
|
||||
"return ours(...)\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_stream_lua_coroutine_status(lua_State *L)
|
||||
{
|
||||
lua_State *co; /* new coroutine to be created */
|
||||
ngx_stream_lua_request_t *r;
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
ngx_stream_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_stream_lua_get_req(L);
|
||||
if (r == NULL) {
|
||||
return luaL_error(L, "no request found");
|
||||
}
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return luaL_error(L, "no request ctx found");
|
||||
}
|
||||
|
||||
ngx_stream_lua_check_context(L, ctx, NGX_STREAM_LUA_CONTEXT_CONTENT
|
||||
| NGX_STREAM_LUA_CONTEXT_TIMER
|
||||
| NGX_STREAM_LUA_CONTEXT_SSL_CLIENT_HELLO
|
||||
| NGX_STREAM_LUA_CONTEXT_SSL_CERT
|
||||
| NGX_STREAM_LUA_CONTEXT_PREREAD
|
||||
);
|
||||
|
||||
coctx = ngx_stream_lua_get_co_ctx(co, ctx);
|
||||
if (coctx == NULL) {
|
||||
lua_pushlstring(L, (const char *)
|
||||
ngx_stream_lua_co_status_names[NGX_STREAM_LUA_CO_DEAD]
|
||||
.data,
|
||||
ngx_stream_lua_co_status_names[NGX_STREAM_LUA_CO_DEAD]
|
||||
.len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
dd("co status: %d", coctx->co_status);
|
||||
|
||||
lua_pushlstring(L, (const char *)
|
||||
ngx_stream_lua_co_status_names[coctx->co_status].data,
|
||||
ngx_stream_lua_co_status_names[coctx->co_status].len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,32 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_coroutine.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_COROUTINE_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_COROUTINE_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
void ngx_stream_lua_inject_coroutine_api(ngx_log_t *log, lua_State *L);
|
||||
|
||||
int ngx_stream_lua_coroutine_create_helper(lua_State *L,
|
||||
ngx_stream_lua_request_t *r, ngx_stream_lua_ctx_t *ctx,
|
||||
ngx_stream_lua_co_ctx_t **pcoctx);
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_COROUTINE_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,210 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_ctx.c.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_stream_lua_util.h"
|
||||
#include "ngx_stream_lua_ssl.h"
|
||||
#include "ngx_stream_lua_ctx.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
int ref;
|
||||
lua_State *vm;
|
||||
} ngx_stream_lua_ngx_ctx_cleanup_data_t;
|
||||
|
||||
|
||||
static ngx_int_t ngx_stream_lua_ngx_ctx_add_cleanup(ngx_stream_lua_request_t *r,
|
||||
ngx_pool_t *pool, int ref);
|
||||
static void ngx_stream_lua_ngx_ctx_cleanup(void *data);
|
||||
|
||||
|
||||
int
|
||||
ngx_stream_lua_ngx_set_ctx_helper(lua_State *L, ngx_stream_lua_request_t *r,
|
||||
ngx_stream_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_STREAM, r->connection->log, 0,
|
||||
"lua create ngx.ctx table for the current request");
|
||||
|
||||
lua_pushliteral(L, ngx_stream_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_stream_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_STREAM, r->connection->log, 0,
|
||||
"lua fetching existing ngx.ctx table for the current "
|
||||
"request");
|
||||
|
||||
lua_pushliteral(L, ngx_stream_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_stream_lua_ffi_get_ctx_ref(ngx_stream_lua_request_t *r, int *in_ssl_phase,
|
||||
int *ssl_ctx_ref)
|
||||
{
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
#if (NGX_STREAM_SSL)
|
||||
ngx_stream_lua_ssl_ctx_t *ssl_ctx;
|
||||
#endif
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return NGX_STREAM_LUA_FFI_NO_REQ_CTX;
|
||||
}
|
||||
|
||||
if (ctx->ctx_ref >= 0 || in_ssl_phase == NULL) {
|
||||
return ctx->ctx_ref;
|
||||
}
|
||||
|
||||
*in_ssl_phase = ctx->context & (NGX_STREAM_LUA_CONTEXT_SSL_CERT
|
||||
| NGX_STREAM_LUA_CONTEXT_SSL_CLIENT_HELLO);
|
||||
*ssl_ctx_ref = LUA_NOREF;
|
||||
|
||||
#if (NGX_STREAM_SSL)
|
||||
if (r->connection->ssl != NULL) {
|
||||
ssl_ctx = ngx_stream_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_stream_lua_ffi_set_ctx_ref(ngx_stream_lua_request_t *r, int ref)
|
||||
{
|
||||
ngx_pool_t *pool;
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
#if (NGX_STREAM_SSL)
|
||||
ngx_connection_t *c;
|
||||
ngx_stream_lua_ssl_ctx_t *ssl_ctx;
|
||||
#endif
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return NGX_STREAM_LUA_FFI_NO_REQ_CTX;
|
||||
}
|
||||
|
||||
#if (NGX_STREAM_SSL)
|
||||
if (ctx->context & (NGX_STREAM_LUA_CONTEXT_SSL_CERT
|
||||
| NGX_STREAM_LUA_CONTEXT_SSL_CLIENT_HELLO))
|
||||
{
|
||||
ssl_ctx = ngx_stream_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_stream_lua_ngx_ctx_add_cleanup(r, pool, ref) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_stream_lua_ngx_ctx_add_cleanup(ngx_stream_lua_request_t *r, ngx_pool_t *pool,
|
||||
int ref)
|
||||
{
|
||||
lua_State *L;
|
||||
ngx_pool_cleanup_t *cln;
|
||||
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
ngx_stream_lua_ngx_ctx_cleanup_data_t *data;
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
L = ngx_stream_lua_get_lua_vm(r, ctx);
|
||||
|
||||
cln = ngx_pool_cleanup_add(pool,
|
||||
sizeof(ngx_stream_lua_ngx_ctx_cleanup_data_t));
|
||||
if (cln == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
cln->handler = ngx_stream_lua_ngx_ctx_cleanup;
|
||||
|
||||
data = cln->data;
|
||||
data->vm = L;
|
||||
data->ref = ref;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_stream_lua_ngx_ctx_cleanup(void *data)
|
||||
{
|
||||
lua_State *L;
|
||||
|
||||
ngx_stream_lua_ngx_ctx_cleanup_data_t *clndata = data;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, ngx_cycle->log, 0,
|
||||
"lua release ngx.ctx at ref %d", clndata->ref);
|
||||
|
||||
L = clndata->vm;
|
||||
|
||||
lua_pushliteral(L, ngx_stream_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,29 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_ctx.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_CTX_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_CTX_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
int ngx_stream_lua_ngx_set_ctx_helper(lua_State *L, ngx_stream_lua_request_t *r,
|
||||
ngx_stream_lua_ctx_t *ctx, int index);
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_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,70 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_directive.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_DIRECTIVE_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_DIRECTIVE_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
char *ngx_stream_lua_shared_dict(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *ngx_stream_lua_package_cpath(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *ngx_stream_lua_package_path(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *ngx_stream_lua_content_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *ngx_stream_lua_content_by_lua(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *ngx_stream_lua_log_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *ngx_stream_lua_log_by_lua(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
|
||||
|
||||
char *ngx_stream_lua_init_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *ngx_stream_lua_init_by_lua(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *ngx_stream_lua_init_worker_by_lua_block(ngx_conf_t *cf,
|
||||
ngx_command_t *cmd, void *conf);
|
||||
char *ngx_stream_lua_init_worker_by_lua(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *ngx_stream_lua_code_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
char *ngx_stream_lua_load_resty_core(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
|
||||
|
||||
char *
|
||||
ngx_stream_lua_preread_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
char *
|
||||
ngx_stream_lua_preread_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
|
||||
char *
|
||||
ngx_stream_lua_add_variable(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
|
||||
char *ngx_stream_lua_conf_lua_block_parse(ngx_conf_t *cf,
|
||||
ngx_command_t *cmd);
|
||||
|
||||
|
||||
char *ngx_stream_lua_capture_error_log(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_DIRECTIVE_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,66 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_exception.c.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_stream_lua_exception.h"
|
||||
#include "ngx_stream_lua_util.h"
|
||||
|
||||
|
||||
/* longjmp mark for restoring nginx execution after Lua VM crashing */
|
||||
jmp_buf ngx_stream_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_stream_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,41 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_exception.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_EXCEPTION_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_EXCEPTION_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
#define NGX_LUA_EXCEPTION_TRY \
|
||||
if (setjmp(ngx_stream_lua_exception) == 0)
|
||||
|
||||
#define NGX_LUA_EXCEPTION_CATCH \
|
||||
else
|
||||
|
||||
#define NGX_LUA_EXCEPTION_THROW(x) \
|
||||
longjmp(ngx_stream_lua_exception, (x))
|
||||
|
||||
|
||||
extern jmp_buf ngx_stream_lua_exception;
|
||||
|
||||
|
||||
int ngx_stream_lua_atpanic(lua_State *L);
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_EXCEPTION_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,50 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_initby.c.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
|
||||
#include "ddebug.h"
|
||||
#include "ngx_stream_lua_initby.h"
|
||||
#include "ngx_stream_lua_util.h"
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_lua_init_by_inline(ngx_log_t *log, ngx_stream_lua_main_conf_t *lmcf,
|
||||
lua_State *L)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = luaL_loadbuffer(L, (char *) lmcf->init_src.data,
|
||||
lmcf->init_src.len, "=init_by_lua")
|
||||
|| ngx_stream_lua_do_call(log, L);
|
||||
|
||||
return ngx_stream_lua_report(log, L, status, "init_by_lua");
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_lua_init_by_file(ngx_log_t *log, ngx_stream_lua_main_conf_t *lmcf,
|
||||
lua_State *L)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = luaL_loadfile(L, (char *) lmcf->init_src.data)
|
||||
|| ngx_stream_lua_do_call(log, L);
|
||||
|
||||
return ngx_stream_lua_report(log, L, status, "init_by_lua_file");
|
||||
}
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,31 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_initby.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_INITBY_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_INITBY_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
ngx_int_t ngx_stream_lua_init_by_inline(ngx_log_t *log,
|
||||
ngx_stream_lua_main_conf_t *lmcf, lua_State *L);
|
||||
|
||||
ngx_int_t ngx_stream_lua_init_by_file(ngx_log_t *log,
|
||||
ngx_stream_lua_main_conf_t *lmcf, lua_State *L);
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_INITBY_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,366 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_initworkerby.c.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_stream_lua_initworkerby.h"
|
||||
#include "ngx_stream_lua_util.h"
|
||||
|
||||
#include "ngx_stream_lua_contentby.h"
|
||||
|
||||
|
||||
|
||||
static u_char *ngx_stream_lua_log_init_worker_error(ngx_log_t *log,
|
||||
u_char *buf, size_t len);
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_lua_init_worker(ngx_cycle_t *cycle)
|
||||
{
|
||||
char *rv;
|
||||
void *cur, *prev;
|
||||
ngx_uint_t i;
|
||||
ngx_conf_t conf;
|
||||
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_stream_module_t *module;
|
||||
ngx_stream_lua_request_t *r = NULL;
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
ngx_stream_conf_ctx_t *conf_ctx, stream_ctx;
|
||||
|
||||
ngx_stream_lua_main_conf_t *lmcf;
|
||||
|
||||
ngx_conf_file_t *conf_file;
|
||||
ngx_stream_session_t *s;
|
||||
|
||||
ngx_stream_core_srv_conf_t *cscf, *top_cscf;
|
||||
ngx_stream_lua_srv_conf_t *lscf, *top_lscf;
|
||||
|
||||
lmcf = ngx_stream_cycle_get_module_main_conf(cycle, ngx_stream_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_STREAM, 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;
|
||||
}
|
||||
|
||||
|
||||
#endif /* NGX_WIN32 */
|
||||
|
||||
#if (NGX_STREAM_LUA_HAVE_SA_RESTART)
|
||||
if (lmcf->set_sa_restart) {
|
||||
ngx_stream_lua_set_sa_restart(ngx_cycle->log);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (lmcf->init_worker_handler == NULL) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
conf_ctx = (ngx_stream_conf_ctx_t *)
|
||||
cycle->conf_ctx[ngx_stream_module.index];
|
||||
stream_ctx.main_conf = conf_ctx->main_conf;
|
||||
|
||||
top_cscf = conf_ctx->srv_conf[ngx_stream_core_module.ctx_index];
|
||||
top_lscf = conf_ctx->srv_conf[ngx_stream_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_stream_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 || 1,
|
||||
sizeof(ngx_listening_t))
|
||||
!= NGX_OK)
|
||||
{
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (ngx_array_init(&fake_cycle->paths, cycle->pool, 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 || 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_file = ngx_pcalloc(fake_cycle->pool, sizeof(ngx_conf_file_t));
|
||||
if (conf_file == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
/* workaround to make ngx_stream_core_create_srv_conf not SEGFAULT */
|
||||
conf_file->file.name.data = (u_char *) "dummy";
|
||||
conf_file->file.name.len = sizeof("dummy") - 1;
|
||||
conf_file->line = 1;
|
||||
conf.conf_file = conf_file;
|
||||
|
||||
conf.ctx = &stream_ctx;
|
||||
conf.cycle = fake_cycle;
|
||||
conf.pool = fake_cycle->pool;
|
||||
conf.log = cycle->log;
|
||||
|
||||
|
||||
stream_ctx.srv_conf = ngx_pcalloc(conf.pool,
|
||||
sizeof(void *) * ngx_stream_max_module);
|
||||
if (stream_ctx.srv_conf == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
#if defined(nginx_version) && nginx_version >= 1009011
|
||||
modules = cycle->modules;
|
||||
#else
|
||||
modules = ngx_modules;
|
||||
#endif
|
||||
|
||||
for (i = 0; modules[i]; i++) {
|
||||
if (modules[i]->type != NGX_STREAM_MODULE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
module = modules[i]->ctx;
|
||||
|
||||
if (module->create_srv_conf) {
|
||||
cur = module->create_srv_conf(&conf);
|
||||
if (cur == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
stream_ctx.srv_conf[modules[i]->ctx_index] = cur;
|
||||
|
||||
if (modules[i]->ctx_index == ngx_stream_core_module.ctx_index) {
|
||||
cscf = cur;
|
||||
/* just to silence the error in
|
||||
* ngx_stream_core_merge_srv_conf */
|
||||
cscf->handler = ngx_stream_lua_content_handler;
|
||||
}
|
||||
|
||||
if (module->merge_srv_conf) {
|
||||
if (modules[i] == &ngx_stream_lua_module) {
|
||||
prev = top_lscf;
|
||||
|
||||
} else if (modules[i] == &ngx_stream_core_module) {
|
||||
prev = top_cscf;
|
||||
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ngx_destroy_pool(conf.temp_pool);
|
||||
conf.temp_pool = NULL;
|
||||
|
||||
c = ngx_stream_lua_create_fake_connection(NULL);
|
||||
if (c == NULL) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
c->log->handler = ngx_stream_lua_log_init_worker_error;
|
||||
|
||||
s = ngx_stream_lua_create_fake_session(c);
|
||||
if (s == NULL) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
s->main_conf = stream_ctx.main_conf;
|
||||
s->srv_conf = stream_ctx.srv_conf;
|
||||
|
||||
cscf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module);
|
||||
|
||||
lscf = ngx_stream_get_module_srv_conf(s, ngx_stream_lua_module);
|
||||
|
||||
if (top_lscf->log_socket_errors != NGX_CONF_UNSET) {
|
||||
lscf->log_socket_errors = top_lscf->log_socket_errors;
|
||||
}
|
||||
|
||||
if (top_cscf->resolver != NULL) {
|
||||
cscf->resolver = top_cscf->resolver;
|
||||
}
|
||||
|
||||
if (top_cscf->resolver_timeout != NGX_CONF_UNSET_MSEC) {
|
||||
cscf->resolver_timeout = top_cscf->resolver_timeout;
|
||||
}
|
||||
|
||||
#if defined(nginx_version) && nginx_version >= 1009000
|
||||
ngx_set_connection_log(s->connection, cscf->error_log);
|
||||
|
||||
#else
|
||||
#endif
|
||||
|
||||
ctx = ngx_stream_lua_create_ctx(s);
|
||||
if (ctx == NULL) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
r = ctx->request;
|
||||
|
||||
ctx->context = NGX_STREAM_LUA_CONTEXT_INIT_WORKER;
|
||||
ctx->cur_co_ctx = NULL;
|
||||
r->read_event_handler = ngx_stream_lua_block_reading;
|
||||
|
||||
ngx_stream_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_stream_lua_close_fake_connection(c);
|
||||
}
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_lua_init_worker_by_inline(ngx_log_t *log,
|
||||
ngx_stream_lua_main_conf_t *lmcf, lua_State *L)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = luaL_loadbuffer(L, (char *) lmcf->init_worker_src.data,
|
||||
lmcf->init_worker_src.len, "=init_worker_by_lua")
|
||||
|| ngx_stream_lua_do_call(log, L);
|
||||
|
||||
return ngx_stream_lua_report(log, L, status, "init_worker_by_lua");
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_lua_init_worker_by_file(ngx_log_t *log,
|
||||
ngx_stream_lua_main_conf_t *lmcf, lua_State *L)
|
||||
{
|
||||
int status;
|
||||
|
||||
status = luaL_loadfile(L, (char *) lmcf->init_worker_src.data)
|
||||
|| ngx_stream_lua_do_call(log, L);
|
||||
|
||||
return ngx_stream_lua_report(log, L, status, "init_worker_by_lua_file");
|
||||
}
|
||||
|
||||
|
||||
static u_char *
|
||||
ngx_stream_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*");
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_initworkerby.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_INITWORKERBY_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_INITWORKERBY_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
ngx_int_t ngx_stream_lua_init_worker_by_inline(ngx_log_t *log,
|
||||
ngx_stream_lua_main_conf_t *lmcf, lua_State *L);
|
||||
|
||||
ngx_int_t ngx_stream_lua_init_worker_by_file(ngx_log_t *log,
|
||||
ngx_stream_lua_main_conf_t *lmcf, lua_State *L);
|
||||
|
||||
ngx_int_t ngx_stream_lua_init_worker(ngx_cycle_t *cycle);
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_INITWORKERBY_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,146 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_input_filters.c.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) by OpenResty Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_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_stream_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_stream_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_stream_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_STREAM, log, 0,
|
||||
"stream 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_STREAM, log, 0,
|
||||
"stream lua read partial line data: %*s",
|
||||
dst - begin, begin);
|
||||
#endif
|
||||
|
||||
buf_in->buf->last = dst;
|
||||
|
||||
return NGX_AGAIN;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_input_filters.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) by OpenResty Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_INPUT_FILTERS_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_INPUT_FILTERS_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
ngx_int_t ngx_stream_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_stream_lua_read_all(ngx_buf_t *src, ngx_chain_t *buf_in,
|
||||
ssize_t bytes, ngx_log_t *log);
|
||||
|
||||
ngx_int_t ngx_stream_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_stream_lua_read_line(ngx_buf_t *src, ngx_chain_t *buf_in,
|
||||
ssize_t bytes, ngx_log_t *log);
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_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,25 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_lex.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_LEX_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_LEX_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
int ngx_stream_lua_lex(const u_char *const s, size_t len, int *const ovec);
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,463 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_log.c.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_stream_lua_log.h"
|
||||
#include "ngx_stream_lua_util.h"
|
||||
|
||||
#include "ngx_stream_lua_log_ringbuf.h"
|
||||
|
||||
|
||||
static int ngx_stream_lua_print(lua_State *L);
|
||||
static int ngx_stream_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_stream_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_stream_lua_ngx_log(lua_State *L)
|
||||
{
|
||||
ngx_log_t *log;
|
||||
ngx_stream_lua_request_t *r;
|
||||
const char *msg;
|
||||
int level;
|
||||
|
||||
r = ngx_stream_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, "stream [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_stream_lua_print(lua_State *L)
|
||||
{
|
||||
ngx_log_t *log;
|
||||
ngx_stream_lua_request_t *r;
|
||||
|
||||
r = ngx_stream_lua_get_req(L);
|
||||
|
||||
if (r && r->connection && r->connection->log) {
|
||||
log = r->connection->log;
|
||||
|
||||
} else {
|
||||
log = ngx_cycle->log;
|
||||
}
|
||||
|
||||
return log_wrapper(log, "stream [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:
|
||||
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:
|
||||
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_stream_lua_inject_log_api(lua_State *L)
|
||||
{
|
||||
ngx_stream_lua_inject_log_consts(L);
|
||||
|
||||
lua_pushcfunction(L, ngx_stream_lua_ngx_log);
|
||||
lua_setfield(L, -2, "log");
|
||||
|
||||
lua_pushcfunction(L, ngx_stream_lua_print);
|
||||
lua_setglobal(L, "print");
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_stream_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_stream_lua_capture_log_handler(ngx_log_t *log,
|
||||
ngx_uint_t level, u_char *buf, size_t n)
|
||||
{
|
||||
ngx_stream_lua_log_ringbuf_t *ringbuf;
|
||||
|
||||
dd("enter");
|
||||
|
||||
ringbuf = (ngx_stream_lua_log_ringbuf_t *)
|
||||
ngx_cycle->intercept_error_log_data;
|
||||
|
||||
if (level > ringbuf->filter_level) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
ngx_stream_lua_log_ringbuf_write(ringbuf, level, buf, n);
|
||||
|
||||
dd("capture log: %s\n", buf);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int
|
||||
ngx_stream_lua_ffi_errlog_set_filter_level(int level, u_char *err,
|
||||
size_t *errlen)
|
||||
{
|
||||
#ifdef HAVE_INTERCEPT_ERROR_LOG_PATCH
|
||||
ngx_stream_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_stream_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_stream_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_stream_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_stream_lua_ffi_errlog_get_sys_filter_level(ngx_stream_lua_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_stream_lua_ffi_raw_log(ngx_stream_lua_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,33 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_log.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_LOG_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_LOG_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
void ngx_stream_lua_inject_log_api(lua_State *L);
|
||||
|
||||
#ifdef HAVE_INTERCEPT_ERROR_LOG_PATCH
|
||||
ngx_int_t ngx_stream_lua_capture_log_handler(ngx_log_t *log,
|
||||
ngx_uint_t level, u_char *buf, size_t n);
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_LOG_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,236 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_log_ringbuf.c.tt2
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
#include "ngx_stream_lua_log_ringbuf.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
double time;
|
||||
unsigned len;
|
||||
unsigned log_level;
|
||||
} ngx_stream_lua_log_ringbuf_header_t;
|
||||
|
||||
|
||||
enum {
|
||||
HEADER_LEN = sizeof(ngx_stream_lua_log_ringbuf_header_t)
|
||||
};
|
||||
|
||||
|
||||
static void *ngx_stream_lua_log_ringbuf_next_header(
|
||||
ngx_stream_lua_log_ringbuf_t *rb);
|
||||
static void ngx_stream_lua_log_ringbuf_append(
|
||||
ngx_stream_lua_log_ringbuf_t *rb, int log_level, void *buf, int n);
|
||||
static size_t ngx_stream_lua_log_ringbuf_free_spaces(
|
||||
ngx_stream_lua_log_ringbuf_t *rb);
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_log_ringbuf_init(ngx_stream_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_stream_lua_log_ringbuf_reset(ngx_stream_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_stream_lua_log_ringbuf_next_header(ngx_stream_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_stream_lua_log_ringbuf_append(ngx_stream_lua_log_ringbuf_t *rb,
|
||||
int log_level, void *buf, int n)
|
||||
{
|
||||
ngx_stream_lua_log_ringbuf_header_t *head;
|
||||
ngx_time_t *tp;
|
||||
|
||||
head = (ngx_stream_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_stream_lua_log_ringbuf_throw_away(ngx_stream_lua_log_ringbuf_t *rb)
|
||||
{
|
||||
ngx_stream_lua_log_ringbuf_header_t *head;
|
||||
|
||||
if (rb->count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
head = (ngx_stream_lua_log_ringbuf_header_t *) rb->head;
|
||||
|
||||
rb->head += HEADER_LEN + head->len;
|
||||
rb->count--;
|
||||
|
||||
if (rb->count == 0) {
|
||||
ngx_stream_lua_log_ringbuf_reset(rb);
|
||||
}
|
||||
|
||||
rb->head = ngx_stream_lua_log_ringbuf_next_header(rb);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* size of free spaces */
|
||||
static size_t
|
||||
ngx_stream_lua_log_ringbuf_free_spaces(ngx_stream_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_stream_lua_log_ringbuf_write(ngx_stream_lua_log_ringbuf_t *rb,
|
||||
int log_level, void *buf, size_t n)
|
||||
{
|
||||
if (n + HEADER_LEN > rb->size) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (ngx_stream_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_stream_lua_log_ringbuf_throw_away(rb);
|
||||
}
|
||||
|
||||
rb->sentinel = rb->tail;
|
||||
rb->tail = rb->data;
|
||||
}
|
||||
|
||||
while (ngx_stream_lua_log_ringbuf_free_spaces(rb) < n + HEADER_LEN) {
|
||||
ngx_stream_lua_log_ringbuf_throw_away(rb);
|
||||
}
|
||||
}
|
||||
|
||||
ngx_stream_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_stream_lua_log_ringbuf_read(ngx_stream_lua_log_ringbuf_t *rb,
|
||||
int *log_level, void **buf, size_t *n, double *log_time)
|
||||
{
|
||||
ngx_stream_lua_log_ringbuf_header_t *head;
|
||||
|
||||
if (rb->count == 0) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
head = (ngx_stream_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_stream_lua_log_ringbuf_reset(rb);
|
||||
}
|
||||
|
||||
rb->head = ngx_stream_lua_log_ringbuf_next_header(rb);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,39 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_log_ringbuf.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_RINGBUF_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_RINGBUF_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_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_stream_lua_log_ringbuf_t;
|
||||
|
||||
|
||||
void ngx_stream_lua_log_ringbuf_init(ngx_stream_lua_log_ringbuf_t *rb,
|
||||
void *buf, size_t len);
|
||||
void ngx_stream_lua_log_ringbuf_reset(ngx_stream_lua_log_ringbuf_t *rb);
|
||||
ngx_int_t ngx_stream_lua_log_ringbuf_read(ngx_stream_lua_log_ringbuf_t *rb,
|
||||
int *log_level, void **buf, size_t *n, double *log_time);
|
||||
ngx_int_t ngx_stream_lua_log_ringbuf_write(ngx_stream_lua_log_ringbuf_t *rb,
|
||||
int log_level, void *buf, size_t n);
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_RINGBUF_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,275 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_logby.c.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_stream_lua_directive.h"
|
||||
#include "ngx_stream_lua_logby.h"
|
||||
#include "ngx_stream_lua_exception.h"
|
||||
#include "ngx_stream_lua_util.h"
|
||||
#include "ngx_stream_lua_pcrefix.h"
|
||||
#include "ngx_stream_lua_cache.h"
|
||||
#include "ngx_stream_lua_misc.h"
|
||||
#include "ngx_stream_lua_consts.h"
|
||||
#include "ngx_stream_lua_util.h"
|
||||
#include "ngx_stream_lua_exception.h"
|
||||
#if (NGX_STREAM_LUA_HAVE_MALLOC_TRIM)
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
|
||||
static ngx_int_t ngx_stream_lua_log_by_chunk(lua_State *L,
|
||||
ngx_stream_lua_request_t *r);
|
||||
|
||||
|
||||
static void
|
||||
ngx_stream_lua_log_by_lua_env(lua_State *L, ngx_stream_lua_request_t *r)
|
||||
{
|
||||
/* set nginx request pointer to current lua thread's globals table */
|
||||
ngx_stream_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_stream_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_stream_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_stream_lua_log_handler(ngx_stream_session_t *r)
|
||||
{
|
||||
#if (NGX_STREAM_LUA_HAVE_MALLOC_TRIM)
|
||||
ngx_uint_t trim_cycle, trim_nreq;
|
||||
ngx_stream_lua_main_conf_t *lmcf;
|
||||
#if (NGX_DEBUG)
|
||||
ngx_int_t trim_ret;
|
||||
#endif
|
||||
#endif
|
||||
ngx_stream_lua_loc_conf_t *llcf;
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
|
||||
#if (NGX_STREAM_LUA_HAVE_MALLOC_TRIM)
|
||||
lmcf = ngx_stream_lua_get_module_main_conf(r, ngx_stream_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_STREAM, 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_STREAM, r->connection->log, 0,
|
||||
"malloc_trim() disabled");
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, r->connection->log, 0,
|
||||
"lua log handler");
|
||||
|
||||
llcf = ngx_stream_get_module_srv_conf(r, ngx_stream_lua_module);
|
||||
|
||||
if (llcf->log_handler == NULL) {
|
||||
dd("no log handler found");
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
ctx = ngx_stream_get_module_ctx(r, ngx_stream_lua_module);
|
||||
|
||||
dd("ctx = %p", ctx);
|
||||
|
||||
if (ctx == NULL) {
|
||||
ctx = ngx_stream_lua_create_ctx(r);
|
||||
if (ctx == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->context = NGX_STREAM_LUA_CONTEXT_LOG;
|
||||
|
||||
dd("calling log handler");
|
||||
return llcf->log_handler(ctx->request);
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_lua_log_handler_inline(ngx_stream_lua_request_t *r)
|
||||
{
|
||||
lua_State *L;
|
||||
ngx_int_t rc;
|
||||
ngx_stream_lua_loc_conf_t *llcf;
|
||||
|
||||
dd("log by lua inline");
|
||||
|
||||
llcf = ngx_stream_lua_get_module_loc_conf(r, ngx_stream_lua_module);
|
||||
|
||||
L = ngx_stream_lua_get_lua_vm(r, NULL);
|
||||
|
||||
/* load Lua inline script (w/ cache) sp = 1 */
|
||||
rc = ngx_stream_lua_cache_loadbuffer(r->connection->log, L,
|
||||
llcf->log_src.value.data,
|
||||
llcf->log_src.value.len,
|
||||
llcf->log_src_key,
|
||||
(const char *) llcf->log_chunkname);
|
||||
if (rc != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return ngx_stream_lua_log_by_chunk(L, r);
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_lua_log_handler_file(ngx_stream_lua_request_t *r)
|
||||
{
|
||||
lua_State *L;
|
||||
ngx_int_t rc;
|
||||
u_char *script_path;
|
||||
ngx_stream_lua_loc_conf_t *llcf;
|
||||
ngx_str_t eval_src;
|
||||
|
||||
llcf = ngx_stream_lua_get_module_loc_conf(r, ngx_stream_lua_module);
|
||||
|
||||
if (ngx_stream_complex_value(r->session, &llcf->log_src, &eval_src)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
script_path = ngx_stream_lua_rebase_path(r->pool, eval_src.data,
|
||||
eval_src.len);
|
||||
|
||||
if (script_path == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
L = ngx_stream_lua_get_lua_vm(r, NULL);
|
||||
|
||||
/* load Lua script file (w/ cache) sp = 1 */
|
||||
rc = ngx_stream_lua_cache_loadfile(r->connection->log, L, script_path,
|
||||
llcf->log_src_key);
|
||||
if (rc != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return ngx_stream_lua_log_by_chunk(L, r);
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_lua_log_by_chunk(lua_State *L, ngx_stream_lua_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_stream_lua_atpanic);
|
||||
|
||||
NGX_LUA_EXCEPTION_TRY {
|
||||
|
||||
/* initialize nginx context in Lua VM, code chunk at stack top sp = 1 */
|
||||
ngx_stream_lua_log_by_lua_env(L, r);
|
||||
|
||||
#if (NGX_PCRE)
|
||||
/* XXX: work-around to nginx regex subsystem */
|
||||
old_pool = ngx_stream_lua_pcre_malloc_init(r->pool);
|
||||
#endif
|
||||
|
||||
lua_pushcfunction(L, ngx_stream_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_stream_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,30 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_logby.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_LOGBY_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_LOGBY_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
ngx_int_t ngx_stream_lua_log_handler(ngx_stream_session_t *r);
|
||||
|
||||
ngx_int_t ngx_stream_lua_log_handler_inline(ngx_stream_lua_request_t *r);
|
||||
ngx_int_t ngx_stream_lua_log_handler_file(ngx_stream_lua_request_t *r);
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_LOGBY_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,65 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_misc.c.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_stream_lua_misc.h"
|
||||
#include "ngx_stream_lua_util.h"
|
||||
|
||||
|
||||
|
||||
|
||||
int
|
||||
ngx_stream_lua_ffi_get_resp_status(ngx_stream_lua_request_t *r)
|
||||
{
|
||||
return r->session->status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int
|
||||
ngx_stream_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,27 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_misc.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_MISC_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_MISC_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_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,739 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_output.c.tt2
|
||||
*/
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_stream_lua_output.h"
|
||||
#include "ngx_stream_lua_util.h"
|
||||
#include "ngx_stream_lua_contentby.h"
|
||||
#include <math.h>
|
||||
|
||||
|
||||
static int ngx_stream_lua_ngx_say(lua_State *L);
|
||||
static int ngx_stream_lua_ngx_print(lua_State *L);
|
||||
static int ngx_stream_lua_ngx_flush(lua_State *L);
|
||||
static int ngx_stream_lua_ngx_eof(lua_State *L);
|
||||
|
||||
|
||||
static int ngx_stream_lua_ngx_echo(lua_State *L, unsigned newline);
|
||||
static void ngx_stream_lua_flush_cleanup(void *data);
|
||||
|
||||
|
||||
static int
|
||||
ngx_stream_lua_ngx_print(lua_State *L)
|
||||
{
|
||||
dd("calling lua print");
|
||||
return ngx_stream_lua_ngx_echo(L, 0);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_stream_lua_ngx_say(lua_State *L)
|
||||
{
|
||||
dd("calling");
|
||||
return ngx_stream_lua_ngx_echo(L, 1);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_stream_lua_ngx_echo(lua_State *L, unsigned newline)
|
||||
{
|
||||
ngx_stream_lua_request_t *r;
|
||||
ngx_stream_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_stream_lua_get_req(L);
|
||||
if (r == NULL) {
|
||||
return luaL_error(L, "no request object found");
|
||||
}
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
|
||||
if (ctx == NULL) {
|
||||
return luaL_error(L, "no request ctx found");
|
||||
}
|
||||
|
||||
if (r->connection->type == SOCK_DGRAM) {
|
||||
return luaL_error(L, "API disabled in the current context");
|
||||
}
|
||||
|
||||
ngx_stream_lua_check_context(L, ctx, NGX_STREAM_LUA_CONTEXT_CONTENT
|
||||
| NGX_STREAM_LUA_CONTEXT_PREREAD);
|
||||
|
||||
|
||||
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:
|
||||
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_stream_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) {
|
||||
|
||||
lua_pushinteger(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ctx->seen_body_data = 1;
|
||||
|
||||
cl = ngx_stream_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:
|
||||
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_stream_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_STREAM, r->connection->log, 0,
|
||||
newline ? "lua say response" : "lua print response");
|
||||
|
||||
rc = ngx_stream_lua_send_chain_link(r, ctx, cl);
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "nginx output filter error");
|
||||
return 2;
|
||||
}
|
||||
|
||||
dd("downstream write: %d, buf len: %d", (int) rc,
|
||||
(int) (b->last - b->pos));
|
||||
|
||||
lua_pushinteger(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
ngx_stream_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:
|
||||
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_stream_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_stream_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:
|
||||
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_stream_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_stream_lua_ngx_flush(lua_State *L)
|
||||
{
|
||||
ngx_stream_lua_request_t *r;
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
ngx_chain_t *cl;
|
||||
ngx_int_t rc;
|
||||
int n;
|
||||
unsigned wait = 0;
|
||||
ngx_event_t *wev;
|
||||
|
||||
ngx_stream_lua_srv_conf_t *cllscf;
|
||||
|
||||
ngx_stream_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_stream_lua_get_req(L);
|
||||
|
||||
if (n == 1) {
|
||||
luaL_checktype(L, 1, LUA_TBOOLEAN);
|
||||
wait = lua_toboolean(L, 1);
|
||||
}
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return luaL_error(L, "no request ctx found");
|
||||
}
|
||||
|
||||
if (r->connection->type == SOCK_DGRAM) {
|
||||
return luaL_error(L, "API disabled in the current context");
|
||||
}
|
||||
|
||||
ngx_stream_lua_check_context(L, ctx, NGX_STREAM_LUA_CONTEXT_CONTENT
|
||||
| NGX_STREAM_LUA_CONTEXT_PREREAD);
|
||||
|
||||
|
||||
coctx = ctx->cur_co_ctx;
|
||||
if (coctx == NULL) {
|
||||
return luaL_error(L, "no co ctx found");
|
||||
}
|
||||
|
||||
|
||||
if (ctx->eof) {
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "seen eof");
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
cl = ngx_stream_lua_get_flush_chain(r, ctx);
|
||||
if (cl == NULL) {
|
||||
return luaL_error(L, "no memory");
|
||||
}
|
||||
|
||||
rc = ngx_stream_lua_send_chain_link(r, ctx, cl);
|
||||
|
||||
dd("send chain: %d", (int) rc);
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
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 || wev->delayed))
|
||||
{
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_STREAM, 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_stream_lua_content_wev_handler;
|
||||
|
||||
} else {
|
||||
r->write_event_handler = ngx_stream_lua_core_run_phases;
|
||||
}
|
||||
|
||||
cllscf = ngx_stream_lua_get_module_srv_conf(r, ngx_stream_lua_module);
|
||||
|
||||
if (!wev->delayed) {
|
||||
ngx_add_timer(wev, cllscf->send_timeout);
|
||||
}
|
||||
|
||||
|
||||
if (ngx_handle_write_event(wev, cllscf->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_stream_lua_cleanup_pending_operation(ctx->cur_co_ctx);
|
||||
coctx->cleanup = ngx_stream_lua_flush_cleanup;
|
||||
coctx->data = r;
|
||||
|
||||
return lua_yield(L, 0);
|
||||
}
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, r->connection->log, 0,
|
||||
"lua flush asynchronously");
|
||||
|
||||
lua_pushinteger(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send last_buf, terminate output stream
|
||||
* */
|
||||
static int
|
||||
ngx_stream_lua_ngx_eof(lua_State *L)
|
||||
{
|
||||
ngx_stream_lua_request_t *r;
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
ngx_int_t rc;
|
||||
|
||||
r = ngx_stream_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_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return luaL_error(L, "no ctx found");
|
||||
}
|
||||
|
||||
|
||||
if (ctx->eof) {
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "seen eof");
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (r->connection->type == SOCK_DGRAM) {
|
||||
return luaL_error(L, "API disabled in the current context");
|
||||
}
|
||||
|
||||
ngx_stream_lua_check_context(L, ctx, NGX_STREAM_LUA_CONTEXT_CONTENT
|
||||
| NGX_STREAM_LUA_CONTEXT_PREREAD);
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, r->connection->log, 0,
|
||||
"lua send eof");
|
||||
|
||||
rc = ngx_stream_lua_send_chain_link(r, ctx, NULL /* indicate last_buf */);
|
||||
|
||||
dd("send chain: %d", (int) rc);
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "nginx output filter error");
|
||||
return 2;
|
||||
}
|
||||
|
||||
lua_pushinteger(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_inject_output_api(lua_State *L)
|
||||
{
|
||||
|
||||
lua_pushcfunction(L, ngx_stream_lua_ngx_print);
|
||||
lua_setfield(L, -2, "print");
|
||||
|
||||
lua_pushcfunction(L, ngx_stream_lua_ngx_say);
|
||||
lua_setfield(L, -2, "say");
|
||||
|
||||
lua_pushcfunction(L, ngx_stream_lua_ngx_flush);
|
||||
lua_setfield(L, -2, "flush");
|
||||
|
||||
lua_pushcfunction(L, ngx_stream_lua_ngx_eof);
|
||||
lua_setfield(L, -2, "eof");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_lua_flush_resume_helper(ngx_stream_lua_request_t *r,
|
||||
ngx_stream_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_stream_lua_get_lua_vm(r, ctx);
|
||||
nreqs = c->requests;
|
||||
|
||||
rc = ngx_stream_lua_run_thread(vm, r, ctx, n);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, r->connection->log, 0,
|
||||
"lua run thread returned %d", rc);
|
||||
|
||||
if (rc == NGX_AGAIN) {
|
||||
return ngx_stream_lua_run_posted_threads(c, vm, r, ctx, nreqs);
|
||||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
ngx_stream_lua_finalize_request(r, NGX_DONE);
|
||||
return ngx_stream_lua_run_posted_threads(c, vm, r, ctx, nreqs);
|
||||
}
|
||||
|
||||
/* rc == NGX_ERROR || rc >= NGX_OK */
|
||||
|
||||
if (ctx->entered_content_phase) {
|
||||
ngx_stream_lua_finalize_request(r, rc);
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_stream_lua_flush_cleanup(void *data)
|
||||
{
|
||||
ngx_stream_lua_request_t *r;
|
||||
ngx_event_t *wev;
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
ngx_stream_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_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx->flushing_coros--;
|
||||
}
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,36 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_output.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_OUTPUT_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_OUTPUT_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
void ngx_stream_lua_inject_output_api(lua_State *L);
|
||||
|
||||
size_t ngx_stream_lua_calc_strlen_in_table(lua_State *L, int index, int arg_i,
|
||||
unsigned strict);
|
||||
|
||||
u_char *ngx_stream_lua_copy_str_in_table(lua_State *L, int index, u_char *dst);
|
||||
|
||||
ngx_int_t ngx_stream_lua_flush_resume_helper(ngx_stream_lua_request_t *r,
|
||||
ngx_stream_lua_ctx_t *ctx);
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_OUTPUT_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,114 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_pcrefix.c.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_stream_lua_pcrefix.h"
|
||||
#include "stdio.h"
|
||||
|
||||
#if (NGX_PCRE)
|
||||
|
||||
static ngx_pool_t *ngx_stream_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_stream_lua_pcre_malloc(size_t size)
|
||||
{
|
||||
dd("lua pcre pool is %p", ngx_stream_lua_pcre_pool);
|
||||
|
||||
if (ngx_stream_lua_pcre_pool) {
|
||||
return ngx_palloc(ngx_stream_lua_pcre_pool, size);
|
||||
}
|
||||
|
||||
fprintf(stderr, "error: lua pcre malloc failed due to empty pcre pool");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_stream_lua_pcre_free(void *ptr)
|
||||
{
|
||||
dd("lua pcre pool is %p", ngx_stream_lua_pcre_pool);
|
||||
|
||||
if (ngx_stream_lua_pcre_pool) {
|
||||
ngx_pfree(ngx_stream_lua_pcre_pool, ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
fprintf(stderr, "error: lua pcre free failed due to empty pcre pool");
|
||||
}
|
||||
|
||||
|
||||
ngx_pool_t *
|
||||
ngx_stream_lua_pcre_malloc_init(ngx_pool_t *pool)
|
||||
{
|
||||
ngx_pool_t *old_pool;
|
||||
|
||||
if (pcre_malloc != ngx_stream_lua_pcre_malloc) {
|
||||
|
||||
dd("overriding nginx pcre malloc and free");
|
||||
|
||||
ngx_stream_lua_pcre_pool = pool;
|
||||
|
||||
old_pcre_malloc = pcre_malloc;
|
||||
old_pcre_free = pcre_free;
|
||||
|
||||
pcre_malloc = ngx_stream_lua_pcre_malloc;
|
||||
pcre_free = ngx_stream_lua_pcre_free;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dd("lua pcre pool was %p", ngx_stream_lua_pcre_pool);
|
||||
|
||||
old_pool = ngx_stream_lua_pcre_pool;
|
||||
ngx_stream_lua_pcre_pool = pool;
|
||||
|
||||
dd("lua pcre pool is %p", ngx_stream_lua_pcre_pool);
|
||||
|
||||
return old_pool;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_pcre_malloc_done(ngx_pool_t *old_pool)
|
||||
{
|
||||
dd("lua pcre pool was %p", ngx_stream_lua_pcre_pool);
|
||||
|
||||
ngx_stream_lua_pcre_pool = old_pool;
|
||||
|
||||
dd("lua pcre pool is %p", ngx_stream_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,31 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_pcrefix.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_PCREFIX_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_PCREFIX_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
#if (NGX_PCRE)
|
||||
ngx_pool_t *ngx_stream_lua_pcre_malloc_init(ngx_pool_t *pool);
|
||||
void ngx_stream_lua_pcre_malloc_done(ngx_pool_t *old_pool);
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_PCREFIX_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,99 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_phase.c.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_stream_lua_phase.h"
|
||||
#include "ngx_stream_lua_util.h"
|
||||
#include "ngx_stream_lua_ctx.h"
|
||||
|
||||
|
||||
|
||||
static int
|
||||
ngx_stream_lua_ngx_get_phase(lua_State *L)
|
||||
{
|
||||
ngx_stream_lua_request_t *r;
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
|
||||
r = ngx_stream_lua_get_req(L);
|
||||
|
||||
/* If we have no request object, assume we are called from the "init"
|
||||
* phase. */
|
||||
|
||||
if (r == NULL) {
|
||||
lua_pushliteral(L, "init");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return luaL_error(L, "no request ctx found");
|
||||
}
|
||||
|
||||
switch (ctx->context) {
|
||||
case NGX_STREAM_LUA_CONTEXT_INIT_WORKER:
|
||||
lua_pushliteral(L, "init_worker");
|
||||
break;
|
||||
|
||||
case NGX_STREAM_LUA_CONTEXT_SSL_CLIENT_HELLO:
|
||||
lua_pushliteral(L, "ssl_client_hello");
|
||||
break;
|
||||
|
||||
case NGX_STREAM_LUA_CONTEXT_SSL_CERT:
|
||||
lua_pushliteral(L, "ssl_cert");
|
||||
break;
|
||||
|
||||
case NGX_STREAM_LUA_CONTEXT_PREREAD:
|
||||
lua_pushliteral(L, "preread");
|
||||
break;
|
||||
|
||||
case NGX_STREAM_LUA_CONTEXT_CONTENT:
|
||||
lua_pushliteral(L, "content");
|
||||
break;
|
||||
|
||||
case NGX_STREAM_LUA_CONTEXT_LOG:
|
||||
lua_pushliteral(L, "log");
|
||||
break;
|
||||
|
||||
case NGX_STREAM_LUA_CONTEXT_TIMER:
|
||||
lua_pushliteral(L, "timer");
|
||||
break;
|
||||
|
||||
case NGX_STREAM_LUA_CONTEXT_BALANCER:
|
||||
lua_pushliteral(L, "balancer");
|
||||
break;
|
||||
|
||||
default:
|
||||
return luaL_error(L, "unknown phase: %#x", (int) ctx->context);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_inject_phase_api(lua_State *L)
|
||||
{
|
||||
lua_pushcfunction(L, ngx_stream_lua_ngx_get_phase);
|
||||
lua_setfield(L, -2, "get_phase");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_phase.h.tt2
|
||||
*/
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_PHASE_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_PHASE_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
void ngx_stream_lua_inject_phase_api(lua_State *L);
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_PHASE_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,333 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) OpenResty Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include <nginx.h>
|
||||
#include "ngx_stream_lua_prereadby.h"
|
||||
#include "ngx_stream_lua_util.h"
|
||||
#include "ngx_stream_lua_exception.h"
|
||||
#include "ngx_stream_lua_cache.h"
|
||||
|
||||
|
||||
static ngx_int_t ngx_stream_lua_preread_by_chunk(lua_State *L,
|
||||
ngx_stream_lua_request_t *r);
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_lua_preread_handler(ngx_stream_session_t *s)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
ngx_stream_lua_srv_conf_t *lscf;
|
||||
ngx_stream_lua_main_conf_t *lmcf;
|
||||
ngx_stream_lua_request_t *r;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
|
||||
"lua preread handler");
|
||||
|
||||
lmcf = ngx_stream_get_module_main_conf(s, ngx_stream_lua_module);
|
||||
|
||||
if (!lmcf->postponed_to_preread_phase_end) {
|
||||
ngx_stream_core_main_conf_t *cmcf;
|
||||
ngx_stream_phase_handler_t tmp;
|
||||
ngx_stream_phase_handler_t *ph;
|
||||
ngx_stream_phase_handler_t *cur_ph;
|
||||
ngx_stream_phase_handler_t *last_ph;
|
||||
|
||||
lmcf->postponed_to_preread_phase_end = 1;
|
||||
|
||||
cmcf = ngx_stream_get_module_main_conf(s, ngx_stream_core_module);
|
||||
|
||||
ph = cmcf->phase_engine.handlers;
|
||||
cur_ph = &ph[s->phase_handler];
|
||||
last_ph = &ph[cur_ph->next - 1];
|
||||
|
||||
if (cur_ph < last_ph) {
|
||||
tmp = *cur_ph;
|
||||
|
||||
ngx_memmove(cur_ph, cur_ph + 1, (last_ph - cur_ph)
|
||||
* sizeof (ngx_stream_phase_handler_t));
|
||||
|
||||
*last_ph = tmp;
|
||||
|
||||
s->phase_handler--; /* redo the current ph */
|
||||
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
}
|
||||
|
||||
lscf = ngx_stream_get_module_srv_conf(s, ngx_stream_lua_module);
|
||||
|
||||
if (lscf->preread_handler == NULL) {
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, s->connection->log, 0,
|
||||
"no preread handler found");
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
ctx = ngx_stream_get_module_ctx(s, ngx_stream_lua_module);
|
||||
|
||||
dd("ctx = %p", ctx);
|
||||
|
||||
if (ctx == NULL) {
|
||||
ctx = ngx_stream_lua_create_ctx(s);
|
||||
if (ctx == NULL) {
|
||||
return NGX_STREAM_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
r = ctx->request;
|
||||
|
||||
dd("entered? %d", (int) ctx->entered_preread_phase);
|
||||
|
||||
if (ctx->entered_preread_phase) {
|
||||
dd("calling wev handler");
|
||||
rc = ctx->resume_handler(r);
|
||||
dd("wev handler returns %d", (int) rc);
|
||||
|
||||
if (rc == NGX_ERROR || rc > NGX_OK) {
|
||||
ngx_stream_lua_finalize_request(ctx->request, rc);
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
if (rc == NGX_DONE && ctx->peek_needs_more_data) {
|
||||
return NGX_AGAIN;
|
||||
}
|
||||
|
||||
if (rc == NGX_OK || rc == NGX_DONE) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
r->connection->read->handler = ngx_stream_lua_request_handler;
|
||||
r->connection->write->handler = ngx_stream_lua_request_handler;
|
||||
|
||||
dd("calling preread handler");
|
||||
rc = lscf->preread_handler(r);
|
||||
|
||||
if (rc == NGX_ERROR || rc > NGX_OK) {
|
||||
ngx_stream_lua_finalize_request(ctx->request, rc);
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_lua_preread_handler_inline(ngx_stream_lua_request_t *r)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
lua_State *L;
|
||||
ngx_stream_lua_srv_conf_t *lscf;
|
||||
|
||||
lscf = ngx_stream_lua_get_module_srv_conf(r, ngx_stream_lua_module);
|
||||
|
||||
L = ngx_stream_lua_get_lua_vm(r, NULL);
|
||||
|
||||
/* load Lua inline script (w/ cache) sp = 1 */
|
||||
rc = ngx_stream_lua_cache_loadbuffer(r->connection->log, L,
|
||||
lscf->preread_src.value.data,
|
||||
lscf->preread_src.value.len,
|
||||
lscf->preread_src_key,
|
||||
(const char *)
|
||||
lscf->preread_chunkname);
|
||||
|
||||
if (rc != NGX_OK) {
|
||||
return NGX_STREAM_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
return ngx_stream_lua_preread_by_chunk(L, r);
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_lua_preread_handler_file(ngx_stream_lua_request_t *r)
|
||||
{
|
||||
u_char *script_path;
|
||||
ngx_int_t rc;
|
||||
ngx_str_t eval_src;
|
||||
lua_State *L;
|
||||
ngx_stream_lua_srv_conf_t *lscf;
|
||||
|
||||
lscf = ngx_stream_lua_get_module_srv_conf(r, ngx_stream_lua_module);
|
||||
|
||||
/* Eval nginx variables in code path string first */
|
||||
if (ngx_stream_complex_value(r->session, &lscf->preread_src, &eval_src)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
script_path = ngx_stream_lua_rebase_path(r->pool, eval_src.data,
|
||||
eval_src.len);
|
||||
|
||||
if (script_path == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
L = ngx_stream_lua_get_lua_vm(r, NULL);
|
||||
|
||||
/* load Lua script file (w/ cache) sp = 1 */
|
||||
rc = ngx_stream_lua_cache_loadfile(r->connection->log, L, script_path,
|
||||
lscf->preread_src_key);
|
||||
if (rc != NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* make sure we have a valid code chunk */
|
||||
ngx_stream_lua_assert(lua_isfunction(L, -1));
|
||||
|
||||
return ngx_stream_lua_preread_by_chunk(L, r);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_stream_lua_preread_by_chunk(lua_State *L, ngx_stream_lua_request_t *r)
|
||||
{
|
||||
int co_ref;
|
||||
ngx_int_t rc;
|
||||
lua_State *co;
|
||||
ngx_event_t *rev;
|
||||
ngx_connection_t *c;
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
ngx_stream_lua_cleanup_t *cln;
|
||||
|
||||
ngx_stream_lua_srv_conf_t *lscf;
|
||||
|
||||
/* {{{ new coroutine to handle request */
|
||||
co = ngx_stream_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_STREAM_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_stream_lua_get_globals_table(co);
|
||||
lua_setfenv(co, -2);
|
||||
#endif
|
||||
|
||||
/* save nginx request in coroutine globals table */
|
||||
ngx_stream_lua_set_req(co, r);
|
||||
|
||||
/* {{{ initialize request context */
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
|
||||
dd("ctx = %p", ctx);
|
||||
|
||||
if (ctx == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ngx_stream_lua_reset_ctx(r, L, ctx);
|
||||
|
||||
ctx->entered_preread_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
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* {{{ register request cleanup hooks */
|
||||
if (ctx->cleanup == NULL) {
|
||||
cln = ngx_stream_lua_cleanup_add(r, 0);
|
||||
if (cln == NULL) {
|
||||
return NGX_STREAM_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
cln->handler = ngx_stream_lua_request_cleanup_handler;
|
||||
cln->data = ctx;
|
||||
ctx->cleanup = &cln->handler;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
ctx->context = NGX_STREAM_LUA_CONTEXT_PREREAD;
|
||||
|
||||
lscf = ngx_stream_lua_get_module_srv_conf(r, ngx_stream_lua_module);
|
||||
|
||||
if (lscf->check_client_abort) {
|
||||
r->read_event_handler = ngx_stream_lua_rd_check_broken_connection;
|
||||
|
||||
rev = r->connection->read;
|
||||
|
||||
if (!rev->active) {
|
||||
if (ngx_add_event(rev, NGX_READ_EVENT, 0) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
r->read_event_handler = ngx_stream_lua_block_reading;
|
||||
}
|
||||
|
||||
rc = ngx_stream_lua_run_thread(L, r, ctx, 0);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, r->connection->log, 0,
|
||||
"preread run thread returned %d", (int) rc);
|
||||
|
||||
if (rc == NGX_ERROR || rc > NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
c = r->connection;
|
||||
|
||||
if (rc == NGX_AGAIN) {
|
||||
rc = ngx_stream_lua_run_posted_threads(c, L, r, ctx, 0);
|
||||
|
||||
if (rc == NGX_DONE && ctx->peek_needs_more_data) {
|
||||
return NGX_AGAIN;
|
||||
}
|
||||
|
||||
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_stream_lua_finalize_request(r, NGX_DONE);
|
||||
|
||||
rc = ngx_stream_lua_run_posted_threads(c, L, r, ctx, 0);
|
||||
|
||||
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) {
|
||||
return NGX_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) OpenResty Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_PREREAD_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_PREREAD_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
ngx_int_t ngx_stream_lua_preread_handler(ngx_stream_session_t *s);
|
||||
ngx_int_t ngx_stream_lua_preread_handler_inline(ngx_stream_lua_request_t *r);
|
||||
ngx_int_t ngx_stream_lua_preread_handler_file(ngx_stream_lua_request_t *r);
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_PREREAD_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,96 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_probe.h.tt2
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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_STREAM_LUA_PROBE_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_PROBE_H_INCLUDED_
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
|
||||
|
||||
|
||||
|
||||
#if defined(NGX_DTRACE) && NGX_DTRACE
|
||||
|
||||
#include <ngx_dtrace_provider.h>
|
||||
|
||||
#define ngx_stream_lua_probe_info(s) \
|
||||
NGINX_LUA_HTTP_LUA_INFO(s)
|
||||
|
||||
#define ngx_stream_lua_probe_register_preload_package(L, pkg) \
|
||||
NGINX_LUA_HTTP_LUA_REGISTER_PRELOAD_PACKAGE(L, pkg)
|
||||
|
||||
#define ngx_stream_lua_probe_req_socket_consume_preread(r, data, len) \
|
||||
NGINX_LUA_HTTP_LUA_REQ_SOCKET_CONSUME_PREREAD(r, data, len)
|
||||
|
||||
#define ngx_stream_lua_probe_user_coroutine_create(r, parent, child) \
|
||||
NGINX_LUA_HTTP_LUA_USER_COROUTINE_CREATE(r, parent, child)
|
||||
|
||||
#define ngx_stream_lua_probe_user_coroutine_resume(r, parent, child) \
|
||||
NGINX_LUA_HTTP_LUA_USER_COROUTINE_RESUME(r, parent, child)
|
||||
|
||||
#define ngx_stream_lua_probe_user_coroutine_yield(r, parent, child) \
|
||||
NGINX_LUA_HTTP_LUA_USER_COROUTINE_YIELD(r, parent, child)
|
||||
|
||||
#define ngx_stream_lua_probe_thread_yield(r, L) \
|
||||
NGINX_LUA_HTTP_LUA_THREAD_YIELD(r, L)
|
||||
|
||||
#define ngx_stream_lua_probe_socket_tcp_send_start(r, u, data, len) \
|
||||
NGINX_LUA_HTTP_LUA_SOCKET_TCP_SEND_START(r, u, data, len)
|
||||
|
||||
#define ngx_stream_lua_probe_socket_tcp_receive_done(r, u, data, len) \
|
||||
NGINX_LUA_HTTP_LUA_SOCKET_TCP_RECEIVE_DONE(r, u, data, len)
|
||||
|
||||
#define ngx_stream_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_stream_lua_probe_user_thread_spawn(r, creator, newthread) \
|
||||
NGINX_LUA_HTTP_LUA_USER_THREAD_SPAWN(r, creator, newthread)
|
||||
|
||||
#define ngx_stream_lua_probe_thread_delete(r, thread, ctx) \
|
||||
NGINX_LUA_HTTP_LUA_THREAD_DELETE(r, thread, ctx)
|
||||
|
||||
#define ngx_stream_lua_probe_run_posted_thread(r, thread, status) \
|
||||
NGINX_LUA_HTTP_LUA_RUN_POSTED_THREAD(r, thread, status)
|
||||
|
||||
#define ngx_stream_lua_probe_coroutine_done(r, co, success) \
|
||||
NGINX_LUA_HTTP_LUA_COROUTINE_DONE(r, co, success)
|
||||
|
||||
#define ngx_stream_lua_probe_user_thread_wait(parent, child) \
|
||||
NGINX_LUA_HTTP_LUA_USER_THREAD_WAIT(parent, child)
|
||||
|
||||
#else /* !(NGX_DTRACE) */
|
||||
|
||||
#define ngx_stream_lua_probe_info(s)
|
||||
#define ngx_stream_lua_probe_register_preload_package(L, pkg)
|
||||
#define ngx_stream_lua_probe_req_socket_consume_preread(r, data, len)
|
||||
#define ngx_stream_lua_probe_user_coroutine_create(r, parent, child)
|
||||
#define ngx_stream_lua_probe_user_coroutine_resume(r, parent, child)
|
||||
#define ngx_stream_lua_probe_user_coroutine_yield(r, parent, child)
|
||||
#define ngx_stream_lua_probe_thread_yield(r, L)
|
||||
#define ngx_stream_lua_probe_socket_tcp_send_start(r, u, data, len)
|
||||
#define ngx_stream_lua_probe_socket_tcp_receive_done(r, u, data, len)
|
||||
#define ngx_stream_lua_probe_socket_tcp_setkeepalive_buf_unread(r, u, data, len)
|
||||
#define ngx_stream_lua_probe_user_thread_spawn(r, creator, newthread)
|
||||
#define ngx_stream_lua_probe_thread_delete(r, thread, ctx)
|
||||
#define ngx_stream_lua_probe_run_posted_thread(r, thread, status)
|
||||
#define ngx_stream_lua_probe_coroutine_done(r, co, success)
|
||||
#define ngx_stream_lua_probe_user_thread_wait(parent, child)
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_PROBE_H_INCLUDED_ */
|
|
@ -0,0 +1,608 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_regex.c.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#if (NGX_PCRE)
|
||||
|
||||
#include "ngx_stream_lua_pcrefix.h"
|
||||
#include "ngx_stream_lua_script.h"
|
||||
#include "ngx_stream_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_stream_lua_complex_value_t *replace;
|
||||
|
||||
/* only for (stap) debugging, and may be an invalid pointer */
|
||||
const u_char *pattern;
|
||||
} ngx_stream_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_stream_lua_regex_compile_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_stream_lua_request_t *request;
|
||||
|
||||
pcre *regex;
|
||||
pcre_extra *regex_sd;
|
||||
int ncaptures;
|
||||
int *captures;
|
||||
int captures_len;
|
||||
uint8_t flags;
|
||||
} ngx_stream_lua_regex_ctx_t;
|
||||
|
||||
|
||||
static void ngx_stream_lua_regex_free_study_data(ngx_pool_t *pool,
|
||||
pcre_extra *sd);
|
||||
static ngx_int_t ngx_stream_lua_regex_compile(
|
||||
ngx_stream_lua_regex_compile_t *rc);
|
||||
|
||||
|
||||
#define ngx_stream_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_stream_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_stream_lua_regex_free_study_data(ngx_pool_t *pool, pcre_extra *sd)
|
||||
{
|
||||
ngx_pool_t *old_pool;
|
||||
|
||||
old_pool = ngx_stream_lua_pcre_malloc_init(pool);
|
||||
|
||||
#if LUA_HAVE_PCRE_JIT
|
||||
pcre_free_study(sd);
|
||||
#else
|
||||
pcre_free(sd);
|
||||
#endif
|
||||
|
||||
ngx_stream_lua_pcre_malloc_done(old_pool);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_stream_lua_regex_compile(ngx_stream_lua_regex_compile_t *rc)
|
||||
{
|
||||
int n, erroff;
|
||||
char *p;
|
||||
const char *errstr;
|
||||
pcre *re;
|
||||
ngx_pool_t *old_pool;
|
||||
|
||||
old_pool = ngx_stream_lua_pcre_malloc_init(rc->pool);
|
||||
|
||||
re = pcre_compile((const char *) rc->pattern.data, (int) rc->options,
|
||||
&errstr, &erroff, NULL);
|
||||
|
||||
ngx_stream_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_stream_lua_ffi_set_jit_stack_size(int size, u_char *errstr,
|
||||
size_t *errstr_size)
|
||||
{
|
||||
#if LUA_HAVE_PCRE_JIT
|
||||
|
||||
ngx_stream_lua_main_conf_t *lmcf;
|
||||
ngx_pool_t *pool, *old_pool;
|
||||
|
||||
lmcf = ngx_stream_cycle_get_module_main_conf(ngx_cycle,
|
||||
ngx_stream_lua_module);
|
||||
|
||||
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_stream_lua_pcre_malloc_init(pool);
|
||||
|
||||
pcre_jit_stack_free(lmcf->jit_stack);
|
||||
|
||||
ngx_stream_lua_pcre_malloc_done(old_pool);
|
||||
}
|
||||
|
||||
old_pool = ngx_stream_lua_pcre_malloc_init(pool);
|
||||
|
||||
lmcf->jit_stack = pcre_jit_stack_alloc(NGX_LUA_RE_MIN_JIT_STACK_SIZE,
|
||||
size);
|
||||
|
||||
ngx_stream_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_stream_lua_regex_t *
|
||||
ngx_stream_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_stream_lua_regex_t *re;
|
||||
ngx_stream_lua_main_conf_t *lmcf;
|
||||
ngx_stream_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_stream_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_stream_lua_pcre_malloc_init(pool);
|
||||
rc = ngx_stream_lua_regex_compile(&re_comp);
|
||||
ngx_stream_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_stream_cycle_get_module_main_conf(ngx_cycle,
|
||||
ngx_stream_lua_module);
|
||||
|
||||
#if (LUA_HAVE_PCRE_JIT)
|
||||
|
||||
if (flags & NGX_LUA_RE_MODE_JIT) {
|
||||
|
||||
old_pool = ngx_stream_lua_pcre_malloc_init(pool);
|
||||
sd = pcre_study(re_comp.regex, PCRE_STUDY_JIT_COMPILE, &msg);
|
||||
ngx_stream_lua_pcre_malloc_done(old_pool);
|
||||
|
||||
# if (NGX_DEBUG)
|
||||
if (msg != NULL) {
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_STREAM, ngx_cycle->log, 0,
|
||||
"pcre study failed with PCRE_STUDY_JIT_COMPILE: "
|
||||
"%s (%p)", msg, sd);
|
||||
}
|
||||
|
||||
if (sd != NULL) {
|
||||
int jitted;
|
||||
|
||||
old_pool = ngx_stream_lua_pcre_malloc_init(pool);
|
||||
|
||||
pcre_fullinfo(re_comp.regex, sd, PCRE_INFO_JIT, &jitted);
|
||||
|
||||
ngx_stream_lua_pcre_malloc_done(old_pool);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, ngx_cycle->log, 0,
|
||||
"pcre JIT compiling result: %d", jitted);
|
||||
}
|
||||
# endif /* !(NGX_DEBUG) */
|
||||
|
||||
} else {
|
||||
old_pool = ngx_stream_lua_pcre_malloc_init(pool);
|
||||
sd = pcre_study(re_comp.regex, 0, &msg);
|
||||
ngx_stream_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_stream_lua_regex_free_study_data(pool, sd);
|
||||
}
|
||||
|
||||
if (pool) {
|
||||
ngx_destroy_pool(pool);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_stream_lua_ffi_exec_regex(ngx_stream_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_stream_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_stream_lua_regex_exec(re->regex, sd, &subj, (int) pos, cap,
|
||||
ovecsize, exec_opts);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_ffi_destroy_regex(ngx_stream_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_stream_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_stream_lua_pcre_malloc_done(old_pool);
|
||||
re->regex_sd = NULL;
|
||||
}
|
||||
|
||||
ngx_destroy_pool(re->pool);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_stream_lua_ffi_compile_replace_template(ngx_stream_lua_regex_t *re,
|
||||
const u_char *replace_data, size_t replace_len)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
ngx_str_t tpl;
|
||||
|
||||
ngx_stream_lua_complex_value_t *ctpl;
|
||||
ngx_stream_lua_compile_complex_value_t ccv;
|
||||
|
||||
ctpl = ngx_palloc(re->pool, sizeof(ngx_stream_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_stream_lua_compile_complex_value_t));
|
||||
ccv.pool = re->pool;
|
||||
ccv.log = ngx_cycle->log;
|
||||
ccv.value = &tpl;
|
||||
ccv.complex_value = ctpl;
|
||||
|
||||
rc = ngx_stream_lua_compile_complex_value(&ccv);
|
||||
|
||||
re->replace = ctpl;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
ngx_stream_lua_script_engine_t *
|
||||
ngx_stream_lua_ffi_create_script_engine(void)
|
||||
{
|
||||
return ngx_calloc(sizeof(ngx_stream_lua_script_engine_t), ngx_cycle->log);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_ffi_init_script_engine(ngx_stream_lua_script_engine_t *e,
|
||||
const unsigned char *subj, ngx_stream_lua_regex_t *compiled, int count)
|
||||
{
|
||||
e->log = ngx_cycle->log;
|
||||
e->ncaptures = count * 2;
|
||||
e->captures = compiled->captures;
|
||||
e->captures_data = (u_char *) subj;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_ffi_destroy_script_engine(ngx_stream_lua_script_engine_t *e)
|
||||
{
|
||||
ngx_free(e);
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
ngx_stream_lua_ffi_script_eval_len(ngx_stream_lua_script_engine_t *e,
|
||||
ngx_stream_lua_complex_value_t *val)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
ngx_stream_lua_script_len_code_pt lcode;
|
||||
|
||||
e->ip = val->lengths;
|
||||
len = 0;
|
||||
|
||||
while (*(uintptr_t *) e->ip) {
|
||||
lcode = *(ngx_stream_lua_script_len_code_pt *) e->ip;
|
||||
len += lcode(e);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_ffi_script_eval_data(ngx_stream_lua_script_engine_t *e,
|
||||
ngx_stream_lua_complex_value_t *val, u_char *dst)
|
||||
{
|
||||
ngx_stream_lua_script_code_pt code;
|
||||
|
||||
e->ip = val->values;
|
||||
e->pos = dst;
|
||||
|
||||
while (*(uintptr_t *) e->ip) {
|
||||
code = *(ngx_stream_lua_script_code_pt *) e->ip;
|
||||
code(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t
|
||||
ngx_stream_lua_ffi_max_regex_cache_size(void)
|
||||
{
|
||||
ngx_stream_lua_main_conf_t *lmcf;
|
||||
lmcf = ngx_stream_cycle_get_module_main_conf(ngx_cycle,
|
||||
ngx_stream_lua_module);
|
||||
if (lmcf == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return (uint32_t) lmcf->regex_cache_max_entries;
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
ngx_stream_lua_ffi_pcre_version(void)
|
||||
{
|
||||
return pcre_version();
|
||||
}
|
||||
|
||||
|
||||
#endif /* NGX_PCRE */
|
||||
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,350 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) OpenResty Inc.
|
||||
*/
|
||||
|
||||
|
||||
#include <ngx_config.h>
|
||||
#include <ngx_core.h>
|
||||
#include <ngx_stream.h>
|
||||
#include "ddebug.h"
|
||||
#include "ngx_stream_lua_common.h"
|
||||
#include "ngx_stream_lua_request.h"
|
||||
#include "ngx_stream_lua_contentby.h"
|
||||
|
||||
|
||||
static ngx_int_t ngx_stream_lua_set_write_handler(ngx_stream_lua_request_t *r);
|
||||
static void ngx_stream_lua_writer(ngx_stream_lua_request_t *r);
|
||||
static void ngx_stream_lua_request_cleanup(void *data);
|
||||
|
||||
|
||||
ngx_stream_lua_cleanup_t *
|
||||
ngx_stream_lua_cleanup_add(ngx_stream_lua_request_t *r, size_t size)
|
||||
{
|
||||
ngx_stream_lua_cleanup_t *cln;
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
|
||||
if (size == 0) {
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
|
||||
if (ctx != NULL && ctx->free_cleanup) {
|
||||
cln = ctx->free_cleanup;
|
||||
ctx->free_cleanup = cln->next;
|
||||
|
||||
dd("reuse cleanup: %p", cln);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, r->connection->log, 0,
|
||||
"lua stream cleanup reuse: %p", cln);
|
||||
|
||||
cln->handler = NULL;
|
||||
cln->next = r->cleanup;
|
||||
|
||||
r->cleanup = cln;
|
||||
|
||||
return cln;
|
||||
}
|
||||
}
|
||||
|
||||
cln = ngx_palloc(r->pool, sizeof(ngx_stream_lua_cleanup_t));
|
||||
if (cln == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size) {
|
||||
cln->data = ngx_palloc(r->pool, size);
|
||||
if (cln->data == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} else {
|
||||
cln->data = NULL;
|
||||
}
|
||||
|
||||
cln->handler = NULL;
|
||||
cln->next = r->cleanup;
|
||||
|
||||
r->cleanup = cln;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, r->connection->log, 0,
|
||||
"stream cleanup add: %p", cln);
|
||||
|
||||
return cln;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_stream_lua_request_cleanup(void *data)
|
||||
{
|
||||
ngx_stream_lua_request_t *r = data;
|
||||
ngx_stream_lua_cleanup_t *cln;
|
||||
|
||||
cln = r->cleanup;
|
||||
r->cleanup = NULL;
|
||||
|
||||
while (cln) {
|
||||
if (cln->handler) {
|
||||
cln->handler(cln->data);
|
||||
}
|
||||
|
||||
cln = cln->next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ngx_stream_lua_request_t *
|
||||
ngx_stream_lua_create_request(ngx_stream_session_t *s)
|
||||
{
|
||||
ngx_pool_t *pool;
|
||||
ngx_stream_lua_request_t *r;
|
||||
ngx_pool_cleanup_t *cln;
|
||||
|
||||
#if 0
|
||||
pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, s->connection->log);
|
||||
if (pool == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
pool = s->connection->pool;
|
||||
|
||||
r = ngx_pcalloc(pool, sizeof(ngx_stream_lua_request_t));
|
||||
if (r == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
r->connection = s->connection;
|
||||
r->session = s;
|
||||
r->pool = pool;
|
||||
|
||||
cln = ngx_pool_cleanup_add(pool, 0);
|
||||
if (cln == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cln->handler = ngx_stream_lua_request_cleanup;
|
||||
cln->data = r;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_request_handler(ngx_event_t *ev)
|
||||
{
|
||||
ngx_connection_t *c;
|
||||
ngx_stream_session_t *s;
|
||||
ngx_stream_lua_request_t *r;
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
|
||||
c = ev->data;
|
||||
s = c->data;
|
||||
|
||||
if (ev->delayed && ev->timedout) {
|
||||
ev->delayed = 0;
|
||||
ev->timedout = 0;
|
||||
}
|
||||
|
||||
ctx = ngx_stream_get_module_ctx(s, ngx_stream_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
r = ctx->request;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0,
|
||||
"session run request: \"%p\"", r);
|
||||
|
||||
if (ev->write) {
|
||||
r->write_event_handler(r);
|
||||
|
||||
} else {
|
||||
r->read_event_handler(r);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_empty_handler(ngx_event_t *wev)
|
||||
{
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, wev->log, 0,
|
||||
"stream lua empty handler");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_block_reading(ngx_stream_lua_request_t *r)
|
||||
{
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, r->connection->log, 0,
|
||||
"stream reading blocked");
|
||||
|
||||
/* aio does not call this handler */
|
||||
|
||||
if ((ngx_event_flags & NGX_USE_LEVEL_EVENT)
|
||||
&& r->connection->read->active)
|
||||
{
|
||||
if (ngx_del_event(r->connection->read, NGX_READ_EVENT, 0) != NGX_OK) {
|
||||
ngx_stream_lua_finalize_real_request(r,
|
||||
NGX_STREAM_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_finalize_real_request(ngx_stream_lua_request_t *r, ngx_int_t rc)
|
||||
{
|
||||
#if 0
|
||||
ngx_pool_t *pool;
|
||||
#endif
|
||||
ngx_stream_session_t *s;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, r->connection->log, 0,
|
||||
"finalize stream request: %i", rc);
|
||||
|
||||
s = r->session;
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
rc = NGX_STREAM_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
if (rc == NGX_DECLINED || rc == NGX_STREAM_INTERNAL_SERVER_ERROR) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (rc == NGX_OK) {
|
||||
rc = NGX_STREAM_OK;
|
||||
}
|
||||
|
||||
if (r->connection->buffered) {
|
||||
if (ngx_stream_lua_set_write_handler(r) != NGX_OK) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
#if 0
|
||||
pool = r->pool;
|
||||
r->pool = NULL;
|
||||
|
||||
ngx_destroy_pool(pool);
|
||||
#endif
|
||||
|
||||
ngx_stream_finalize_session(s, rc);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_request_empty_handler(ngx_stream_lua_request_t *r)
|
||||
{
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, r->connection->log, 0,
|
||||
"stream request empty handler");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_stream_lua_writer(ngx_stream_lua_request_t *r)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
ngx_event_t *wev;
|
||||
ngx_connection_t *c;
|
||||
ngx_stream_lua_srv_conf_t *lscf;
|
||||
|
||||
c = r->connection;
|
||||
wev = c->write;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, wev->log, 0,
|
||||
"stream writer handler");
|
||||
|
||||
lscf = ngx_stream_lua_get_module_srv_conf(r, ngx_stream_lua_module);
|
||||
|
||||
if (wev->timedout) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT,
|
||||
"client timed out");
|
||||
c->timedout = 1;
|
||||
|
||||
ngx_stream_lua_finalize_real_request(r, NGX_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
rc = ngx_stream_top_filter(r->session, NULL, 1);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0,
|
||||
"stream writer output filter: %i", rc);
|
||||
|
||||
if (rc == NGX_ERROR) {
|
||||
ngx_stream_lua_finalize_real_request(r, rc);
|
||||
return;
|
||||
}
|
||||
|
||||
if (c->buffered) {
|
||||
if (!wev->delayed) {
|
||||
ngx_add_timer(wev, lscf->send_timeout);
|
||||
}
|
||||
|
||||
if (ngx_handle_write_event(wev, lscf->send_lowat) != NGX_OK) {
|
||||
ngx_stream_lua_finalize_real_request(r, NGX_ERROR);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, wev->log, 0,
|
||||
"stream writer done");
|
||||
|
||||
r->write_event_handler = ngx_stream_lua_request_empty_handler;
|
||||
|
||||
ngx_stream_lua_finalize_real_request(r, rc);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_stream_lua_set_write_handler(ngx_stream_lua_request_t *r)
|
||||
{
|
||||
ngx_event_t *wev;
|
||||
ngx_stream_lua_srv_conf_t *lscf;
|
||||
|
||||
r->read_event_handler = ngx_stream_lua_request_empty_handler;
|
||||
r->write_event_handler = ngx_stream_lua_writer;
|
||||
|
||||
wev = r->connection->write;
|
||||
|
||||
if (wev->ready && wev->delayed) {
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
lscf = ngx_stream_lua_get_module_srv_conf(r, ngx_stream_lua_module);
|
||||
if (!wev->delayed) {
|
||||
ngx_add_timer(wev, lscf->send_timeout);
|
||||
}
|
||||
|
||||
if (ngx_handle_write_event(wev, lscf->send_lowat) != NGX_OK) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_core_run_phases(ngx_stream_lua_request_t *r)
|
||||
{
|
||||
ngx_stream_session_t *s;
|
||||
|
||||
s = r->session;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, r->connection->log, 0,
|
||||
"lua session run phases: \"%p\"", r);
|
||||
|
||||
ngx_stream_core_run_phases(s);
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
|
||||
/*
|
||||
* Copyright (C) OpenResty Inc.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_REQUEST_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_REQUEST_H_INCLUDED_
|
||||
|
||||
|
||||
typedef void (*ngx_stream_lua_cleanup_pt)(void *data);
|
||||
|
||||
typedef struct ngx_stream_lua_cleanup_s ngx_stream_lua_cleanup_t;
|
||||
|
||||
struct ngx_stream_lua_cleanup_s {
|
||||
ngx_stream_lua_cleanup_pt handler;
|
||||
void *data;
|
||||
ngx_stream_lua_cleanup_t *next;
|
||||
};
|
||||
|
||||
|
||||
typedef struct ngx_stream_lua_request_s ngx_stream_lua_request_t;
|
||||
|
||||
typedef void (*ngx_stream_lua_event_handler_pt)(ngx_stream_lua_request_t *r);
|
||||
|
||||
|
||||
struct ngx_stream_lua_request_s {
|
||||
ngx_connection_t *connection;
|
||||
ngx_stream_session_t *session;
|
||||
ngx_pool_t *pool;
|
||||
ngx_stream_lua_cleanup_t *cleanup;
|
||||
|
||||
ngx_stream_lua_event_handler_pt read_event_handler;
|
||||
ngx_stream_lua_event_handler_pt write_event_handler;
|
||||
};
|
||||
|
||||
|
||||
void ngx_stream_lua_empty_handler(ngx_event_t *wev);
|
||||
void ngx_stream_lua_request_handler(ngx_event_t *ev);
|
||||
void ngx_stream_lua_block_reading(ngx_stream_lua_request_t *r);
|
||||
|
||||
ngx_stream_lua_cleanup_t *
|
||||
ngx_stream_lua_cleanup_add(ngx_stream_lua_request_t *r, size_t size);
|
||||
|
||||
ngx_stream_lua_request_t *
|
||||
ngx_stream_lua_create_request(ngx_stream_session_t *s);
|
||||
void ngx_stream_lua_finalize_real_request(ngx_stream_lua_request_t *r,
|
||||
ngx_int_t rc);
|
||||
void ngx_stream_lua_core_run_phases(ngx_stream_lua_request_t *r);
|
||||
|
||||
|
||||
typedef ngx_int_t (*ngx_stream_lua_handler_pt)(ngx_stream_lua_request_t *r);
|
||||
|
||||
|
||||
#define ngx_stream_lua_get_module_ctx(r, module) \
|
||||
ngx_stream_get_module_ctx((r)->session, module)
|
||||
#define ngx_stream_lua_set_ctx(r, c, module) \
|
||||
ngx_stream_set_ctx((r)->session, c, module)
|
||||
#define ngx_stream_lua_get_module_main_conf(r, module) \
|
||||
ngx_stream_get_module_main_conf((r)->session, module)
|
||||
#define ngx_stream_lua_get_module_srv_conf(r, module) \
|
||||
ngx_stream_get_module_srv_conf((r)->session, module)
|
||||
#define ngx_stream_lua_get_module_loc_conf \
|
||||
ngx_stream_lua_get_module_srv_conf
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_REQUEST_H_INCLUDED_ */
|
|
@ -0,0 +1,555 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_script.c.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_stream_lua_script.h"
|
||||
|
||||
|
||||
static void *ngx_stream_lua_script_add_code(ngx_array_t *codes, size_t size);
|
||||
static size_t ngx_stream_lua_script_copy_len_code(
|
||||
ngx_stream_lua_script_engine_t *e);
|
||||
static void ngx_stream_lua_script_copy_code(ngx_stream_lua_script_engine_t *e);
|
||||
static ngx_int_t ngx_stream_lua_script_add_copy_code(
|
||||
ngx_stream_lua_script_compile_t *sc, ngx_str_t *value, ngx_uint_t last);
|
||||
static ngx_int_t ngx_stream_lua_script_compile(
|
||||
ngx_stream_lua_script_compile_t *sc);
|
||||
static ngx_int_t ngx_stream_lua_script_add_capture_code(
|
||||
ngx_stream_lua_script_compile_t *sc, ngx_uint_t n);
|
||||
static size_t ngx_stream_lua_script_copy_capture_len_code(
|
||||
ngx_stream_lua_script_engine_t *e);
|
||||
static void ngx_stream_lua_script_copy_capture_code(
|
||||
ngx_stream_lua_script_engine_t *e);
|
||||
static ngx_int_t ngx_stream_lua_script_done(
|
||||
ngx_stream_lua_script_compile_t *sc);
|
||||
static ngx_int_t ngx_stream_lua_script_init_arrays(
|
||||
ngx_stream_lua_script_compile_t *sc);
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_lua_compile_complex_value(
|
||||
ngx_stream_lua_compile_complex_value_t *ccv)
|
||||
{
|
||||
ngx_str_t *v;
|
||||
ngx_uint_t i, n, nv;
|
||||
ngx_array_t lengths, values, *pl, *pv;
|
||||
|
||||
ngx_stream_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_stream_lua_script_copy_code_t)
|
||||
+ sizeof(ngx_stream_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_stream_lua_script_copy_code_t)
|
||||
+ sizeof(ngx_stream_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_stream_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_stream_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_stream_lua_complex_value(ngx_stream_lua_request_t *r, ngx_str_t *subj,
|
||||
size_t offset, ngx_int_t count, int *cap,
|
||||
ngx_stream_lua_complex_value_t *val, luaL_Buffer *luabuf)
|
||||
{
|
||||
size_t len;
|
||||
u_char *p;
|
||||
|
||||
ngx_stream_lua_script_code_pt code;
|
||||
ngx_stream_lua_script_len_code_pt lcode;
|
||||
ngx_stream_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_stream_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_stream_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_stream_lua_script_code_pt *) e.ip;
|
||||
code((ngx_stream_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_stream_lua_script_compile(ngx_stream_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_stream_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_stream_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_stream_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_stream_lua_script_add_copy_code(sc, &name,
|
||||
i == sc->source->len)
|
||||
!= NGX_OK)
|
||||
{
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return ngx_stream_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_stream_lua_script_add_copy_code(ngx_stream_lua_script_compile_t *sc,
|
||||
ngx_str_t *value, ngx_uint_t last)
|
||||
{
|
||||
size_t size, len;
|
||||
|
||||
ngx_stream_lua_script_copy_code_t *code;
|
||||
|
||||
len = value->len;
|
||||
|
||||
code = ngx_stream_lua_script_add_code(*sc->lengths,
|
||||
sizeof(ngx_stream_lua_script_copy_code_t));
|
||||
if (code == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
code->code = (ngx_stream_lua_script_code_pt) (void *)
|
||||
ngx_stream_lua_script_copy_len_code;
|
||||
code->len = len;
|
||||
|
||||
size = (sizeof(ngx_stream_lua_script_copy_code_t) + len +
|
||||
sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1);
|
||||
|
||||
code = ngx_stream_lua_script_add_code(*sc->values, size);
|
||||
if (code == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
code->code = ngx_stream_lua_script_copy_code;
|
||||
code->len = len;
|
||||
|
||||
ngx_memcpy((u_char *) code + sizeof(ngx_stream_lua_script_copy_code_t),
|
||||
value->data, value->len);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
ngx_stream_lua_script_copy_len_code(ngx_stream_lua_script_engine_t *e)
|
||||
{
|
||||
ngx_stream_lua_script_copy_code_t *code;
|
||||
|
||||
code = (ngx_stream_lua_script_copy_code_t *) e->ip;
|
||||
|
||||
e->ip += sizeof(ngx_stream_lua_script_copy_code_t);
|
||||
|
||||
return code->len;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_stream_lua_script_copy_code(ngx_stream_lua_script_engine_t *e)
|
||||
{
|
||||
u_char *p;
|
||||
|
||||
ngx_stream_lua_script_copy_code_t *code;
|
||||
|
||||
code = (ngx_stream_lua_script_copy_code_t *) e->ip;
|
||||
|
||||
p = e->pos;
|
||||
|
||||
if (!e->skip) {
|
||||
e->pos = ngx_copy(p, e->ip + sizeof(ngx_stream_lua_script_copy_code_t),
|
||||
code->len);
|
||||
}
|
||||
|
||||
e->ip += sizeof(ngx_stream_lua_script_copy_code_t)
|
||||
+ ((code->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1));
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_STREAM, e->log, 0,
|
||||
"lua script copy: \"%*s\"", e->pos - p, p);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_stream_lua_script_add_capture_code(ngx_stream_lua_script_compile_t *sc,
|
||||
ngx_uint_t n)
|
||||
{
|
||||
ngx_stream_lua_script_capture_code_t *code;
|
||||
|
||||
code = ngx_stream_lua_script_add_code(*sc->lengths,
|
||||
sizeof(ngx_stream_lua_script_capture_code_t));
|
||||
if (code == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
code->code = (ngx_stream_lua_script_code_pt) (void *)
|
||||
ngx_stream_lua_script_copy_capture_len_code;
|
||||
code->n = 2 * n;
|
||||
|
||||
code = ngx_stream_lua_script_add_code(*sc->values,
|
||||
sizeof(ngx_stream_lua_script_capture_code_t));
|
||||
if (code == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
code->code = ngx_stream_lua_script_copy_capture_code;
|
||||
code->n = 2 * n;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static size_t
|
||||
ngx_stream_lua_script_copy_capture_len_code(ngx_stream_lua_script_engine_t *e)
|
||||
{
|
||||
int *cap;
|
||||
ngx_uint_t n;
|
||||
|
||||
ngx_stream_lua_script_capture_code_t *code;
|
||||
|
||||
code = (ngx_stream_lua_script_capture_code_t *) e->ip;
|
||||
|
||||
e->ip += sizeof(ngx_stream_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_stream_lua_script_copy_capture_code(ngx_stream_lua_script_engine_t *e)
|
||||
{
|
||||
int *cap;
|
||||
u_char *p, *pos;
|
||||
ngx_uint_t n;
|
||||
|
||||
ngx_stream_lua_script_capture_code_t *code;
|
||||
|
||||
code = (ngx_stream_lua_script_capture_code_t *) e->ip;
|
||||
|
||||
e->ip += sizeof(ngx_stream_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_STREAM, e->log, 0,
|
||||
"lua script capture: \"%*s\"", e->pos - pos, pos);
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_stream_lua_script_init_arrays(ngx_stream_lua_script_compile_t *sc)
|
||||
{
|
||||
ngx_uint_t n;
|
||||
|
||||
if (*sc->lengths == NULL) {
|
||||
n = sc->variables * (2 * sizeof(ngx_stream_lua_script_copy_code_t)
|
||||
+ sizeof(ngx_stream_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_stream_lua_script_copy_code_t)
|
||||
+ sizeof(ngx_stream_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_stream_lua_script_done(ngx_stream_lua_script_compile_t *sc)
|
||||
{
|
||||
uintptr_t *code;
|
||||
|
||||
if (sc->complete_lengths) {
|
||||
code = ngx_stream_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_stream_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_stream_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,96 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_script.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_SCRIPT_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_SCRIPT_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_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_stream_lua_script_compile_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_str_t value;
|
||||
void *lengths;
|
||||
void *values;
|
||||
} ngx_stream_lua_complex_value_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_log_t *log;
|
||||
ngx_pool_t *pool;
|
||||
ngx_str_t *value;
|
||||
|
||||
ngx_stream_lua_complex_value_t *complex_value;
|
||||
} ngx_stream_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_stream_lua_script_engine_t;
|
||||
|
||||
|
||||
typedef void (*ngx_stream_lua_script_code_pt) (
|
||||
ngx_stream_lua_script_engine_t *e);
|
||||
typedef size_t (*ngx_stream_lua_script_len_code_pt)
|
||||
(ngx_stream_lua_script_engine_t *e);
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_stream_lua_script_code_pt code;
|
||||
uintptr_t len;
|
||||
} ngx_stream_lua_script_copy_code_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_stream_lua_script_code_pt code;
|
||||
uintptr_t n;
|
||||
} ngx_stream_lua_script_capture_code_t;
|
||||
|
||||
|
||||
ngx_int_t ngx_stream_lua_compile_complex_value(
|
||||
ngx_stream_lua_compile_complex_value_t *ccv);
|
||||
ngx_int_t ngx_stream_lua_complex_value(ngx_stream_lua_request_t *r,
|
||||
ngx_str_t *subj, size_t offset, ngx_int_t count, int *cap,
|
||||
ngx_stream_lua_complex_value_t *val, luaL_Buffer *luabuf);
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_SCRIPT_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,583 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_semaphore.c.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* 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_stream_lua_util.h"
|
||||
#include "ngx_stream_lua_semaphore.h"
|
||||
#include "ngx_stream_lua_contentby.h"
|
||||
|
||||
|
||||
ngx_int_t ngx_stream_lua_sema_mm_init(ngx_conf_t *cf,
|
||||
ngx_stream_lua_main_conf_t *lmcf);
|
||||
void ngx_stream_lua_sema_mm_cleanup(void *data);
|
||||
static ngx_stream_lua_sema_t *ngx_stream_lua_alloc_sema(void);
|
||||
static void ngx_stream_lua_free_sema(ngx_stream_lua_sema_t *sem);
|
||||
static ngx_int_t ngx_stream_lua_sema_resume(ngx_stream_lua_request_t *r);
|
||||
int ngx_stream_lua_ffi_sema_new(ngx_stream_lua_sema_t **psem,
|
||||
int n, char **errmsg);
|
||||
int ngx_stream_lua_ffi_sema_post(ngx_stream_lua_sema_t *sem, int n);
|
||||
int ngx_stream_lua_ffi_sema_wait(ngx_stream_lua_request_t *r,
|
||||
ngx_stream_lua_sema_t *sem, int wait_ms, u_char *err, size_t *errlen);
|
||||
static void ngx_stream_lua_sema_cleanup(void *data);
|
||||
static void ngx_stream_lua_sema_handler(ngx_event_t *ev);
|
||||
static void ngx_stream_lua_sema_timeout_handler(ngx_event_t *ev);
|
||||
void ngx_stream_lua_ffi_sema_gc(ngx_stream_lua_sema_t *sem);
|
||||
|
||||
|
||||
enum {
|
||||
SEMAPHORE_WAIT_SUCC = 0,
|
||||
SEMAPHORE_WAIT_TIMEOUT = 1
|
||||
};
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_lua_sema_mm_init(ngx_conf_t *cf, ngx_stream_lua_main_conf_t *lmcf)
|
||||
{
|
||||
ngx_stream_lua_sema_mm_t *mm;
|
||||
|
||||
mm = ngx_palloc(cf->pool, sizeof(ngx_stream_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_stream_lua_sema_mm_block_t, one is enough, so it is 4095
|
||||
*/
|
||||
mm->num_per_block = 4095;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
static ngx_stream_lua_sema_t *
|
||||
ngx_stream_lua_alloc_sema(void)
|
||||
{
|
||||
ngx_uint_t i, n;
|
||||
ngx_queue_t *q;
|
||||
ngx_stream_lua_sema_t *sem, *iter;
|
||||
ngx_stream_lua_sema_mm_t *mm;
|
||||
ngx_stream_lua_main_conf_t *lmcf;
|
||||
ngx_stream_lua_sema_mm_block_t *block;
|
||||
|
||||
ngx_stream_lua_assert(ngx_cycle && ngx_cycle->conf_ctx);
|
||||
|
||||
lmcf = ngx_stream_cycle_get_module_main_conf(ngx_cycle,
|
||||
ngx_stream_lua_module);
|
||||
|
||||
ngx_stream_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_stream_lua_sema_t, chain);
|
||||
|
||||
sem->block->used++;
|
||||
|
||||
ngx_memzero(&sem->sem_event, sizeof(ngx_event_t));
|
||||
|
||||
sem->sem_event.handler = ngx_stream_lua_sema_handler;
|
||||
sem->sem_event.data = sem;
|
||||
sem->sem_event.log = ngx_cycle->log;
|
||||
|
||||
mm->used++;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, ngx_cycle->log, 0,
|
||||
"from head of free queue, alloc semaphore: %p", sem);
|
||||
|
||||
return sem;
|
||||
}
|
||||
|
||||
/* free_queue is empty */
|
||||
|
||||
n = sizeof(ngx_stream_lua_sema_mm_block_t)
|
||||
+ mm->num_per_block * sizeof(ngx_stream_lua_sema_t);
|
||||
|
||||
dd("block size: %d, item size: %d",
|
||||
(int) sizeof(ngx_stream_lua_sema_mm_block_t),
|
||||
(int) sizeof(ngx_stream_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_stream_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_stream_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_STREAM, ngx_cycle->log, 0,
|
||||
"new block, alloc semaphore: %p block: %p", sem, block);
|
||||
|
||||
return sem;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_sema_mm_cleanup(void *data)
|
||||
{
|
||||
ngx_uint_t i;
|
||||
ngx_queue_t *q;
|
||||
ngx_stream_lua_sema_t *sem, *iter;
|
||||
ngx_stream_lua_sema_mm_t *mm;
|
||||
ngx_stream_lua_main_conf_t *lmcf;
|
||||
ngx_stream_lua_sema_mm_block_t *block;
|
||||
|
||||
lmcf = (ngx_stream_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_stream_lua_sema_t, chain);
|
||||
block = sem->block;
|
||||
|
||||
ngx_stream_lua_assert(block != NULL);
|
||||
|
||||
if (block->used == 0) {
|
||||
iter = (ngx_stream_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_stream_lua_free_sema(ngx_stream_lua_sema_t *sem)
|
||||
{
|
||||
ngx_stream_lua_sema_t *iter;
|
||||
ngx_uint_t i, mid_epoch;
|
||||
ngx_stream_lua_sema_mm_block_t *block;
|
||||
ngx_stream_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_STREAM, 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_STREAM, 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_stream_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_STREAM, ngx_cycle->log, 0,
|
||||
"free semaphore block: %p", block);
|
||||
|
||||
ngx_free(block);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_stream_lua_sema_resume(ngx_stream_lua_request_t *r)
|
||||
{
|
||||
lua_State *vm;
|
||||
ngx_connection_t *c;
|
||||
ngx_int_t rc;
|
||||
ngx_uint_t nreqs;
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ctx->resume_handler = ngx_stream_lua_wev_handler;
|
||||
|
||||
c = r->connection;
|
||||
vm = ngx_stream_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_stream_lua_run_thread(vm, r, ctx, 2);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, r->connection->log, 0,
|
||||
"lua run thread returned %d", rc);
|
||||
|
||||
if (rc == NGX_AGAIN) {
|
||||
return ngx_stream_lua_run_posted_threads(c, vm, r, ctx, nreqs);
|
||||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
ngx_stream_lua_finalize_request(r, NGX_DONE);
|
||||
return ngx_stream_lua_run_posted_threads(c, vm, r, ctx, nreqs);
|
||||
}
|
||||
|
||||
/* rc == NGX_ERROR || rc >= NGX_OK */
|
||||
|
||||
if (ctx->entered_content_phase) {
|
||||
ngx_stream_lua_finalize_request(r, rc);
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_stream_lua_ffi_sema_new(ngx_stream_lua_sema_t **psem,
|
||||
int n, char **errmsg)
|
||||
{
|
||||
ngx_stream_lua_sema_t *sem;
|
||||
|
||||
sem = ngx_stream_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_STREAM, ngx_cycle->log, 0,
|
||||
"stream lua semaphore new: %p, resources: %d",
|
||||
sem, sem->resource_count);
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_stream_lua_ffi_sema_post(ngx_stream_lua_sema_t *sem, int n)
|
||||
{
|
||||
ngx_log_debug3(NGX_LOG_DEBUG_STREAM, ngx_cycle->log, 0,
|
||||
"stream 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 paranthese 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_stream_lua_ffi_sema_wait(ngx_stream_lua_request_t *r,
|
||||
ngx_stream_lua_sema_t *sem, int wait_ms, u_char *err, size_t *errlen)
|
||||
{
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
ngx_stream_lua_co_ctx_t *wait_co_ctx;
|
||||
ngx_int_t rc;
|
||||
|
||||
ngx_log_debug4(NGX_LOG_DEBUG_STREAM, ngx_cycle->log, 0,
|
||||
"stream lua semaphore wait: %p, timeout: %d, "
|
||||
"resources: %d, event posted: %d",
|
||||
sem, wait_ms, sem->resource_count,
|
||||
#if defined(nginx_version) && nginx_version >= 1007005
|
||||
(int) sem->sem_event.posted
|
||||
#else
|
||||
sem->sem_event.prev ? 1 : 0
|
||||
#endif
|
||||
);
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
if (ctx == NULL) {
|
||||
*errlen = ngx_snprintf(err, *errlen, "no request ctx found") - err;
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
rc = ngx_stream_lua_ffi_check_context(ctx, NGX_STREAM_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_stream_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_stream_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_stream_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_stream_lua_sema_cleanup;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ngx_cycle->log, 0,
|
||||
"stream lua semaphore wait yielding");
|
||||
|
||||
return NGX_AGAIN;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_stream_lua_ffi_sema_count(ngx_stream_lua_sema_t *sem)
|
||||
{
|
||||
return sem->resource_count - sem->wait_count;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_stream_lua_sema_cleanup(void *data)
|
||||
{
|
||||
ngx_stream_lua_co_ctx_t *coctx = data;
|
||||
ngx_queue_t *q;
|
||||
ngx_stream_lua_sema_t *sem;
|
||||
|
||||
sem = coctx->data;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ngx_cycle->log, 0,
|
||||
"stream 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_stream_lua_sema_handler(ngx_event_t *ev)
|
||||
{
|
||||
ngx_stream_lua_sema_t *sem;
|
||||
ngx_stream_lua_request_t *r;
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
ngx_stream_lua_co_ctx_t *wait_co_ctx;
|
||||
ngx_queue_t *q;
|
||||
|
||||
sem = ev->data;
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_STREAM, 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_stream_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_stream_lua_get_req(wait_co_ctx->co);
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
ngx_stream_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_stream_lua_sema_resume(r);
|
||||
|
||||
} else {
|
||||
ctx->resume_handler = ngx_stream_lua_sema_resume;
|
||||
ngx_stream_lua_core_run_phases(r);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_stream_lua_sema_timeout_handler(ngx_event_t *ev)
|
||||
{
|
||||
ngx_stream_lua_co_ctx_t *wait_co_ctx;
|
||||
ngx_stream_lua_request_t *r;
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
ngx_stream_lua_sema_t *sem;
|
||||
|
||||
wait_co_ctx = ev->data;
|
||||
wait_co_ctx->cleanup = NULL;
|
||||
|
||||
dd("ngx_stream_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_stream_lua_get_req(wait_co_ctx->co);
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
ngx_stream_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_stream_lua_sema_resume(r);
|
||||
|
||||
} else {
|
||||
ctx->resume_handler = ngx_stream_lua_sema_resume;
|
||||
ngx_stream_lua_core_run_phases(r);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_ffi_sema_gc(ngx_stream_lua_sema_t *sem)
|
||||
{
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, 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_stream_lua_free_sema(sem);
|
||||
}
|
||||
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,59 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_semaphore.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* 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_STREAM_LUA_SEMAPHORE_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_SEMAPHORE_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
typedef struct ngx_stream_lua_sema_mm_block_s {
|
||||
ngx_uint_t used;
|
||||
ngx_stream_lua_sema_mm_t *mm;
|
||||
ngx_uint_t epoch;
|
||||
} ngx_stream_lua_sema_mm_block_t;
|
||||
|
||||
|
||||
struct ngx_stream_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_stream_lua_main_conf_t *lmcf;
|
||||
};
|
||||
|
||||
|
||||
typedef struct ngx_stream_lua_sema_s {
|
||||
ngx_queue_t wait_queue;
|
||||
ngx_queue_t chain;
|
||||
ngx_event_t sem_event;
|
||||
ngx_stream_lua_sema_mm_block_t *block;
|
||||
int resource_count;
|
||||
unsigned wait_count;
|
||||
} ngx_stream_lua_sema_t;
|
||||
|
||||
|
||||
void ngx_stream_lua_sema_mm_cleanup(void *data);
|
||||
ngx_int_t ngx_stream_lua_sema_mm_init(ngx_conf_t *cf,
|
||||
ngx_stream_lua_main_conf_t *lmcf);
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_SEMAPHORE_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,121 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_shdict.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_SHDICT_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_SHDICT_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
typedef struct {
|
||||
u_char color;
|
||||
uint8_t value_type;
|
||||
u_short key_len;
|
||||
uint32_t value_len;
|
||||
uint64_t expires;
|
||||
ngx_queue_t queue;
|
||||
uint32_t user_flags;
|
||||
u_char data[1];
|
||||
} ngx_stream_lua_shdict_node_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_queue_t queue;
|
||||
uint32_t value_len;
|
||||
uint8_t value_type;
|
||||
u_char data[1];
|
||||
} ngx_stream_lua_shdict_list_node_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_rbtree_t rbtree;
|
||||
ngx_rbtree_node_t sentinel;
|
||||
ngx_queue_t lru_queue;
|
||||
} ngx_stream_lua_shdict_shctx_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_stream_lua_shdict_shctx_t *sh;
|
||||
ngx_slab_pool_t *shpool;
|
||||
ngx_str_t name;
|
||||
ngx_stream_lua_main_conf_t *main_conf;
|
||||
ngx_log_t *log;
|
||||
} ngx_stream_lua_shdict_ctx_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_log_t *log;
|
||||
ngx_stream_lua_main_conf_t *lmcf;
|
||||
ngx_cycle_t *cycle;
|
||||
ngx_shm_zone_t zone;
|
||||
} ngx_stream_lua_shm_zone_ctx_t;
|
||||
|
||||
|
||||
#if (NGX_DARWIN)
|
||||
typedef struct {
|
||||
void *zone;
|
||||
const unsigned char *key;
|
||||
size_t key_len;
|
||||
int *value_type;
|
||||
unsigned char **str_value_buf;
|
||||
size_t *str_value_len;
|
||||
double *num_value;
|
||||
int *user_flags;
|
||||
int get_stale;
|
||||
int *is_stale;
|
||||
char **errmsg;
|
||||
} ngx_stream_lua_shdict_get_params_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
void *zone;
|
||||
int op;
|
||||
const unsigned char *key;
|
||||
size_t key_len;
|
||||
int value_type;
|
||||
const unsigned char *str_value_buf;
|
||||
size_t str_value_len;
|
||||
double num_value;
|
||||
long exptime;
|
||||
int user_flags;
|
||||
char **errmsg;
|
||||
int *forcible;
|
||||
} ngx_stream_lua_shdict_store_params_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
void *zone;
|
||||
const unsigned char *key;
|
||||
size_t key_len;
|
||||
double *num_value;
|
||||
char **errmsg;
|
||||
int has_init;
|
||||
double init;
|
||||
long init_ttl;
|
||||
int *forcible;
|
||||
} ngx_stream_lua_shdict_incr_params_t;
|
||||
#endif
|
||||
|
||||
|
||||
ngx_int_t ngx_stream_lua_shdict_init_zone(ngx_shm_zone_t *shm_zone, void *data);
|
||||
void ngx_stream_lua_shdict_rbtree_insert_value(ngx_rbtree_node_t *temp,
|
||||
ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
|
||||
void ngx_stream_lua_inject_shdict_api(ngx_stream_lua_main_conf_t *lmcf,
|
||||
lua_State *L);
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_SHDICT_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,223 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_sleep.c.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_stream_lua_util.h"
|
||||
#include "ngx_stream_lua_sleep.h"
|
||||
#include "ngx_stream_lua_contentby.h"
|
||||
|
||||
|
||||
static int ngx_stream_lua_ngx_sleep(lua_State *L);
|
||||
static void ngx_stream_lua_sleep_handler(ngx_event_t *ev);
|
||||
static void ngx_stream_lua_sleep_cleanup(void *data);
|
||||
static ngx_int_t ngx_stream_lua_sleep_resume(ngx_stream_lua_request_t *r);
|
||||
|
||||
|
||||
static int
|
||||
ngx_stream_lua_ngx_sleep(lua_State *L)
|
||||
{
|
||||
int n;
|
||||
ngx_int_t delay; /* in msec */
|
||||
ngx_stream_lua_request_t *r;
|
||||
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
ngx_stream_lua_co_ctx_t *coctx;
|
||||
|
||||
n = lua_gettop(L);
|
||||
if (n != 1) {
|
||||
return luaL_error(L, "attempt to pass %d arguments, but accepted 1", n);
|
||||
}
|
||||
|
||||
r = ngx_stream_lua_get_req(L);
|
||||
if (r == NULL) {
|
||||
return luaL_error(L, "no request found");
|
||||
}
|
||||
|
||||
delay = (ngx_int_t) (luaL_checknumber(L, 1) * 1000);
|
||||
|
||||
if (delay < 0) {
|
||||
return luaL_error(L, "invalid sleep duration \"%d\"", delay);
|
||||
}
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return luaL_error(L, "no request ctx found");
|
||||
}
|
||||
|
||||
ngx_stream_lua_check_context(L, ctx, NGX_STREAM_LUA_CONTEXT_YIELDABLE);
|
||||
|
||||
coctx = ctx->cur_co_ctx;
|
||||
if (coctx == NULL) {
|
||||
return luaL_error(L, "no co ctx found");
|
||||
}
|
||||
|
||||
ngx_stream_lua_cleanup_pending_operation(coctx);
|
||||
coctx->cleanup = ngx_stream_lua_sleep_cleanup;
|
||||
coctx->data = r;
|
||||
|
||||
coctx->sleep.handler = ngx_stream_lua_sleep_handler;
|
||||
coctx->sleep.data = coctx;
|
||||
coctx->sleep.log = r->connection->log;
|
||||
|
||||
if (delay == 0) {
|
||||
#ifdef HAVE_POSTED_DELAYED_EVENTS_PATCH
|
||||
dd("posting 0 sec sleep event to head of delayed queue");
|
||||
|
||||
coctx->sleep.delayed = 1;
|
||||
ngx_post_event(&coctx->sleep, &ngx_posted_delayed_events);
|
||||
#else
|
||||
ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, "ngx.sleep(0)"
|
||||
" called without delayed events patch, this will"
|
||||
" hurt performance");
|
||||
ngx_add_timer(&coctx->sleep, (ngx_msec_t) delay);
|
||||
#endif
|
||||
|
||||
} else {
|
||||
dd("adding timer with delay %lu ms, r:%p", (unsigned long) delay, r);
|
||||
|
||||
ngx_add_timer(&coctx->sleep, (ngx_msec_t) delay);
|
||||
}
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, r->connection->log, 0,
|
||||
"lua ready to sleep for %d ms", delay);
|
||||
|
||||
return lua_yield(L, 0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_sleep_handler(ngx_event_t *ev)
|
||||
{
|
||||
#if (NGX_DEBUG)
|
||||
ngx_connection_t *c;
|
||||
#endif
|
||||
ngx_stream_lua_request_t *r;
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
ngx_stream_lua_co_ctx_t *coctx;
|
||||
|
||||
coctx = ev->data;
|
||||
|
||||
r = coctx->data;
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
|
||||
c = r->connection;
|
||||
|
||||
#endif
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
|
||||
if (ctx == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
coctx->cleanup = NULL;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0,
|
||||
"stream lua sleep timer expired");
|
||||
|
||||
ctx->cur_co_ctx = coctx;
|
||||
|
||||
if (ctx->entered_content_phase) {
|
||||
(void) ngx_stream_lua_sleep_resume(r);
|
||||
|
||||
} else {
|
||||
ctx->resume_handler = ngx_stream_lua_sleep_resume;
|
||||
ngx_stream_lua_core_run_phases(r);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_inject_sleep_api(lua_State *L)
|
||||
{
|
||||
lua_pushcfunction(L, ngx_stream_lua_ngx_sleep);
|
||||
lua_setfield(L, -2, "sleep");
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_stream_lua_sleep_cleanup(void *data)
|
||||
{
|
||||
ngx_stream_lua_co_ctx_t *coctx = data;
|
||||
|
||||
if (coctx->sleep.timer_set) {
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ngx_cycle->log, 0,
|
||||
"lua clean up the timer for pending ngx.sleep");
|
||||
|
||||
ngx_del_timer(&coctx->sleep);
|
||||
}
|
||||
|
||||
#ifdef HAVE_POSTED_DELAYED_EVENTS_PATCH
|
||||
if (coctx->sleep.posted) {
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ngx_cycle->log, 0,
|
||||
"lua clean up the posted event for pending ngx.sleep");
|
||||
|
||||
ngx_delete_posted_event(&coctx->sleep);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_stream_lua_sleep_resume(ngx_stream_lua_request_t *r)
|
||||
{
|
||||
lua_State *vm;
|
||||
ngx_connection_t *c;
|
||||
ngx_int_t rc;
|
||||
ngx_uint_t nreqs;
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ctx->resume_handler = ngx_stream_lua_wev_handler;
|
||||
|
||||
c = r->connection;
|
||||
vm = ngx_stream_lua_get_lua_vm(r, ctx);
|
||||
nreqs = c->requests;
|
||||
|
||||
rc = ngx_stream_lua_run_thread(vm, r, ctx, 0);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, r->connection->log, 0,
|
||||
"lua run thread returned %d", rc);
|
||||
|
||||
if (rc == NGX_AGAIN) {
|
||||
return ngx_stream_lua_run_posted_threads(c, vm, r, ctx, nreqs);
|
||||
}
|
||||
|
||||
if (rc == NGX_DONE) {
|
||||
ngx_stream_lua_finalize_request(r, NGX_DONE);
|
||||
return ngx_stream_lua_run_posted_threads(c, vm, r, ctx, nreqs);
|
||||
}
|
||||
|
||||
if (ctx->entered_content_phase) {
|
||||
ngx_stream_lua_finalize_request(r, rc);
|
||||
return NGX_DONE;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_sleep.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_SLEEP_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_SLEEP_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
void ngx_stream_lua_inject_sleep_api(lua_State *L);
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_SLEEP_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,189 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_socket_tcp.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_SOCKET_TCP_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_SOCKET_TCP_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
#define NGX_STREAM_LUA_SOCKET_FT_ERROR 0x0001
|
||||
#define NGX_STREAM_LUA_SOCKET_FT_TIMEOUT 0x0002
|
||||
#define NGX_STREAM_LUA_SOCKET_FT_CLOSED 0x0004
|
||||
#define NGX_STREAM_LUA_SOCKET_FT_RESOLVER 0x0008
|
||||
#define NGX_STREAM_LUA_SOCKET_FT_BUFTOOSMALL 0x0010
|
||||
#define NGX_STREAM_LUA_SOCKET_FT_NOMEM 0x0020
|
||||
#define NGX_STREAM_LUA_SOCKET_FT_PARTIALWRITE 0x0040
|
||||
#define NGX_STREAM_LUA_SOCKET_FT_CLIENTABORT 0x0080
|
||||
#define NGX_STREAM_LUA_SOCKET_FT_SSL 0x0100
|
||||
|
||||
|
||||
typedef struct ngx_stream_lua_socket_tcp_upstream_s
|
||||
ngx_stream_lua_socket_tcp_upstream_t;
|
||||
|
||||
|
||||
typedef
|
||||
int (*ngx_stream_lua_socket_tcp_retval_handler)(ngx_stream_lua_request_t *r,
|
||||
ngx_stream_lua_socket_tcp_upstream_t *u, lua_State *L);
|
||||
|
||||
|
||||
typedef void (*ngx_stream_lua_socket_tcp_upstream_handler_pt)
|
||||
(ngx_stream_lua_request_t *r, ngx_stream_lua_socket_tcp_upstream_t *u);
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_event_t event;
|
||||
ngx_queue_t queue;
|
||||
ngx_str_t host;
|
||||
ngx_stream_lua_cleanup_pt *cleanup;
|
||||
ngx_stream_lua_socket_tcp_upstream_t *u;
|
||||
in_port_t port;
|
||||
} ngx_stream_lua_socket_tcp_conn_op_ctx_t;
|
||||
|
||||
|
||||
#define ngx_stream_lua_socket_tcp_free_conn_op_ctx(conn_op_ctx) \
|
||||
ngx_free(conn_op_ctx->host.data); \
|
||||
ngx_free(conn_op_ctx)
|
||||
|
||||
|
||||
typedef struct {
|
||||
lua_State *lua_vm;
|
||||
|
||||
ngx_int_t size;
|
||||
ngx_queue_t cache_connect_op;
|
||||
ngx_queue_t wait_connect_op;
|
||||
|
||||
/* connections == active connections + pending connect operations,
|
||||
* while active connections == out-of-pool reused connections
|
||||
* + in-pool connections */
|
||||
ngx_int_t connections;
|
||||
|
||||
/* queues of ngx_stream_lua_socket_pool_item_t: */
|
||||
ngx_queue_t cache;
|
||||
ngx_queue_t free;
|
||||
|
||||
ngx_int_t backlog;
|
||||
|
||||
u_char key[1];
|
||||
|
||||
} ngx_stream_lua_socket_pool_t;
|
||||
|
||||
|
||||
struct ngx_stream_lua_socket_tcp_upstream_s {
|
||||
ngx_stream_lua_socket_tcp_retval_handler read_prepare_retvals;
|
||||
ngx_stream_lua_socket_tcp_retval_handler write_prepare_retvals;
|
||||
ngx_stream_lua_socket_tcp_upstream_handler_pt read_event_handler;
|
||||
ngx_stream_lua_socket_tcp_upstream_handler_pt write_event_handler;
|
||||
|
||||
ngx_stream_lua_socket_pool_t *socket_pool;
|
||||
|
||||
ngx_stream_lua_loc_conf_t *conf;
|
||||
ngx_stream_lua_cleanup_pt *cleanup;
|
||||
ngx_stream_lua_request_t *request;
|
||||
|
||||
ngx_peer_connection_t peer;
|
||||
|
||||
ngx_msec_t read_timeout;
|
||||
ngx_msec_t send_timeout;
|
||||
ngx_msec_t connect_timeout;
|
||||
|
||||
ngx_stream_upstream_resolved_t *resolved;
|
||||
|
||||
ngx_chain_t *bufs_in; /* input data buffers */
|
||||
ngx_chain_t *buf_in; /* last input data buffer */
|
||||
ngx_buf_t buffer; /* receive buffer */
|
||||
|
||||
size_t length;
|
||||
size_t rest;
|
||||
|
||||
ngx_err_t socket_errno;
|
||||
|
||||
ngx_int_t (*input_filter)(void *data, ssize_t bytes);
|
||||
void *input_filter_ctx;
|
||||
|
||||
size_t request_len;
|
||||
ngx_chain_t *request_bufs;
|
||||
|
||||
ngx_stream_lua_co_ctx_t *read_co_ctx;
|
||||
ngx_stream_lua_co_ctx_t *write_co_ctx;
|
||||
|
||||
ngx_uint_t reused;
|
||||
|
||||
#if (NGX_STREAM_SSL)
|
||||
ngx_str_t ssl_name;
|
||||
#endif
|
||||
|
||||
unsigned ft_type:16;
|
||||
unsigned no_close:1;
|
||||
unsigned conn_waiting:1;
|
||||
unsigned read_waiting:1;
|
||||
unsigned write_waiting:1;
|
||||
unsigned eof:1;
|
||||
unsigned body_downstream:1;
|
||||
unsigned raw_downstream:1;
|
||||
unsigned read_closed:1;
|
||||
unsigned write_closed:1;
|
||||
unsigned conn_closed:1;
|
||||
unsigned read_consumed:1;
|
||||
#if (NGX_STREAM_SSL)
|
||||
unsigned ssl_verify:1;
|
||||
unsigned ssl_session_reuse:1;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
typedef struct ngx_stream_lua_dfa_edge_s ngx_stream_lua_dfa_edge_t;
|
||||
|
||||
|
||||
struct ngx_stream_lua_dfa_edge_s {
|
||||
ngx_stream_lua_dfa_edge_t *next;
|
||||
int new_state;
|
||||
u_char chr;
|
||||
};
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_stream_lua_socket_tcp_upstream_t *upstream;
|
||||
|
||||
ngx_str_t pattern;
|
||||
ngx_stream_lua_dfa_edge_t **recovering;
|
||||
int state;
|
||||
|
||||
unsigned inclusive:1;
|
||||
} ngx_stream_lua_socket_compiled_pattern_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_stream_lua_socket_pool_t *socket_pool;
|
||||
|
||||
ngx_queue_t queue;
|
||||
ngx_connection_t *connection;
|
||||
|
||||
socklen_t socklen;
|
||||
struct sockaddr_storage sockaddr;
|
||||
|
||||
ngx_uint_t reused;
|
||||
|
||||
} ngx_stream_lua_socket_pool_item_t;
|
||||
|
||||
|
||||
void ngx_stream_lua_inject_socket_tcp_api(ngx_log_t *log, lua_State *L);
|
||||
void ngx_stream_lua_cleanup_conn_pools(lua_State *L);
|
||||
int ngx_stream_lua_req_socket_tcp(lua_State *L);
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_SOCKET_TCP_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,76 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_socket_udp.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_SOCKET_UDP_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_SOCKET_UDP_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
typedef struct ngx_stream_lua_socket_udp_upstream_s
|
||||
ngx_stream_lua_socket_udp_upstream_t;
|
||||
|
||||
|
||||
typedef
|
||||
int (*ngx_stream_lua_socket_udp_retval_handler)(ngx_stream_lua_request_t *r,
|
||||
ngx_stream_lua_socket_udp_upstream_t *u, lua_State *L);
|
||||
|
||||
|
||||
typedef void (*ngx_stream_lua_socket_udp_upstream_handler_pt)
|
||||
(ngx_stream_lua_request_t *r, ngx_stream_lua_socket_udp_upstream_t *u);
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_connection_t *connection;
|
||||
struct sockaddr *sockaddr;
|
||||
socklen_t socklen;
|
||||
ngx_str_t server;
|
||||
ngx_log_t log;
|
||||
} ngx_stream_lua_udp_connection_t;
|
||||
|
||||
|
||||
struct ngx_stream_lua_socket_udp_upstream_s {
|
||||
ngx_stream_lua_socket_udp_retval_handler prepare_retvals;
|
||||
ngx_stream_lua_socket_udp_upstream_handler_pt read_event_handler;
|
||||
|
||||
ngx_stream_lua_loc_conf_t *conf;
|
||||
ngx_stream_lua_cleanup_pt *cleanup;
|
||||
ngx_stream_lua_request_t *request;
|
||||
ngx_stream_lua_udp_connection_t udp_connection;
|
||||
|
||||
ngx_msec_t read_timeout;
|
||||
|
||||
ngx_stream_upstream_resolved_t *resolved;
|
||||
|
||||
ngx_uint_t ft_type;
|
||||
ngx_err_t socket_errno;
|
||||
size_t received; /* for receive */
|
||||
size_t recv_buf_size;
|
||||
|
||||
ngx_stream_lua_co_ctx_t *co_ctx;
|
||||
|
||||
unsigned waiting:1;
|
||||
|
||||
unsigned raw_downstream:1;
|
||||
};
|
||||
|
||||
|
||||
void ngx_stream_lua_inject_socket_udp_api(ngx_log_t *log, lua_State *L);
|
||||
int ngx_stream_lua_req_socket_udp(lua_State *L);
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_SOCKET_UDP_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,47 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_ssl.c.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#if (NGX_STREAM_SSL)
|
||||
|
||||
|
||||
int ngx_stream_lua_ssl_ctx_index = -1;
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_lua_ssl_init(ngx_log_t *log)
|
||||
{
|
||||
if (ngx_stream_lua_ssl_ctx_index == -1) {
|
||||
ngx_stream_lua_ssl_ctx_index = SSL_get_ex_new_index(0, NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
if (ngx_stream_lua_ssl_ctx_index == -1) {
|
||||
ngx_ssl_error(NGX_LOG_ALERT, log, 0,
|
||||
"lua: SSL_get_ex_new_index() for ctx failed");
|
||||
return NGX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
#endif /* NGX_STREAM_SSL */
|
|
@ -0,0 +1,61 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_ssl.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_SSL_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_SSL_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
#if (NGX_STREAM_SSL)
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_connection_t *connection; /* original true connection */
|
||||
ngx_stream_lua_request_t *request; /* fake request */
|
||||
ngx_pool_cleanup_pt *cleanup;
|
||||
|
||||
ngx_ssl_session_t *session; /* retrurn value for openssl's
|
||||
* session_get_cb */
|
||||
|
||||
ngx_str_t session_id;
|
||||
|
||||
int exit_code; /* exit code for openssl's
|
||||
set_client_hello_cb or
|
||||
set_cert_cb callback */
|
||||
|
||||
int ctx_ref; /* reference to anchor
|
||||
request ctx data in lua
|
||||
registry */
|
||||
|
||||
unsigned done:1;
|
||||
unsigned aborted:1;
|
||||
|
||||
unsigned entered_client_hello_handler:1;
|
||||
unsigned entered_cert_handler:1;
|
||||
unsigned entered_sess_fetch_handler:1;
|
||||
} ngx_stream_lua_ssl_ctx_t;
|
||||
|
||||
|
||||
ngx_int_t ngx_stream_lua_ssl_init(ngx_log_t *log);
|
||||
|
||||
|
||||
extern int ngx_stream_lua_ssl_ctx_index;
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_SSL_H_INCLUDED_ */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,45 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_ssl_certby.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_SSL_CERTBY_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_SSL_CERTBY_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
#if (NGX_STREAM_SSL)
|
||||
|
||||
|
||||
ngx_int_t ngx_stream_lua_ssl_cert_handler_inline(ngx_stream_lua_request_t *r,
|
||||
ngx_stream_lua_srv_conf_t *lscf, lua_State *L);
|
||||
|
||||
ngx_int_t ngx_stream_lua_ssl_cert_handler_file(ngx_stream_lua_request_t *r,
|
||||
ngx_stream_lua_srv_conf_t *lscf, lua_State *L);
|
||||
|
||||
char *ngx_stream_lua_ssl_cert_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
|
||||
char *ngx_stream_lua_ssl_cert_by_lua(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
|
||||
int ngx_stream_lua_ssl_cert_handler(ngx_ssl_conn_t *ssl_conn, void *data);
|
||||
|
||||
|
||||
#endif /* NGX_STREAM_SSL */
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_SSL_CERTBY_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,716 @@
|
|||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#if (NGX_STREAM_SSL)
|
||||
|
||||
#include "ngx_stream_lua_cache.h"
|
||||
#include "ngx_stream_lua_initworkerby.h"
|
||||
#include "ngx_stream_lua_util.h"
|
||||
#include "ngx_stream_ssl_module.h"
|
||||
#include "ngx_stream_lua_contentby.h"
|
||||
#include "ngx_stream_lua_ssl_certby.h"
|
||||
#include "ngx_stream_lua_ssl_client_helloby.h"
|
||||
#include "ngx_stream_lua_directive.h"
|
||||
#include "ngx_stream_lua_ssl.h"
|
||||
|
||||
|
||||
static void ngx_stream_lua_ssl_client_hello_done(void *data);
|
||||
static void ngx_stream_lua_ssl_client_hello_aborted(void *data);
|
||||
static u_char *ngx_stream_lua_log_ssl_client_hello_error(ngx_log_t *log,
|
||||
u_char *buf, size_t len);
|
||||
static ngx_int_t ngx_stream_lua_ssl_client_hello_by_chunk(lua_State *L,
|
||||
ngx_stream_lua_request_t *r);
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_lua_ssl_client_hello_handler_file(ngx_stream_lua_request_t *r,
|
||||
ngx_stream_lua_srv_conf_t *lscf, lua_State *L)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
|
||||
rc = ngx_stream_lua_cache_loadfile(r->connection->log, L,
|
||||
lscf->srv.ssl_client_hello_src.data,
|
||||
lscf->srv.ssl_client_hello_src_key);
|
||||
if (rc != NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* make sure we have a valid code chunk */
|
||||
ngx_stream_lua_assert(lua_isfunction(L, -1));
|
||||
|
||||
return ngx_stream_lua_ssl_client_hello_by_chunk(L, r);
|
||||
}
|
||||
|
||||
|
||||
ngx_int_t
|
||||
ngx_stream_lua_ssl_client_hello_handler_inline(ngx_stream_lua_request_t *r,
|
||||
ngx_stream_lua_srv_conf_t *lscf, lua_State *L)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
|
||||
rc = ngx_stream_lua_cache_loadbuffer(r->connection->log, L,
|
||||
lscf->srv.ssl_client_hello_src.data,
|
||||
lscf->srv.ssl_client_hello_src.len,
|
||||
lscf->srv.ssl_client_hello_src_key,
|
||||
"=ssl_client_hello_by_lua");
|
||||
if (rc != NGX_OK) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* make sure we have a valid code chunk */
|
||||
ngx_stream_lua_assert(lua_isfunction(L, -1));
|
||||
|
||||
return ngx_stream_lua_ssl_client_hello_by_chunk(L, r);
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
ngx_stream_lua_ssl_client_hello_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf)
|
||||
{
|
||||
char *rv;
|
||||
ngx_conf_t save;
|
||||
|
||||
save = *cf;
|
||||
cf->handler = ngx_stream_lua_ssl_client_hello_by_lua;
|
||||
cf->handler_conf = conf;
|
||||
|
||||
rv = ngx_stream_lua_conf_lua_block_parse(cf, cmd);
|
||||
|
||||
*cf = save;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
ngx_stream_lua_ssl_client_hello_by_lua(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf)
|
||||
{
|
||||
#ifndef SSL_ERROR_WANT_CLIENT_HELLO_CB
|
||||
|
||||
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
|
||||
"at least OpenSSL 1.1.1 required but found "
|
||||
OPENSSL_VERSION_TEXT);
|
||||
|
||||
return NGX_CONF_ERROR;
|
||||
|
||||
#else
|
||||
|
||||
u_char *p;
|
||||
u_char *name;
|
||||
ngx_str_t *value;
|
||||
ngx_stream_lua_srv_conf_t *lscf = conf;
|
||||
|
||||
/* must specify a concrete handler */
|
||||
if (cmd->post == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
if (lscf->srv.ssl_client_hello_handler) {
|
||||
return "is duplicate";
|
||||
}
|
||||
|
||||
if (ngx_stream_lua_ssl_init(cf->log) != NGX_OK) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
value = cf->args->elts;
|
||||
|
||||
lscf->srv.ssl_client_hello_handler =
|
||||
(ngx_stream_lua_srv_conf_handler_pt) cmd->post;
|
||||
|
||||
if (cmd->post == ngx_stream_lua_ssl_client_hello_handler_file) {
|
||||
/* Lua code in an external file */
|
||||
|
||||
name = ngx_stream_lua_rebase_path(cf->pool, value[1].data,
|
||||
value[1].len);
|
||||
if (name == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
lscf->srv.ssl_client_hello_src.data = name;
|
||||
lscf->srv.ssl_client_hello_src.len = ngx_strlen(name);
|
||||
|
||||
p = ngx_palloc(cf->pool, NGX_STREAM_LUA_FILE_KEY_LEN + 1);
|
||||
if (p == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
lscf->srv.ssl_client_hello_src_key = p;
|
||||
|
||||
p = ngx_copy(p, NGX_STREAM_LUA_FILE_TAG, NGX_STREAM_LUA_FILE_TAG_LEN);
|
||||
p = ngx_stream_lua_digest_hex(p, value[1].data, value[1].len);
|
||||
*p = '\0';
|
||||
|
||||
} else {
|
||||
/* inlined Lua code */
|
||||
|
||||
lscf->srv.ssl_client_hello_src = value[1];
|
||||
|
||||
p = ngx_palloc(cf->pool,
|
||||
sizeof("ssl_client_hello_by_lua") +
|
||||
NGX_STREAM_LUA_INLINE_KEY_LEN);
|
||||
if (p == NULL) {
|
||||
return NGX_CONF_ERROR;
|
||||
}
|
||||
|
||||
lscf->srv.ssl_client_hello_src_key = p;
|
||||
|
||||
p = ngx_copy(p, "ssl_client_hello_by_lua",
|
||||
sizeof("ssl_client_hello_by_lua") - 1);
|
||||
p = ngx_copy(p, NGX_STREAM_LUA_INLINE_TAG,
|
||||
NGX_STREAM_LUA_INLINE_TAG_LEN);
|
||||
p = ngx_stream_lua_digest_hex(p, value[1].data, value[1].len);
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
return NGX_CONF_OK;
|
||||
|
||||
#endif /* NO SSL_ERROR_WANT_CLIENT_HELLO_CB */
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_stream_lua_ssl_client_hello_handler(ngx_ssl_conn_t *ssl_conn,
|
||||
int *al, void *arg)
|
||||
{
|
||||
lua_State *L;
|
||||
ngx_int_t rc;
|
||||
ngx_connection_t *c, *fc;
|
||||
ngx_stream_lua_request_t *r = NULL;
|
||||
ngx_pool_cleanup_t *cln;
|
||||
ngx_stream_lua_srv_conf_t *lscf;
|
||||
ngx_stream_lua_ssl_ctx_t *cctx;
|
||||
ngx_stream_core_srv_conf_t *cscf;
|
||||
ngx_stream_session_t *s, *fs;
|
||||
|
||||
c = ngx_ssl_get_connection(ssl_conn);
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0,
|
||||
"stream ssl client hello: connection reusable: %ud",
|
||||
c->reusable);
|
||||
|
||||
cctx = ngx_stream_lua_ssl_get_ctx(c->ssl->connection);
|
||||
|
||||
dd("ssl client hello handler, client-hello-ctx=%p", cctx);
|
||||
|
||||
if (cctx && cctx->entered_client_hello_handler) {
|
||||
/* not the first time */
|
||||
|
||||
if (cctx->done) {
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0,
|
||||
"stream lua_client_hello_by_lua:"
|
||||
" client hello cb exit code: %d",
|
||||
cctx->exit_code);
|
||||
|
||||
dd("lua ssl client hello done, finally");
|
||||
return cctx->exit_code;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
dd("first time");
|
||||
|
||||
ngx_reusable_connection(c, 0);
|
||||
|
||||
s = c->data;
|
||||
|
||||
fc = ngx_stream_lua_create_fake_connection(NULL);
|
||||
if (fc == NULL) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
fc->log->handler = ngx_stream_lua_log_ssl_client_hello_error;
|
||||
fc->log->data = fc;
|
||||
|
||||
fc->addr_text = c->addr_text;
|
||||
fc->listening = c->listening;
|
||||
|
||||
fs = ngx_stream_lua_create_fake_session(fc);
|
||||
if (fs == NULL) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
fs->main_conf = s->main_conf;
|
||||
fs->srv_conf = s->srv_conf;
|
||||
|
||||
r = ngx_stream_lua_create_fake_request(fs);
|
||||
if (r == NULL) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
fc->log->file = c->log->file;
|
||||
fc->log->log_level = c->log->log_level;
|
||||
fc->ssl = c->ssl;
|
||||
|
||||
cscf = ngx_stream_get_module_srv_conf(fs, ngx_stream_core_module);
|
||||
|
||||
#if defined(nginx_version) && nginx_version >= 1009000
|
||||
ngx_set_connection_log(fc, cscf->error_log);
|
||||
|
||||
#else
|
||||
#error "stream ssl_client_hello_by_lua only supports nginx >= 1.19.3"
|
||||
#endif
|
||||
|
||||
if (cctx == NULL) {
|
||||
cctx = ngx_pcalloc(c->pool, sizeof(ngx_stream_lua_ssl_ctx_t));
|
||||
if (cctx == NULL) {
|
||||
goto failed; /* error */
|
||||
}
|
||||
|
||||
cctx->ctx_ref = LUA_NOREF;
|
||||
}
|
||||
|
||||
cctx->exit_code = 1; /* successful by default */
|
||||
cctx->connection = c;
|
||||
cctx->request = r;
|
||||
cctx->entered_client_hello_handler = 1;
|
||||
cctx->done = 0;
|
||||
|
||||
dd("setting cctx");
|
||||
|
||||
if (SSL_set_ex_data(c->ssl->connection, ngx_stream_lua_ssl_ctx_index,
|
||||
cctx) == 0)
|
||||
{
|
||||
ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_ex_data() failed");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
lscf = ngx_stream_lua_get_module_srv_conf(r, ngx_stream_lua_module);
|
||||
|
||||
/* TODO honor lua_code_cache off */
|
||||
L = ngx_stream_lua_get_lua_vm(r, NULL);
|
||||
|
||||
c->log->action = "loading SSL client hello by lua";
|
||||
|
||||
if (lscf->srv.ssl_client_hello_handler == NULL) {
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, c->log, 0,
|
||||
"no ssl_client_hello_by_lua* defined in "
|
||||
"server %s:%ui", &cscf->file_name, &cscf->line);
|
||||
|
||||
goto failed;
|
||||
}
|
||||
|
||||
rc = lscf->srv.ssl_client_hello_handler(r, lscf, L);
|
||||
|
||||
if (rc >= NGX_OK || rc == NGX_ERROR) {
|
||||
cctx->done = 1;
|
||||
|
||||
if (cctx->cleanup) {
|
||||
*cctx->cleanup = NULL;
|
||||
}
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_STREAM, c->log, 0,
|
||||
"stream lua_client_hello_by_lua:"
|
||||
" handler return value: %i, "
|
||||
"client hello cb exit code: %d", rc, cctx->exit_code);
|
||||
|
||||
c->log->action = "SSL handshaking";
|
||||
return cctx->exit_code;
|
||||
}
|
||||
|
||||
/* rc == NGX_DONE */
|
||||
|
||||
cln = ngx_pool_cleanup_add(fc->pool, 0);
|
||||
if (cln == NULL) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
cln->handler = ngx_stream_lua_ssl_client_hello_done;
|
||||
cln->data = cctx;
|
||||
|
||||
if (cctx->cleanup == NULL) {
|
||||
cln = ngx_pool_cleanup_add(c->pool, 0);
|
||||
if (cln == NULL) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
cln->data = cctx;
|
||||
cctx->cleanup = &cln->handler;
|
||||
}
|
||||
|
||||
*cctx->cleanup = ngx_stream_lua_ssl_client_hello_aborted;
|
||||
|
||||
return -1;
|
||||
|
||||
#if 1
|
||||
failed:
|
||||
|
||||
if (r && r->pool) {
|
||||
ngx_stream_lua_free_fake_request(r);
|
||||
}
|
||||
|
||||
if (fc) {
|
||||
ngx_stream_lua_close_fake_connection(fc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_stream_lua_ssl_client_hello_done(void *data)
|
||||
{
|
||||
ngx_connection_t *c;
|
||||
ngx_stream_lua_ssl_ctx_t *cctx = data;
|
||||
|
||||
dd("lua ssl client hello done");
|
||||
|
||||
if (cctx->aborted) {
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_stream_lua_assert(cctx->done == 0);
|
||||
|
||||
cctx->done = 1;
|
||||
|
||||
if (cctx->cleanup) {
|
||||
*cctx->cleanup = NULL;
|
||||
}
|
||||
|
||||
c = cctx->connection;
|
||||
|
||||
c->log->action = "SSL handshaking";
|
||||
|
||||
ngx_post_event(c->write, &ngx_posted_events);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_stream_lua_ssl_client_hello_aborted(void *data)
|
||||
{
|
||||
ngx_stream_lua_ssl_ctx_t *cctx = data;
|
||||
|
||||
dd("lua ssl client hello done");
|
||||
|
||||
if (cctx->done) {
|
||||
/* completed successfully already */
|
||||
return;
|
||||
}
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, cctx->connection->log, 0,
|
||||
"stream lua_client_hello_by_lua: client hello cb aborted");
|
||||
|
||||
cctx->aborted = 1;
|
||||
cctx->request->connection->ssl = NULL;
|
||||
|
||||
ngx_stream_lua_finalize_fake_request(cctx->request, NGX_ERROR);
|
||||
}
|
||||
|
||||
|
||||
static u_char *
|
||||
ngx_stream_lua_log_ssl_client_hello_error(ngx_log_t *log, u_char *buf,
|
||||
size_t len)
|
||||
{
|
||||
u_char *p;
|
||||
ngx_connection_t *c;
|
||||
|
||||
if (log->action) {
|
||||
p = ngx_snprintf(buf, len, " while %s", log->action);
|
||||
len -= p - buf;
|
||||
buf = p;
|
||||
}
|
||||
|
||||
p = ngx_snprintf(buf, len, ", context: ssl_client_hello_by_lua*");
|
||||
len -= p - buf;
|
||||
buf = p;
|
||||
|
||||
c = log->data;
|
||||
|
||||
if (c && c->addr_text.len) {
|
||||
p = ngx_snprintf(buf, len, ", client: %V", &c->addr_text);
|
||||
len -= p - buf;
|
||||
buf = p;
|
||||
}
|
||||
|
||||
if (c && c->listening && c->listening->addr_text.len) {
|
||||
p = ngx_snprintf(buf, len, ", server: %V", &c->listening->addr_text);
|
||||
/* len -= p - buf; */
|
||||
buf = p;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_stream_lua_ssl_client_hello_by_chunk(lua_State *L,
|
||||
ngx_stream_lua_request_t *r)
|
||||
{
|
||||
int co_ref;
|
||||
ngx_int_t rc;
|
||||
lua_State *co;
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
ngx_stream_lua_cleanup_t *cln;
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
|
||||
if (ctx == NULL) {
|
||||
ctx = ngx_stream_lua_create_ctx(r->session);
|
||||
if (ctx == NULL) {
|
||||
rc = NGX_ERROR;
|
||||
ngx_stream_lua_finalize_request(r, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
} else {
|
||||
dd("reset ctx");
|
||||
ngx_stream_lua_reset_ctx(r, L, ctx);
|
||||
}
|
||||
|
||||
ctx->entered_content_phase = 1;
|
||||
|
||||
/* {{{ new coroutine to handle request */
|
||||
co = ngx_stream_lua_new_thread(r, L, &co_ref);
|
||||
|
||||
if (co == NULL) {
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"stream failed to create new"
|
||||
" coroutine to handle request");
|
||||
|
||||
rc = NGX_ERROR;
|
||||
ngx_stream_lua_finalize_request(r, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* 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_stream_lua_get_globals_table(co);
|
||||
lua_setfenv(co, -2);
|
||||
#endif
|
||||
|
||||
/* save nginx request in coroutine globals table */
|
||||
ngx_stream_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
|
||||
|
||||
/* register request cleanup hooks */
|
||||
if (ctx->cleanup == NULL) {
|
||||
cln = ngx_stream_lua_cleanup_add(r, 0);
|
||||
if (cln == NULL) {
|
||||
rc = NGX_ERROR;
|
||||
ngx_stream_lua_finalize_request(r, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
cln->handler = ngx_stream_lua_request_cleanup_handler;
|
||||
cln->data = ctx;
|
||||
ctx->cleanup = &cln->handler;
|
||||
}
|
||||
|
||||
ctx->context = NGX_STREAM_LUA_CONTEXT_SSL_CLIENT_HELLO;
|
||||
|
||||
rc = ngx_stream_lua_run_thread(L, r, ctx, 0);
|
||||
|
||||
if (rc == NGX_ERROR || rc >= NGX_OK) {
|
||||
/* do nothing */
|
||||
|
||||
} else if (rc == NGX_AGAIN) {
|
||||
rc = ngx_stream_lua_content_run_posted_threads(L, r, ctx, 0);
|
||||
|
||||
} else if (rc == NGX_DONE) {
|
||||
rc = ngx_stream_lua_content_run_posted_threads(L, r, ctx, 1);
|
||||
|
||||
} else {
|
||||
rc = NGX_OK;
|
||||
}
|
||||
|
||||
ngx_stream_lua_finalize_request(r, rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int ngx_stream_lua_ffi_ssl_get_client_hello_server_name(
|
||||
ngx_stream_lua_request_t *r, const char **name,
|
||||
size_t *namelen, char **err)
|
||||
{
|
||||
ngx_ssl_conn_t *ssl_conn;
|
||||
#ifdef SSL_ERROR_WANT_CLIENT_HELLO_CB
|
||||
const unsigned char *p;
|
||||
size_t remaining, len;
|
||||
#endif
|
||||
|
||||
if (r->connection == NULL || r->connection->ssl == NULL) {
|
||||
*err = "bad request";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ssl_conn = r->connection->ssl->connection;
|
||||
if (ssl_conn == NULL) {
|
||||
*err = "bad ssl conn";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||
|
||||
#ifdef SSL_ERROR_WANT_CLIENT_HELLO_CB
|
||||
remaining = 0;
|
||||
|
||||
/* This code block is taken from OpenSSL's client_hello_select_server_ctx()
|
||||
* */
|
||||
if (!SSL_client_hello_get0_ext(ssl_conn, TLSEXT_TYPE_server_name, &p,
|
||||
&remaining))
|
||||
{
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
if (remaining <= 2) {
|
||||
*err = "Bad SSL Client Hello Extension";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
len = (*(p++) << 8);
|
||||
len += *(p++);
|
||||
if (len + 2 != remaining) {
|
||||
*err = "Bad SSL Client Hello Extension";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
remaining = len;
|
||||
if (remaining == 0 || *p++ != TLSEXT_NAMETYPE_host_name) {
|
||||
*err = "Bad SSL Client Hello Extension";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
remaining--;
|
||||
if (remaining <= 2) {
|
||||
*err = "Bad SSL Client Hello Extension";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
len = (*(p++) << 8);
|
||||
len += *(p++);
|
||||
if (len + 2 > remaining) {
|
||||
*err = "Bad SSL Client Hello Extension";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
remaining = len;
|
||||
*name = (const char *) p;
|
||||
*namelen = len;
|
||||
|
||||
return NGX_OK;
|
||||
|
||||
#else
|
||||
*err = "OpenSSL too old to support this function";
|
||||
return NGX_ERROR;
|
||||
#endif
|
||||
|
||||
#else
|
||||
*err = "no TLS extension support";
|
||||
return NGX_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_stream_lua_ffi_ssl_get_client_hello_ext(ngx_stream_lua_request_t *r,
|
||||
unsigned int type, const unsigned char **out, size_t *outlen, char **err)
|
||||
{
|
||||
ngx_ssl_conn_t *ssl_conn;
|
||||
|
||||
if (r->connection == NULL || r->connection->ssl == NULL) {
|
||||
*err = "bad request";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ssl_conn = r->connection->ssl->connection;
|
||||
if (ssl_conn == NULL) {
|
||||
*err = "bad ssl conn";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
#ifdef SSL_ERROR_WANT_CLIENT_HELLO_CB
|
||||
if (SSL_client_hello_get0_ext(ssl_conn, type, out, outlen) == 0) {
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
|
||||
#else
|
||||
*err = "OpenSSL too old to support this function";
|
||||
return NGX_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_stream_lua_ffi_ssl_set_protocols(ngx_stream_lua_request_t *r,
|
||||
int protocols, char **err)
|
||||
{
|
||||
|
||||
ngx_ssl_conn_t *ssl_conn;
|
||||
|
||||
if (r->connection == NULL || r->connection->ssl == NULL) {
|
||||
*err = "bad request";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
ssl_conn = r->connection->ssl->connection;
|
||||
if (ssl_conn == NULL) {
|
||||
*err = "bad ssl conn";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x009080dfL
|
||||
/* only in 0.9.8m+ */
|
||||
SSL_clear_options(ssl_conn,
|
||||
SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1);
|
||||
#endif
|
||||
|
||||
if (!(protocols & NGX_SSL_SSLv2)) {
|
||||
SSL_set_options(ssl_conn, SSL_OP_NO_SSLv2);
|
||||
}
|
||||
|
||||
if (!(protocols & NGX_SSL_SSLv3)) {
|
||||
SSL_set_options(ssl_conn, SSL_OP_NO_SSLv3);
|
||||
}
|
||||
|
||||
if (!(protocols & NGX_SSL_TLSv1)) {
|
||||
SSL_set_options(ssl_conn, SSL_OP_NO_TLSv1);
|
||||
}
|
||||
|
||||
#ifdef SSL_OP_NO_TLSv1_1
|
||||
SSL_clear_options(ssl_conn, SSL_OP_NO_TLSv1_1);
|
||||
if (!(protocols & NGX_SSL_TLSv1_1)) {
|
||||
SSL_set_options(ssl_conn, SSL_OP_NO_TLSv1_1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SSL_OP_NO_TLSv1_2
|
||||
SSL_clear_options(ssl_conn, SSL_OP_NO_TLSv1_2);
|
||||
if (!(protocols & NGX_SSL_TLSv1_2)) {
|
||||
SSL_set_options(ssl_conn, SSL_OP_NO_TLSv1_2);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SSL_OP_NO_TLSv1_3
|
||||
SSL_clear_options(ssl_conn, SSL_OP_NO_TLSv1_3);
|
||||
if (!(protocols & NGX_SSL_TLSv1_3)) {
|
||||
SSL_set_options(ssl_conn, SSL_OP_NO_TLSv1_3);
|
||||
}
|
||||
#endif
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
#endif /* NGX_STREAM_SSL */
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_SSL_CLIENT_HELLOBY_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_SSL_CLIENT_HELLOBY_H_INCLUDED_
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
#if (NGX_STREAM_SSL)
|
||||
|
||||
ngx_int_t ngx_stream_lua_ssl_client_hello_handler_inline(
|
||||
ngx_stream_lua_request_t *r, ngx_stream_lua_srv_conf_t *lscf, lua_State *L);
|
||||
|
||||
ngx_int_t ngx_stream_lua_ssl_client_hello_handler_file(
|
||||
ngx_stream_lua_request_t *r, ngx_stream_lua_srv_conf_t *lscf, lua_State *L);
|
||||
|
||||
char *ngx_stream_lua_ssl_client_hello_by_lua_block(ngx_conf_t *cf,
|
||||
ngx_command_t *cmd, void *conf);
|
||||
|
||||
char *ngx_stream_lua_ssl_client_hello_by_lua(ngx_conf_t *cf, ngx_command_t *cmd,
|
||||
void *conf);
|
||||
|
||||
int ngx_stream_lua_ssl_client_hello_handler(ngx_ssl_conn_t *ssl_conn,
|
||||
int *al, void *arg);
|
||||
|
||||
#endif /* NGX_STREAM_SSL */
|
||||
#endif /* _NGX_STREAM_LUA_SSL_CLIENT_HELLOBY_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,463 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_string.c.tt2
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_stream_lua_string.h"
|
||||
#include "ngx_stream_lua_util.h"
|
||||
#include "ngx_stream_lua_args.h"
|
||||
#include "ngx_crc32.h"
|
||||
|
||||
#if (NGX_HAVE_SHA1)
|
||||
#include "ngx_sha1.h"
|
||||
#endif
|
||||
|
||||
#include "ngx_md5.h"
|
||||
|
||||
#if (NGX_OPENSSL)
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hmac.h>
|
||||
#endif
|
||||
|
||||
|
||||
static uintptr_t ngx_stream_lua_ngx_escape_sql_str(u_char *dst,
|
||||
u_char *src, size_t size);
|
||||
static int ngx_stream_lua_ngx_quote_sql_str(lua_State *L);
|
||||
static int ngx_stream_lua_ngx_encode_args(lua_State *L);
|
||||
static int ngx_stream_lua_ngx_decode_args(lua_State *L);
|
||||
#if (NGX_OPENSSL)
|
||||
static int ngx_stream_lua_ngx_hmac_sha1(lua_State *L);
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_inject_string_api(lua_State *L)
|
||||
{
|
||||
lua_pushcfunction(L, ngx_stream_lua_ngx_encode_args);
|
||||
lua_setfield(L, -2, "encode_args");
|
||||
|
||||
lua_pushcfunction(L, ngx_stream_lua_ngx_decode_args);
|
||||
lua_setfield(L, -2, "decode_args");
|
||||
|
||||
lua_pushcfunction(L, ngx_stream_lua_ngx_quote_sql_str);
|
||||
lua_setfield(L, -2, "quote_sql_str");
|
||||
|
||||
#if (NGX_OPENSSL)
|
||||
lua_pushcfunction(L, ngx_stream_lua_ngx_hmac_sha1);
|
||||
lua_setfield(L, -2, "hmac_sha1");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_stream_lua_ngx_quote_sql_str(lua_State *L)
|
||||
{
|
||||
size_t len, dlen, escape;
|
||||
u_char *p;
|
||||
u_char *src, *dst;
|
||||
|
||||
if (lua_gettop(L) != 1) {
|
||||
return luaL_error(L, "expecting one argument");
|
||||
}
|
||||
|
||||
src = (u_char *) luaL_checklstring(L, 1, &len);
|
||||
|
||||
if (len == 0) {
|
||||
dst = (u_char *) "''";
|
||||
dlen = sizeof("''") - 1;
|
||||
lua_pushlstring(L, (char *) dst, dlen);
|
||||
return 1;
|
||||
}
|
||||
|
||||
escape = ngx_stream_lua_ngx_escape_sql_str(NULL, src, len);
|
||||
|
||||
dlen = sizeof("''") - 1 + len + escape;
|
||||
|
||||
p = lua_newuserdata(L, dlen);
|
||||
|
||||
dst = p;
|
||||
|
||||
*p++ = '\'';
|
||||
|
||||
if (escape == 0) {
|
||||
p = ngx_copy(p, src, len);
|
||||
|
||||
} else {
|
||||
p = (u_char *) ngx_stream_lua_ngx_escape_sql_str(p, src, len);
|
||||
}
|
||||
|
||||
*p++ = '\'';
|
||||
|
||||
if (p != dst + dlen) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
lua_pushlstring(L, (char *) dst, p - dst);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static uintptr_t
|
||||
ngx_stream_lua_ngx_escape_sql_str(u_char *dst, u_char *src, size_t size)
|
||||
{
|
||||
ngx_uint_t n;
|
||||
|
||||
if (dst == NULL) {
|
||||
/* find the number of chars to be escaped */
|
||||
n = 0;
|
||||
while (size) {
|
||||
/* the highest bit of all the UTF-8 chars
|
||||
* is always 1 */
|
||||
if ((*src & 0x80) == 0) {
|
||||
switch (*src) {
|
||||
case '\0':
|
||||
case '\b':
|
||||
case '\n':
|
||||
case '\r':
|
||||
case '\t':
|
||||
case 26: /* \Z */
|
||||
case '\\':
|
||||
case '\'':
|
||||
case '"':
|
||||
n++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
src++;
|
||||
size--;
|
||||
}
|
||||
|
||||
return (uintptr_t) n;
|
||||
}
|
||||
|
||||
while (size) {
|
||||
if ((*src & 0x80) == 0) {
|
||||
switch (*src) {
|
||||
case '\0':
|
||||
*dst++ = '\\';
|
||||
*dst++ = '0';
|
||||
break;
|
||||
|
||||
case '\b':
|
||||
*dst++ = '\\';
|
||||
*dst++ = 'b';
|
||||
break;
|
||||
|
||||
case '\n':
|
||||
*dst++ = '\\';
|
||||
*dst++ = 'n';
|
||||
break;
|
||||
|
||||
case '\r':
|
||||
*dst++ = '\\';
|
||||
*dst++ = 'r';
|
||||
break;
|
||||
|
||||
case '\t':
|
||||
*dst++ = '\\';
|
||||
*dst++ = 't';
|
||||
break;
|
||||
|
||||
case 26:
|
||||
*dst++ = '\\';
|
||||
*dst++ = 'Z';
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
*dst++ = '\\';
|
||||
*dst++ = '\\';
|
||||
break;
|
||||
|
||||
case '\'':
|
||||
*dst++ = '\\';
|
||||
*dst++ = '\'';
|
||||
break;
|
||||
|
||||
case '"':
|
||||
*dst++ = '\\';
|
||||
*dst++ = '"';
|
||||
break;
|
||||
|
||||
default:
|
||||
*dst++ = *src;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
*dst++ = *src;
|
||||
}
|
||||
src++;
|
||||
size--;
|
||||
} /* while (size) */
|
||||
|
||||
return (uintptr_t) dst;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_stream_lua_encode_base64(ngx_str_t *dst, ngx_str_t *src, int no_padding)
|
||||
{
|
||||
u_char *d, *s;
|
||||
size_t len;
|
||||
static u_char basis[] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
len = src->len;
|
||||
s = src->data;
|
||||
d = dst->data;
|
||||
|
||||
while (len > 2) {
|
||||
*d++ = basis[(s[0] >> 2) & 0x3f];
|
||||
*d++ = basis[((s[0] & 3) << 4) | (s[1] >> 4)];
|
||||
*d++ = basis[((s[1] & 0x0f) << 2) | (s[2] >> 6)];
|
||||
*d++ = basis[s[2] & 0x3f];
|
||||
|
||||
s += 3;
|
||||
len -= 3;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
*d++ = basis[(s[0] >> 2) & 0x3f];
|
||||
|
||||
if (len == 1) {
|
||||
*d++ = basis[(s[0] & 3) << 4];
|
||||
if (!no_padding) {
|
||||
*d++ = '=';
|
||||
}
|
||||
|
||||
} else {
|
||||
*d++ = basis[((s[0] & 3) << 4) | (s[1] >> 4)];
|
||||
*d++ = basis[(s[1] & 0x0f) << 2];
|
||||
}
|
||||
|
||||
if (!no_padding) {
|
||||
*d++ = '=';
|
||||
}
|
||||
}
|
||||
|
||||
dst->len = d - dst->data;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_stream_lua_ngx_encode_args(lua_State *L)
|
||||
{
|
||||
ngx_str_t args;
|
||||
|
||||
if (lua_gettop(L) != 1) {
|
||||
return luaL_error(L, "expecting 1 argument but seen %d",
|
||||
lua_gettop(L));
|
||||
}
|
||||
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
ngx_stream_lua_process_args_option(NULL, L, 1, &args);
|
||||
lua_pushlstring(L, (char *) args.data, args.len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_stream_lua_ngx_decode_args(lua_State *L)
|
||||
{
|
||||
u_char *buf;
|
||||
u_char *tmp;
|
||||
size_t len = 0;
|
||||
int n;
|
||||
int max;
|
||||
|
||||
n = lua_gettop(L);
|
||||
|
||||
if (n != 1 && n != 2) {
|
||||
return luaL_error(L, "expecting 1 or 2 arguments but seen %d", n);
|
||||
}
|
||||
|
||||
buf = (u_char *) luaL_checklstring(L, 1, &len);
|
||||
|
||||
if (n == 2) {
|
||||
max = luaL_checkint(L, 2);
|
||||
lua_pop(L, 1);
|
||||
|
||||
} else {
|
||||
max = NGX_STREAM_LUA_MAX_ARGS;
|
||||
}
|
||||
|
||||
tmp = lua_newuserdata(L, len);
|
||||
ngx_memcpy(tmp, buf, len);
|
||||
|
||||
lua_createtable(L, 0, 4);
|
||||
|
||||
return ngx_stream_lua_parse_args(L, tmp, tmp + len, max);
|
||||
}
|
||||
|
||||
|
||||
#if (NGX_OPENSSL)
|
||||
static int
|
||||
ngx_stream_lua_ngx_hmac_sha1(lua_State *L)
|
||||
{
|
||||
u_char *sec, *sts;
|
||||
size_t lsec, lsts;
|
||||
unsigned int md_len;
|
||||
unsigned char md[EVP_MAX_MD_SIZE];
|
||||
const EVP_MD *evp_md;
|
||||
|
||||
if (lua_gettop(L) != 2) {
|
||||
return luaL_error(L, "expecting 2 arguments, but got %d",
|
||||
lua_gettop(L));
|
||||
}
|
||||
|
||||
sec = (u_char *) luaL_checklstring(L, 1, &lsec);
|
||||
sts = (u_char *) luaL_checklstring(L, 2, &lsts);
|
||||
|
||||
evp_md = EVP_sha1();
|
||||
|
||||
HMAC(evp_md, sec, lsec, sts, lsts, md, &md_len);
|
||||
|
||||
lua_pushlstring(L, (char *) md, md_len);
|
||||
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_ffi_md5_bin(const u_char *src, size_t len, u_char *dst)
|
||||
{
|
||||
ngx_md5_t md5;
|
||||
|
||||
ngx_md5_init(&md5);
|
||||
ngx_md5_update(&md5, src, len);
|
||||
ngx_md5_final(dst, &md5);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_ffi_md5(const u_char *src, size_t len, u_char *dst)
|
||||
{
|
||||
ngx_md5_t md5;
|
||||
u_char md5_buf[MD5_DIGEST_LENGTH];
|
||||
|
||||
ngx_md5_init(&md5);
|
||||
ngx_md5_update(&md5, src, len);
|
||||
ngx_md5_final(md5_buf, &md5);
|
||||
|
||||
ngx_hex_dump(dst, md5_buf, sizeof(md5_buf));
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_stream_lua_ffi_sha1_bin(const u_char *src, size_t len, u_char *dst)
|
||||
{
|
||||
#if (NGX_HAVE_SHA1)
|
||||
ngx_sha1_t sha;
|
||||
|
||||
ngx_sha1_init(&sha);
|
||||
ngx_sha1_update(&sha, src, len);
|
||||
ngx_sha1_final(dst, &sha);
|
||||
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
unsigned int
|
||||
ngx_stream_lua_ffi_crc32_short(const u_char *src, size_t len)
|
||||
{
|
||||
return ngx_crc32_short((u_char *) src, len);
|
||||
}
|
||||
|
||||
|
||||
unsigned int
|
||||
ngx_stream_lua_ffi_crc32_long(const u_char *src, size_t len)
|
||||
{
|
||||
return ngx_crc32_long((u_char *) src, len);
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
ngx_stream_lua_ffi_encode_base64(const u_char *src, size_t slen, u_char *dst,
|
||||
int no_padding)
|
||||
{
|
||||
ngx_str_t in, out;
|
||||
|
||||
in.data = (u_char *) src;
|
||||
in.len = slen;
|
||||
|
||||
out.data = dst;
|
||||
|
||||
ngx_stream_lua_encode_base64(&out, &in, no_padding);
|
||||
|
||||
return out.len;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_stream_lua_ffi_decode_base64(const u_char *src, size_t slen, u_char *dst,
|
||||
size_t *dlen)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
ngx_str_t in, out;
|
||||
|
||||
in.data = (u_char *) src;
|
||||
in.len = slen;
|
||||
|
||||
out.data = dst;
|
||||
|
||||
rc = ngx_decode_base64(&out, &in);
|
||||
|
||||
*dlen = out.len;
|
||||
|
||||
return rc == NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
ngx_stream_lua_ffi_unescape_uri(const u_char *src, size_t len, u_char *dst)
|
||||
{
|
||||
u_char *p = dst;
|
||||
|
||||
ngx_stream_lua_unescape_uri(&p, (u_char **) &src, len,
|
||||
NGX_UNESCAPE_URI_COMPONENT);
|
||||
return p - dst;
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
ngx_stream_lua_ffi_uri_escaped_length(const u_char *src, size_t len,
|
||||
int type)
|
||||
{
|
||||
return len + 2 * ngx_stream_lua_escape_uri(NULL, (u_char *) src, len,
|
||||
type);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_ffi_escape_uri(const u_char *src, size_t len, u_char *dst,
|
||||
int type)
|
||||
{
|
||||
ngx_stream_lua_escape_uri(dst, (u_char *) src, len,
|
||||
type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_string.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_STRING_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_STRING_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
void ngx_stream_lua_inject_string_api(lua_State *L);
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_STRING_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,104 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_time.c.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
double
|
||||
ngx_stream_lua_ffi_now(void)
|
||||
{
|
||||
ngx_time_t *tp;
|
||||
|
||||
tp = ngx_timeofday();
|
||||
|
||||
return tp->sec + tp->msec / 1000.0;
|
||||
}
|
||||
|
||||
|
||||
double
|
||||
ngx_stream_lua_ffi_req_start_time(ngx_stream_lua_request_t *r)
|
||||
{
|
||||
return r->session->start_sec + r->session->start_msec / 1000.0;
|
||||
}
|
||||
|
||||
|
||||
long
|
||||
ngx_stream_lua_ffi_time(void)
|
||||
{
|
||||
return (long) ngx_time();
|
||||
}
|
||||
|
||||
|
||||
long
|
||||
ngx_stream_lua_ffi_monotonic_msec(void)
|
||||
{
|
||||
return (long) ngx_current_msec;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_ffi_update_time(void)
|
||||
{
|
||||
ngx_time_update();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_ffi_today(u_char *buf)
|
||||
{
|
||||
ngx_tm_t tm;
|
||||
|
||||
ngx_gmtime(ngx_time() + ngx_cached_time->gmtoff * 60, &tm);
|
||||
|
||||
ngx_sprintf(buf, "%04d-%02d-%02d", tm.ngx_tm_year, tm.ngx_tm_mon,
|
||||
tm.ngx_tm_mday);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_ffi_localtime(u_char *buf)
|
||||
{
|
||||
ngx_tm_t tm;
|
||||
|
||||
ngx_gmtime(ngx_time() + ngx_cached_time->gmtoff * 60, &tm);
|
||||
|
||||
ngx_sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d", tm.ngx_tm_year,
|
||||
tm.ngx_tm_mon, tm.ngx_tm_mday, tm.ngx_tm_hour, tm.ngx_tm_min,
|
||||
tm.ngx_tm_sec);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_ffi_utctime(u_char *buf)
|
||||
{
|
||||
ngx_tm_t tm;
|
||||
|
||||
ngx_gmtime(ngx_time(), &tm);
|
||||
|
||||
ngx_sprintf(buf, "%04d-%02d-%02d %02d:%02d:%02d", tm.ngx_tm_year,
|
||||
tm.ngx_tm_mon, tm.ngx_tm_mday, tm.ngx_tm_hour, tm.ngx_tm_min,
|
||||
tm.ngx_tm_sec);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,966 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_timer.c.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_stream_lua_timer.h"
|
||||
#include "ngx_stream_lua_util.h"
|
||||
#include "ngx_stream_lua_contentby.h"
|
||||
#include "ngx_stream_lua_probe.h"
|
||||
|
||||
|
||||
#define NGX_STREAM_LUA_TIMER_ERRBUF_SIZE 128
|
||||
|
||||
|
||||
typedef struct {
|
||||
void **main_conf;
|
||||
void **srv_conf;
|
||||
|
||||
|
||||
lua_State *co;
|
||||
|
||||
ngx_pool_t *pool;
|
||||
|
||||
ngx_listening_t *listening;
|
||||
ngx_str_t client_addr_text;
|
||||
|
||||
ngx_stream_lua_main_conf_t *lmcf;
|
||||
ngx_stream_lua_vm_state_t *vm_state;
|
||||
|
||||
int co_ref;
|
||||
unsigned delay:31;
|
||||
unsigned premature:1;
|
||||
} ngx_stream_lua_timer_ctx_t;
|
||||
|
||||
|
||||
static int ngx_stream_lua_ngx_timer_at(lua_State *L);
|
||||
static int ngx_stream_lua_ngx_timer_every(lua_State *L);
|
||||
static int ngx_stream_lua_ngx_timer_helper(lua_State *L, int every);
|
||||
static int ngx_stream_lua_ngx_timer_running_count(lua_State *L);
|
||||
static int ngx_stream_lua_ngx_timer_pending_count(lua_State *L);
|
||||
static ngx_int_t ngx_stream_lua_timer_copy(
|
||||
ngx_stream_lua_timer_ctx_t *old_tctx);
|
||||
static void ngx_stream_lua_timer_handler(ngx_event_t *ev);
|
||||
static u_char *ngx_stream_lua_log_timer_error(ngx_log_t *log, u_char *buf,
|
||||
size_t len);
|
||||
static void ngx_stream_lua_abort_pending_timers(ngx_event_t *ev);
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_inject_timer_api(lua_State *L)
|
||||
{
|
||||
lua_createtable(L, 0 /* narr */, 4 /* nrec */); /* ngx.timer. */
|
||||
|
||||
lua_pushcfunction(L, ngx_stream_lua_ngx_timer_at);
|
||||
lua_setfield(L, -2, "at");
|
||||
|
||||
lua_pushcfunction(L, ngx_stream_lua_ngx_timer_every);
|
||||
lua_setfield(L, -2, "every");
|
||||
|
||||
lua_pushcfunction(L, ngx_stream_lua_ngx_timer_running_count);
|
||||
lua_setfield(L, -2, "running_count");
|
||||
|
||||
lua_pushcfunction(L, ngx_stream_lua_ngx_timer_pending_count);
|
||||
lua_setfield(L, -2, "pending_count");
|
||||
|
||||
lua_setfield(L, -2, "timer");
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_stream_lua_ngx_timer_running_count(lua_State *L)
|
||||
{
|
||||
ngx_stream_lua_request_t *r;
|
||||
ngx_stream_lua_main_conf_t *lmcf;
|
||||
|
||||
r = ngx_stream_lua_get_req(L);
|
||||
if (r == NULL) {
|
||||
return luaL_error(L, "no request");
|
||||
}
|
||||
|
||||
lmcf = ngx_stream_lua_get_module_main_conf(r, ngx_stream_lua_module);
|
||||
|
||||
lua_pushnumber(L, lmcf->running_timers);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_stream_lua_ngx_timer_pending_count(lua_State *L)
|
||||
{
|
||||
ngx_stream_lua_request_t *r;
|
||||
ngx_stream_lua_main_conf_t *lmcf;
|
||||
|
||||
r = ngx_stream_lua_get_req(L);
|
||||
if (r == NULL) {
|
||||
return luaL_error(L, "no request");
|
||||
}
|
||||
|
||||
lmcf = ngx_stream_lua_get_module_main_conf(r, ngx_stream_lua_module);
|
||||
|
||||
lua_pushnumber(L, lmcf->pending_timers);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_stream_lua_ngx_timer_at(lua_State *L)
|
||||
{
|
||||
return ngx_stream_lua_ngx_timer_helper(L, 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* TODO: return a timer handler instead which can be passed to
|
||||
* the ngx.timer.cancel method to cancel the timer.
|
||||
*/
|
||||
static int
|
||||
ngx_stream_lua_ngx_timer_every(lua_State *L)
|
||||
{
|
||||
return ngx_stream_lua_ngx_timer_helper(L, 1);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_stream_lua_ngx_timer_helper(lua_State *L, int every)
|
||||
{
|
||||
int nargs, co_ref;
|
||||
u_char *p;
|
||||
lua_State *vm; /* the main thread */
|
||||
lua_State *co;
|
||||
ngx_msec_t delay;
|
||||
ngx_event_t *ev = NULL;
|
||||
ngx_stream_lua_request_t *r;
|
||||
ngx_connection_t *saved_c = NULL;
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
#if 0
|
||||
ngx_http_connection_t *hc;
|
||||
#endif
|
||||
|
||||
ngx_stream_lua_timer_ctx_t *tctx = NULL;
|
||||
ngx_stream_lua_main_conf_t *lmcf;
|
||||
#if 0
|
||||
ngx_http_core_main_conf_t *cmcf;
|
||||
#endif
|
||||
|
||||
nargs = lua_gettop(L);
|
||||
if (nargs < 2) {
|
||||
return luaL_error(L, "expecting at least 2 arguments but got %d",
|
||||
nargs);
|
||||
}
|
||||
|
||||
delay = (ngx_msec_t) (luaL_checknumber(L, 1) * 1000);
|
||||
|
||||
if (every && delay == 0) {
|
||||
return luaL_error(L, "delay cannot be zero");
|
||||
}
|
||||
|
||||
luaL_argcheck(L, lua_isfunction(L, 2) && !lua_iscfunction(L, 2), 2,
|
||||
"Lua function expected");
|
||||
|
||||
r = ngx_stream_lua_get_req(L);
|
||||
if (r == NULL) {
|
||||
return luaL_error(L, "no request");
|
||||
}
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
|
||||
if (ngx_exiting && delay > 0) {
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "process exiting");
|
||||
return 2;
|
||||
}
|
||||
|
||||
lmcf = ngx_stream_lua_get_module_main_conf(r, ngx_stream_lua_module);
|
||||
|
||||
if (lmcf->pending_timers >= lmcf->max_pending_timers) {
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "too many pending timers");
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (lmcf->watcher == NULL) {
|
||||
/* create the watcher fake connection */
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ngx_cycle->log, 0,
|
||||
"lua creating fake watcher connection");
|
||||
|
||||
if (ngx_cycle->files) {
|
||||
saved_c = ngx_cycle->files[0];
|
||||
}
|
||||
|
||||
lmcf->watcher = ngx_get_connection(0, ngx_cycle->log);
|
||||
|
||||
if (ngx_cycle->files) {
|
||||
ngx_cycle->files[0] = saved_c;
|
||||
}
|
||||
|
||||
if (lmcf->watcher == NULL) {
|
||||
return luaL_error(L, "no memory");
|
||||
}
|
||||
|
||||
/* to work around the -1 check in ngx_worker_process_cycle: */
|
||||
lmcf->watcher->fd = (ngx_socket_t) -2;
|
||||
|
||||
lmcf->watcher->idle = 1;
|
||||
lmcf->watcher->read->handler = ngx_stream_lua_abort_pending_timers;
|
||||
lmcf->watcher->data = lmcf;
|
||||
}
|
||||
|
||||
vm = ngx_stream_lua_get_lua_vm(r, ctx);
|
||||
|
||||
co = lua_newthread(vm);
|
||||
|
||||
/* L stack: time func [args] */
|
||||
|
||||
ngx_stream_lua_probe_user_coroutine_create(r, L, co);
|
||||
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
lua_createtable(co, 0, 0); /* the new globals table */
|
||||
|
||||
/* co stack: global_tb */
|
||||
|
||||
lua_createtable(co, 0, 1); /* the metatable */
|
||||
ngx_stream_lua_get_globals_table(co);
|
||||
lua_setfield(co, -2, "__index");
|
||||
lua_setmetatable(co, -2);
|
||||
|
||||
/* co stack: global_tb */
|
||||
|
||||
ngx_stream_lua_set_globals_table(co);
|
||||
#endif
|
||||
|
||||
/* co stack: <empty> */
|
||||
|
||||
dd("stack top: %d", lua_gettop(L));
|
||||
|
||||
lua_xmove(vm, L, 1); /* move coroutine from main thread to L */
|
||||
|
||||
/* L stack: time func [args] thread */
|
||||
/* vm stack: empty */
|
||||
|
||||
lua_pushvalue(L, 2); /* copy entry function to top of L*/
|
||||
|
||||
/* L stack: time func [args] thread func */
|
||||
|
||||
lua_xmove(L, co, 1); /* move entry function from L to co */
|
||||
|
||||
/* L stack: time func [args] thread */
|
||||
/* co stack: func */
|
||||
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
ngx_stream_lua_get_globals_table(co);
|
||||
lua_setfenv(co, -2);
|
||||
#endif
|
||||
|
||||
/* co stack: func */
|
||||
|
||||
lua_pushlightuserdata(L, ngx_stream_lua_lightudata_mask(
|
||||
coroutines_key));
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
|
||||
/* L stack: time func [args] thread coroutines */
|
||||
|
||||
lua_pushvalue(L, -2);
|
||||
|
||||
/* L stack: time func [args] thread coroutines thread */
|
||||
|
||||
co_ref = luaL_ref(L, -2);
|
||||
lua_pop(L, 1);
|
||||
|
||||
/* L stack: time func [args] thread */
|
||||
|
||||
if (nargs > 2) {
|
||||
lua_pop(L, 1); /* L stack: time func [args] */
|
||||
lua_xmove(L, co, nargs - 2); /* L stack: time func */
|
||||
|
||||
/* co stack: func [args] */
|
||||
}
|
||||
|
||||
p = ngx_alloc(sizeof(ngx_event_t) + sizeof(ngx_stream_lua_timer_ctx_t),
|
||||
r->connection->log);
|
||||
if (p == NULL) {
|
||||
goto nomem;
|
||||
}
|
||||
|
||||
ev = (ngx_event_t *) p;
|
||||
|
||||
ngx_memzero(ev, sizeof(ngx_event_t));
|
||||
|
||||
p += sizeof(ngx_event_t);
|
||||
|
||||
tctx = (ngx_stream_lua_timer_ctx_t *) p;
|
||||
|
||||
tctx->delay = every ? delay : 0;
|
||||
|
||||
tctx->premature = 0;
|
||||
tctx->co_ref = co_ref;
|
||||
tctx->co = co;
|
||||
|
||||
|
||||
tctx->main_conf = r->session->main_conf;
|
||||
tctx->srv_conf = r->session->srv_conf;
|
||||
|
||||
tctx->lmcf = lmcf;
|
||||
|
||||
tctx->pool = ngx_create_pool(128, ngx_cycle->log);
|
||||
if (tctx->pool == NULL) {
|
||||
goto nomem;
|
||||
}
|
||||
|
||||
if (r->connection) {
|
||||
tctx->listening = r->connection->listening;
|
||||
|
||||
} else {
|
||||
tctx->listening = NULL;
|
||||
}
|
||||
|
||||
if (r->connection->addr_text.len) {
|
||||
tctx->client_addr_text.data = ngx_palloc(tctx->pool,
|
||||
r->connection->addr_text.len);
|
||||
if (tctx->client_addr_text.data == NULL) {
|
||||
goto nomem;
|
||||
}
|
||||
|
||||
ngx_memcpy(tctx->client_addr_text.data, r->connection->addr_text.data,
|
||||
r->connection->addr_text.len);
|
||||
tctx->client_addr_text.len = r->connection->addr_text.len;
|
||||
|
||||
} else {
|
||||
tctx->client_addr_text.len = 0;
|
||||
tctx->client_addr_text.data = NULL;
|
||||
}
|
||||
|
||||
if (ctx && ctx->vm_state) {
|
||||
tctx->vm_state = ctx->vm_state;
|
||||
tctx->vm_state->count++;
|
||||
|
||||
} else {
|
||||
tctx->vm_state = NULL;
|
||||
}
|
||||
|
||||
ev->handler = ngx_stream_lua_timer_handler;
|
||||
ev->data = tctx;
|
||||
ev->log = ngx_cycle->log;
|
||||
|
||||
lmcf->pending_timers++;
|
||||
|
||||
ngx_add_timer(ev, delay);
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_STREAM, ngx_cycle->log, 0,
|
||||
"stream created timer (co: %p delay: %M ms)",
|
||||
tctx->co, delay);
|
||||
|
||||
lua_pushinteger(L, 1);
|
||||
return 1;
|
||||
|
||||
nomem:
|
||||
|
||||
if (tctx && tctx->pool) {
|
||||
ngx_destroy_pool(tctx->pool);
|
||||
}
|
||||
|
||||
if (ev) {
|
||||
ngx_free(ev);
|
||||
}
|
||||
|
||||
lua_pushlightuserdata(L, ngx_stream_lua_lightudata_mask(
|
||||
coroutines_key));
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
luaL_unref(L, -1, co_ref);
|
||||
|
||||
return luaL_error(L, "no memory");
|
||||
}
|
||||
|
||||
|
||||
static ngx_int_t
|
||||
ngx_stream_lua_timer_copy(ngx_stream_lua_timer_ctx_t *old_tctx)
|
||||
{
|
||||
int nargs, co_ref, i;
|
||||
u_char *p;
|
||||
lua_State *vm; /* the main thread */
|
||||
lua_State *co;
|
||||
lua_State *L;
|
||||
ngx_event_t *ev = NULL;
|
||||
|
||||
ngx_stream_lua_timer_ctx_t *tctx = NULL;
|
||||
ngx_stream_lua_main_conf_t *lmcf;
|
||||
|
||||
/* L stack: func [args] */
|
||||
L = old_tctx->co;
|
||||
|
||||
lmcf = old_tctx->lmcf;
|
||||
|
||||
vm = old_tctx->vm_state ? old_tctx->vm_state->vm : lmcf->lua;
|
||||
|
||||
co = lua_newthread(vm);
|
||||
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
lua_createtable(co, 0, 0); /* the new globals table */
|
||||
|
||||
/* co stack: global_tb */
|
||||
|
||||
lua_createtable(co, 0, 1); /* the metatable */
|
||||
ngx_stream_lua_get_globals_table(co);
|
||||
lua_setfield(co, -2, "__index");
|
||||
lua_setmetatable(co, -2);
|
||||
|
||||
/* co stack: global_tb */
|
||||
|
||||
ngx_stream_lua_set_globals_table(co);
|
||||
#endif
|
||||
|
||||
/* co stack: <empty> */
|
||||
|
||||
dd("stack top: %d", lua_gettop(L));
|
||||
|
||||
lua_xmove(vm, L, 1); /* move coroutine from main thread to L */
|
||||
|
||||
/* L stack: func [args] thread */
|
||||
/* vm stack: empty */
|
||||
|
||||
lua_pushvalue(L, 1); /* copy entry function to top of L*/
|
||||
|
||||
/* L stack: func [args] thread func */
|
||||
|
||||
lua_xmove(L, co, 1); /* move entry function from L to co */
|
||||
|
||||
/* L stack: func [args] thread */
|
||||
/* co stack: func */
|
||||
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
ngx_stream_lua_get_globals_table(co);
|
||||
lua_setfenv(co, -2);
|
||||
#endif
|
||||
|
||||
/* co stack: func */
|
||||
|
||||
lua_pushlightuserdata(L, ngx_stream_lua_lightudata_mask(
|
||||
coroutines_key));
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
|
||||
/* L stack: func [args] thread coroutines */
|
||||
|
||||
lua_pushvalue(L, -2);
|
||||
|
||||
/* L stack: func [args] thread coroutines thread */
|
||||
|
||||
co_ref = luaL_ref(L, -2);
|
||||
lua_pop(L, 2);
|
||||
|
||||
/* L stack: func [args] */
|
||||
|
||||
nargs = lua_gettop(L);
|
||||
if (nargs > 1) {
|
||||
for (i = 2; i <= nargs; i++) {
|
||||
lua_pushvalue(L, i);
|
||||
}
|
||||
|
||||
/* L stack: func [args] [args] */
|
||||
|
||||
lua_xmove(L, co, nargs - 1);
|
||||
|
||||
/* L stack: func [args] */
|
||||
/* co stack: func [args] */
|
||||
}
|
||||
|
||||
p = ngx_alloc(sizeof(ngx_event_t) + sizeof(ngx_stream_lua_timer_ctx_t),
|
||||
ngx_cycle->log);
|
||||
if (p == NULL) {
|
||||
goto nomem;
|
||||
}
|
||||
|
||||
ev = (ngx_event_t *) p;
|
||||
|
||||
ngx_memzero(ev, sizeof(ngx_event_t));
|
||||
|
||||
p += sizeof(ngx_event_t);
|
||||
|
||||
tctx = (ngx_stream_lua_timer_ctx_t *) p;
|
||||
|
||||
ngx_memcpy(tctx, old_tctx, sizeof(ngx_stream_lua_timer_ctx_t));
|
||||
|
||||
tctx->co_ref = co_ref;
|
||||
tctx->co = co;
|
||||
|
||||
tctx->pool = ngx_create_pool(128, ngx_cycle->log);
|
||||
if (tctx->pool == NULL) {
|
||||
goto nomem;
|
||||
}
|
||||
|
||||
if (tctx->client_addr_text.len) {
|
||||
tctx->client_addr_text.data = ngx_palloc(tctx->pool,
|
||||
tctx->client_addr_text.len);
|
||||
if (tctx->client_addr_text.data == NULL) {
|
||||
goto nomem;
|
||||
}
|
||||
|
||||
ngx_memcpy(tctx->client_addr_text.data, old_tctx->client_addr_text.data,
|
||||
tctx->client_addr_text.len);
|
||||
}
|
||||
|
||||
if (tctx->vm_state) {
|
||||
tctx->vm_state->count++;
|
||||
}
|
||||
|
||||
ev->handler = ngx_stream_lua_timer_handler;
|
||||
ev->data = tctx;
|
||||
ev->log = ngx_cycle->log;
|
||||
|
||||
lmcf->pending_timers++;
|
||||
|
||||
ngx_add_timer(ev, tctx->delay);
|
||||
|
||||
ngx_log_debug2(NGX_LOG_DEBUG_STREAM, ngx_cycle->log, 0,
|
||||
"stream created next timer (co: %p delay: %M ms)",
|
||||
tctx->co, tctx->delay);
|
||||
|
||||
return NGX_OK;
|
||||
|
||||
nomem:
|
||||
|
||||
if (tctx && tctx->pool) {
|
||||
ngx_destroy_pool(tctx->pool);
|
||||
}
|
||||
|
||||
if (ev) {
|
||||
ngx_free(ev);
|
||||
}
|
||||
|
||||
/* L stack: func [args] */
|
||||
|
||||
lua_pushlightuserdata(L, ngx_stream_lua_lightudata_mask(
|
||||
coroutines_key));
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
luaL_unref(L, -1, co_ref);
|
||||
|
||||
/* L stack: func [args] coroutines */
|
||||
|
||||
lua_pop(L, 1);
|
||||
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_stream_lua_timer_handler(ngx_event_t *ev)
|
||||
{
|
||||
int n;
|
||||
lua_State *L;
|
||||
ngx_int_t rc;
|
||||
ngx_connection_t *c = NULL;
|
||||
ngx_pool_cleanup_t *pcln;
|
||||
|
||||
ngx_stream_lua_request_t *r = NULL;
|
||||
ngx_stream_lua_cleanup_t *cln;
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
ngx_stream_lua_timer_ctx_t tctx;
|
||||
ngx_stream_lua_main_conf_t *lmcf;
|
||||
|
||||
ngx_stream_core_srv_conf_t *clcf;
|
||||
ngx_stream_session_t *s;
|
||||
|
||||
lua_Debug ar;
|
||||
u_char *p;
|
||||
u_char errbuf[NGX_STREAM_LUA_TIMER_ERRBUF_SIZE];
|
||||
const char *source;
|
||||
const char *errmsg;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ngx_cycle->log, 0,
|
||||
"stream lua ngx.timer expired");
|
||||
|
||||
ngx_memcpy(&tctx, ev->data, sizeof(ngx_stream_lua_timer_ctx_t));
|
||||
ngx_free(ev);
|
||||
|
||||
ngx_stream_lua_assert(tctx.co_ref && tctx.co);
|
||||
|
||||
lmcf = tctx.lmcf;
|
||||
|
||||
lmcf->pending_timers--;
|
||||
|
||||
if (!ngx_exiting && tctx.delay > 0) {
|
||||
rc = ngx_stream_lua_timer_copy(&tctx);
|
||||
if (rc != NGX_OK) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
|
||||
"failed to create the next timer of delay %ud ms",
|
||||
(unsigned) tctx.delay);
|
||||
}
|
||||
}
|
||||
|
||||
if (lmcf->running_timers >= lmcf->max_running_timers) {
|
||||
p = ngx_snprintf(errbuf, NGX_STREAM_LUA_TIMER_ERRBUF_SIZE - 1,
|
||||
"stream lua: %i lua_max_running_timers are not enough",
|
||||
lmcf->max_running_timers);
|
||||
*p = '\0';
|
||||
errmsg = (const char *) errbuf;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
c = ngx_stream_lua_create_fake_connection(tctx.pool);
|
||||
if (c == NULL) {
|
||||
errmsg = "could not create fake connection";
|
||||
goto failed;
|
||||
}
|
||||
|
||||
c->log->handler = ngx_stream_lua_log_timer_error;
|
||||
c->log->data = c;
|
||||
|
||||
c->listening = tctx.listening;
|
||||
c->addr_text = tctx.client_addr_text;
|
||||
|
||||
s = ngx_stream_lua_create_fake_session(c);
|
||||
if (s == NULL) {
|
||||
errmsg = "could not create fake session";
|
||||
goto failed;
|
||||
}
|
||||
|
||||
|
||||
s->main_conf = tctx.main_conf;
|
||||
s->srv_conf = tctx.srv_conf;
|
||||
|
||||
clcf = ngx_stream_get_module_srv_conf(s, ngx_stream_core_module);
|
||||
|
||||
#if defined(nginx_version) && nginx_version >= 1009000
|
||||
ngx_set_connection_log(s->connection, clcf->error_log);
|
||||
|
||||
#else
|
||||
#endif
|
||||
|
||||
dd("lmcf: %p", lmcf);
|
||||
|
||||
ctx = ngx_stream_lua_create_ctx(s);
|
||||
if (ctx == NULL) {
|
||||
errmsg = "could not create ctx";
|
||||
goto failed;
|
||||
}
|
||||
|
||||
r = ctx->request;
|
||||
|
||||
if (tctx.vm_state) {
|
||||
ctx->vm_state = tctx.vm_state;
|
||||
|
||||
pcln = ngx_pool_cleanup_add(r->pool, 0);
|
||||
if (pcln == NULL) {
|
||||
errmsg = "could not add vm cleanup";
|
||||
goto failed;
|
||||
}
|
||||
|
||||
pcln->handler = ngx_stream_lua_cleanup_vm;
|
||||
pcln->data = tctx.vm_state;
|
||||
}
|
||||
|
||||
ctx->cur_co_ctx = &ctx->entry_co_ctx;
|
||||
|
||||
L = ngx_stream_lua_get_lua_vm(r, ctx);
|
||||
|
||||
cln = ngx_stream_lua_cleanup_add(r, 0);
|
||||
if (cln == NULL) {
|
||||
errmsg = "could not add request cleanup";
|
||||
goto failed;
|
||||
}
|
||||
|
||||
cln->handler = ngx_stream_lua_request_cleanup_handler;
|
||||
cln->data = ctx;
|
||||
ctx->cleanup = &cln->handler;
|
||||
|
||||
ctx->entered_content_phase = 1;
|
||||
ctx->context = NGX_STREAM_LUA_CONTEXT_TIMER;
|
||||
|
||||
r->read_event_handler = ngx_stream_lua_block_reading;
|
||||
|
||||
ctx->cur_co_ctx->co_ref = tctx.co_ref;
|
||||
ctx->cur_co_ctx->co = tctx.co;
|
||||
ctx->cur_co_ctx->co_status = NGX_STREAM_LUA_CO_RUNNING;
|
||||
|
||||
dd("r connection: %p, log %p", r->connection, r->connection->log);
|
||||
|
||||
/* save the request in coroutine globals table */
|
||||
ngx_stream_lua_set_req(tctx.co, r);
|
||||
|
||||
lmcf->running_timers++;
|
||||
|
||||
lua_pushboolean(tctx.co, tctx.premature);
|
||||
|
||||
n = lua_gettop(tctx.co);
|
||||
if (n > 2) {
|
||||
lua_insert(tctx.co, 2);
|
||||
}
|
||||
|
||||
#ifdef NGX_LUA_USE_ASSERT
|
||||
ctx->cur_co_ctx->co_top = 1;
|
||||
#endif
|
||||
|
||||
rc = ngx_stream_lua_run_thread(L, r, ctx, n - 1);
|
||||
|
||||
dd("timer lua run thread: %d", (int) rc);
|
||||
|
||||
if (rc == NGX_ERROR || rc >= NGX_OK) {
|
||||
/* do nothing */
|
||||
|
||||
} else if (rc == NGX_AGAIN) {
|
||||
rc = ngx_stream_lua_content_run_posted_threads(L, r, ctx, 0);
|
||||
|
||||
} else if (rc == NGX_DONE) {
|
||||
rc = ngx_stream_lua_content_run_posted_threads(L, r, ctx, 1);
|
||||
|
||||
} else {
|
||||
rc = NGX_OK;
|
||||
}
|
||||
|
||||
ngx_stream_lua_finalize_request(r, rc);
|
||||
return;
|
||||
|
||||
failed:
|
||||
|
||||
/* co stack: func [args] */
|
||||
lua_pushvalue(tctx.co, 1);
|
||||
/* co stack: func [args] func */
|
||||
lua_getinfo(tctx.co, ">Sf", &ar);
|
||||
|
||||
source = ar.source;
|
||||
|
||||
if (source == NULL) {
|
||||
source = "(unknown)";
|
||||
}
|
||||
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
|
||||
"stream lua failed to run timer with function "
|
||||
"defined at %s:%d: %s",
|
||||
source, ar.linedefined, errmsg);
|
||||
|
||||
lua_pushlightuserdata(tctx.co, ngx_stream_lua_lightudata_mask(
|
||||
coroutines_key));
|
||||
lua_rawget(tctx.co, LUA_REGISTRYINDEX);
|
||||
luaL_unref(tctx.co, -1, tctx.co_ref);
|
||||
lua_settop(tctx.co, 0);
|
||||
|
||||
if (tctx.vm_state) {
|
||||
ngx_stream_lua_cleanup_vm(tctx.vm_state);
|
||||
}
|
||||
|
||||
if (c) {
|
||||
ngx_stream_lua_close_fake_connection(c);
|
||||
|
||||
} else if (tctx.pool) {
|
||||
ngx_destroy_pool(tctx.pool);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static u_char *
|
||||
ngx_stream_lua_log_timer_error(ngx_log_t *log, u_char *buf, size_t len)
|
||||
{
|
||||
u_char *p;
|
||||
ngx_connection_t *c;
|
||||
|
||||
if (log->action) {
|
||||
p = ngx_snprintf(buf, len, " while %s", log->action);
|
||||
len -= p - buf;
|
||||
buf = p;
|
||||
}
|
||||
|
||||
c = log->data;
|
||||
|
||||
dd("ctx = %p", c);
|
||||
|
||||
p = ngx_snprintf(buf, len, ", context: ngx.timer");
|
||||
len -= p - buf;
|
||||
buf = p;
|
||||
|
||||
if (c != NULL) {
|
||||
if (c->addr_text.len) {
|
||||
p = ngx_snprintf(buf, len, ", client: %V", &c->addr_text);
|
||||
len -= p - buf;
|
||||
buf = p;
|
||||
}
|
||||
|
||||
if (c->listening && c->listening->addr_text.len) {
|
||||
p = ngx_snprintf(buf, len, ", server: %V",
|
||||
&c->listening->addr_text);
|
||||
/* len -= p - buf; */
|
||||
buf = p;
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ngx_stream_lua_abort_pending_timers(ngx_event_t *ev)
|
||||
{
|
||||
ngx_int_t i, n;
|
||||
ngx_event_t **events;
|
||||
ngx_connection_t *c, *saved_c = NULL;
|
||||
ngx_rbtree_node_t *cur, *prev, *next, *sentinel, *temp;
|
||||
|
||||
ngx_stream_lua_timer_ctx_t *tctx;
|
||||
ngx_stream_lua_main_conf_t *lmcf;
|
||||
|
||||
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ngx_cycle->log, 0,
|
||||
"lua abort pending timers");
|
||||
|
||||
c = ev->data;
|
||||
lmcf = c->data;
|
||||
|
||||
dd("lua connection fd: %d", (int) c->fd);
|
||||
|
||||
if (!c->close) {
|
||||
return;
|
||||
}
|
||||
|
||||
c->read->closed = 1;
|
||||
c->write->closed = 1;
|
||||
|
||||
/* we temporarily use a valid fd (0) to make ngx_free_connection happy */
|
||||
|
||||
c->fd = 0;
|
||||
|
||||
if (ngx_cycle->files) {
|
||||
saved_c = ngx_cycle->files[0];
|
||||
}
|
||||
|
||||
ngx_free_connection(c);
|
||||
|
||||
c->fd = (ngx_socket_t) -1;
|
||||
|
||||
if (ngx_cycle->files) {
|
||||
ngx_cycle->files[0] = saved_c;
|
||||
}
|
||||
|
||||
if (lmcf->pending_timers == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* expire pending timers immediately */
|
||||
|
||||
sentinel = ngx_event_timer_rbtree.sentinel;
|
||||
|
||||
cur = ngx_event_timer_rbtree.root;
|
||||
|
||||
/* XXX nginx does not guarantee the parent of root is meaningful,
|
||||
* so we temporarily override it to simplify tree traversal. */
|
||||
temp = cur->parent;
|
||||
cur->parent = NULL;
|
||||
|
||||
prev = NULL;
|
||||
|
||||
events = ngx_pcalloc(ngx_cycle->pool,
|
||||
lmcf->pending_timers * sizeof(ngx_event_t *));
|
||||
if (events == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
n = 0;
|
||||
|
||||
dd("root: %p, root parent: %p, sentinel: %p", cur, cur->parent, sentinel);
|
||||
|
||||
while (n < lmcf->pending_timers) {
|
||||
if (cur == sentinel || cur == NULL) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
|
||||
"lua pending timer counter got out of sync: %i",
|
||||
lmcf->pending_timers);
|
||||
break;
|
||||
}
|
||||
|
||||
dd("prev: %p, cur: %p, cur parent: %p, cur left: %p, cur right: %p",
|
||||
prev, cur, cur->parent, cur->left, cur->right);
|
||||
|
||||
if (prev == cur->parent) {
|
||||
/* neither of the children has been accessed yet */
|
||||
|
||||
next = cur->left;
|
||||
if (next == sentinel) {
|
||||
ev = (ngx_event_t *)
|
||||
((char *) cur - offsetof(ngx_event_t, timer));
|
||||
|
||||
if (ev->handler == ngx_stream_lua_timer_handler) {
|
||||
dd("found node: %p", cur);
|
||||
events[n++] = ev;
|
||||
}
|
||||
|
||||
next = (cur->right != sentinel) ? cur->right : cur->parent;
|
||||
}
|
||||
|
||||
} else if (prev == cur->left) {
|
||||
/* just accessed the left child */
|
||||
|
||||
ev = (ngx_event_t *)
|
||||
((char *) cur - offsetof(ngx_event_t, timer));
|
||||
|
||||
if (ev->handler == ngx_stream_lua_timer_handler) {
|
||||
dd("found node 2: %p", cur);
|
||||
events[n++] = ev;
|
||||
}
|
||||
|
||||
next = (cur->right != sentinel) ? cur->right : cur->parent;
|
||||
|
||||
} else if (prev == cur->right) {
|
||||
/* already accessed both children */
|
||||
next = cur->parent;
|
||||
|
||||
} else {
|
||||
/* not reacheable */
|
||||
next = NULL;
|
||||
}
|
||||
|
||||
prev = cur;
|
||||
cur = next;
|
||||
}
|
||||
|
||||
/* restore the old tree root's parent */
|
||||
ngx_event_timer_rbtree.root->parent = temp;
|
||||
|
||||
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, ngx_cycle->log, 0,
|
||||
"stream lua found %i pending timers to be "
|
||||
"aborted prematurely", n);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
ev = events[i];
|
||||
|
||||
ngx_rbtree_delete(&ngx_event_timer_rbtree, &ev->timer);
|
||||
|
||||
#if (NGX_DEBUG)
|
||||
ev->timer.left = NULL;
|
||||
ev->timer.right = NULL;
|
||||
ev->timer.parent = NULL;
|
||||
#endif
|
||||
|
||||
ev->timer_set = 0;
|
||||
|
||||
ev->timedout = 1;
|
||||
|
||||
tctx = ev->data;
|
||||
tctx->premature = 1;
|
||||
|
||||
dd("calling timer handler prematurely");
|
||||
ev->handler(ev);
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (pending_timers) {
|
||||
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
|
||||
"lua pending timer counter got out of sync: %i",
|
||||
pending_timers);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_timer.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_TIMER_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_TIMER_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
void ngx_stream_lua_inject_timer_api(lua_State *L);
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_TIMER_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,288 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_uthread.c.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_stream_lua_uthread.h"
|
||||
#include "ngx_stream_lua_coroutine.h"
|
||||
#include "ngx_stream_lua_util.h"
|
||||
#include "ngx_stream_lua_probe.h"
|
||||
|
||||
|
||||
#if 1
|
||||
#undef ngx_stream_lua_probe_info
|
||||
#define ngx_stream_lua_probe_info(msg)
|
||||
#endif
|
||||
|
||||
|
||||
static int ngx_stream_lua_uthread_spawn(lua_State *L);
|
||||
static int ngx_stream_lua_uthread_wait(lua_State *L);
|
||||
static int ngx_stream_lua_uthread_kill(lua_State *L);
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_inject_uthread_api(ngx_log_t *log, lua_State *L)
|
||||
{
|
||||
/* new thread table */
|
||||
lua_createtable(L, 0 /* narr */, 3 /* nrec */);
|
||||
|
||||
lua_pushcfunction(L, ngx_stream_lua_uthread_spawn);
|
||||
lua_setfield(L, -2, "spawn");
|
||||
|
||||
lua_pushcfunction(L, ngx_stream_lua_uthread_wait);
|
||||
lua_setfield(L, -2, "wait");
|
||||
|
||||
lua_pushcfunction(L, ngx_stream_lua_uthread_kill);
|
||||
lua_setfield(L, -2, "kill");
|
||||
|
||||
lua_setfield(L, -2, "thread");
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_stream_lua_uthread_spawn(lua_State *L)
|
||||
{
|
||||
int n;
|
||||
ngx_stream_lua_request_t *r;
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
ngx_stream_lua_co_ctx_t *coctx = NULL;
|
||||
|
||||
n = lua_gettop(L);
|
||||
|
||||
r = ngx_stream_lua_get_req(L);
|
||||
if (r == NULL) {
|
||||
return luaL_error(L, "no request found");
|
||||
}
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return luaL_error(L, "no request ctx found");
|
||||
}
|
||||
|
||||
ngx_stream_lua_coroutine_create_helper(L, r, ctx, &coctx);
|
||||
|
||||
/* anchor the newly created coroutine into the Lua registry */
|
||||
|
||||
lua_pushlightuserdata(L, ngx_stream_lua_lightudata_mask(
|
||||
coroutines_key));
|
||||
lua_rawget(L, LUA_REGISTRYINDEX);
|
||||
lua_pushvalue(L, -2);
|
||||
coctx->co_ref = luaL_ref(L, -2);
|
||||
lua_pop(L, 1);
|
||||
|
||||
if (n > 1) {
|
||||
lua_replace(L, 1);
|
||||
lua_xmove(L, coctx->co, n - 1);
|
||||
}
|
||||
|
||||
coctx->is_uthread = 1;
|
||||
ctx->uthreads++;
|
||||
|
||||
coctx->co_status = NGX_STREAM_LUA_CO_RUNNING;
|
||||
ctx->co_op = NGX_STREAM_LUA_USER_THREAD_RESUME;
|
||||
|
||||
ctx->cur_co_ctx->thread_spawn_yielded = 1;
|
||||
|
||||
if (ngx_stream_lua_post_thread(r, ctx, ctx->cur_co_ctx) != NGX_OK) {
|
||||
return luaL_error(L, "no memory");
|
||||
}
|
||||
|
||||
coctx->parent_co_ctx = ctx->cur_co_ctx;
|
||||
ctx->cur_co_ctx = coctx;
|
||||
|
||||
ngx_stream_lua_probe_user_thread_spawn(r, L, coctx->co);
|
||||
|
||||
dd("yielding with arg %s, top=%d, index-1:%s", luaL_typename(L, -1),
|
||||
(int) lua_gettop(L), luaL_typename(L, 1));
|
||||
return lua_yield(L, 1);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_stream_lua_uthread_wait(lua_State *L)
|
||||
{
|
||||
int i, nargs, nrets;
|
||||
lua_State *sub_co;
|
||||
ngx_stream_lua_request_t *r;
|
||||
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
ngx_stream_lua_co_ctx_t *coctx, *sub_coctx;
|
||||
|
||||
r = ngx_stream_lua_get_req(L);
|
||||
if (r == NULL) {
|
||||
return luaL_error(L, "no request found");
|
||||
}
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return luaL_error(L, "no request ctx found");
|
||||
}
|
||||
|
||||
ngx_stream_lua_check_context(L, ctx, NGX_STREAM_LUA_CONTEXT_YIELDABLE);
|
||||
|
||||
coctx = ctx->cur_co_ctx;
|
||||
|
||||
nargs = lua_gettop(L);
|
||||
|
||||
for (i = 1; i <= nargs; i++) {
|
||||
sub_co = lua_tothread(L, i);
|
||||
|
||||
luaL_argcheck(L, sub_co, i, "lua thread expected");
|
||||
|
||||
sub_coctx = ngx_stream_lua_get_co_ctx(sub_co, ctx);
|
||||
if (sub_coctx == NULL) {
|
||||
return luaL_error(L, "no co ctx found");
|
||||
}
|
||||
|
||||
if (!sub_coctx->is_uthread) {
|
||||
return luaL_error(L, "attempt to wait on a coroutine that is "
|
||||
"not a user thread");
|
||||
}
|
||||
|
||||
if (sub_coctx->parent_co_ctx != coctx) {
|
||||
return luaL_error(L, "only the parent coroutine can wait on the "
|
||||
"thread");
|
||||
}
|
||||
|
||||
switch (sub_coctx->co_status) {
|
||||
case NGX_STREAM_LUA_CO_ZOMBIE:
|
||||
|
||||
ngx_stream_lua_probe_info("found zombie child");
|
||||
|
||||
nrets = lua_gettop(sub_coctx->co);
|
||||
|
||||
dd("child retval count: %d, %s: %s", (int) nrets,
|
||||
luaL_typename(sub_coctx->co, -1),
|
||||
lua_tostring(sub_coctx->co, -1));
|
||||
|
||||
if (nrets) {
|
||||
lua_xmove(sub_coctx->co, L, nrets);
|
||||
}
|
||||
|
||||
#if 1
|
||||
ngx_stream_lua_del_thread(r, L, ctx, sub_coctx);
|
||||
ctx->uthreads--;
|
||||
#endif
|
||||
|
||||
return nrets;
|
||||
|
||||
case NGX_STREAM_LUA_CO_DEAD:
|
||||
dd("uthread already waited: %p (parent %p)", sub_coctx,
|
||||
coctx);
|
||||
|
||||
if (i < nargs) {
|
||||
/* just ignore it if it is not the last one */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* being the last one */
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "already waited or killed");
|
||||
return 2;
|
||||
|
||||
default:
|
||||
dd("uthread %p still alive, status: %d, parent %p", sub_coctx,
|
||||
sub_coctx->co_status, coctx);
|
||||
break;
|
||||
}
|
||||
|
||||
ngx_stream_lua_probe_user_thread_wait(L, sub_coctx->co);
|
||||
sub_coctx->waited_by_parent = 1;
|
||||
}
|
||||
|
||||
return lua_yield(L, 0);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
ngx_stream_lua_uthread_kill(lua_State *L)
|
||||
{
|
||||
lua_State *sub_co;
|
||||
ngx_stream_lua_request_t *r;
|
||||
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
ngx_stream_lua_co_ctx_t *coctx, *sub_coctx;
|
||||
|
||||
r = ngx_stream_lua_get_req(L);
|
||||
if (r == NULL) {
|
||||
return luaL_error(L, "no request found");
|
||||
}
|
||||
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
if (ctx == NULL) {
|
||||
return luaL_error(L, "no request ctx found");
|
||||
}
|
||||
|
||||
ngx_stream_lua_check_context(L, ctx, NGX_STREAM_LUA_CONTEXT_CONTENT
|
||||
|
||||
| NGX_STREAM_LUA_CONTEXT_PREREAD
|
||||
| NGX_STREAM_LUA_CONTEXT_SSL_CLIENT_HELLO
|
||||
| NGX_STREAM_LUA_CONTEXT_SSL_CERT
|
||||
| NGX_STREAM_LUA_CONTEXT_TIMER);
|
||||
|
||||
coctx = ctx->cur_co_ctx;
|
||||
|
||||
sub_co = lua_tothread(L, 1);
|
||||
luaL_argcheck(L, sub_co, 1, "lua thread expected");
|
||||
|
||||
sub_coctx = ngx_stream_lua_get_co_ctx(sub_co, ctx);
|
||||
|
||||
if (sub_coctx == NULL) {
|
||||
return luaL_error(L, "no co ctx found");
|
||||
}
|
||||
|
||||
if (!sub_coctx->is_uthread) {
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "not user thread");
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (sub_coctx->parent_co_ctx != coctx) {
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "killer not parent");
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
switch (sub_coctx->co_status) {
|
||||
case NGX_STREAM_LUA_CO_ZOMBIE:
|
||||
ngx_stream_lua_del_thread(r, L, ctx, sub_coctx);
|
||||
ctx->uthreads--;
|
||||
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "already terminated");
|
||||
return 2;
|
||||
|
||||
case NGX_STREAM_LUA_CO_DEAD:
|
||||
lua_pushnil(L);
|
||||
lua_pushliteral(L, "already waited or killed");
|
||||
return 2;
|
||||
|
||||
default:
|
||||
ngx_stream_lua_cleanup_pending_operation(sub_coctx);
|
||||
ngx_stream_lua_del_thread(r, L, ctx, sub_coctx);
|
||||
ctx->uthreads--;
|
||||
|
||||
lua_pushinteger(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* not reacheable */
|
||||
}
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,44 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_uthread.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_UTHREAD_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_UTHREAD_H_INCLUDED_
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
|
||||
|
||||
#define ngx_stream_lua_is_thread(ctx) \
|
||||
((ctx)->cur_co_ctx->is_uthread || (ctx)->cur_co_ctx == &(ctx)->entry_co_ctx)
|
||||
|
||||
|
||||
#define ngx_stream_lua_is_entry_thread(ctx) \
|
||||
((ctx)->cur_co_ctx == &(ctx)->entry_co_ctx)
|
||||
|
||||
|
||||
#define ngx_stream_lua_entry_thread_alive(ctx) \
|
||||
((ctx)->entry_co_ctx.co_ref != LUA_NOREF)
|
||||
|
||||
|
||||
#define ngx_stream_lua_coroutine_alive(coctx) \
|
||||
((coctx)->co_status != NGX_STREAM_LUA_CO_DEAD \
|
||||
&& (coctx)->co_status != NGX_STREAM_LUA_CO_ZOMBIE)
|
||||
|
||||
|
||||
void ngx_stream_lua_inject_uthread_api(ngx_log_t *log, lua_State *L);
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_UTHREAD_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,528 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_util.h.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _NGX_STREAM_LUA_UTIL_H_INCLUDED_
|
||||
#define _NGX_STREAM_LUA_UTIL_H_INCLUDED_
|
||||
|
||||
|
||||
#ifdef DDEBUG
|
||||
#include "ddebug.h"
|
||||
#endif
|
||||
|
||||
|
||||
#include "ngx_stream_lua_common.h"
|
||||
#include "ngx_stream_lua_ssl.h"
|
||||
#include "ngx_stream_lua_api.h"
|
||||
|
||||
|
||||
#ifndef NGX_UNESCAPE_URI_COMPONENT
|
||||
#define NGX_UNESCAPE_URI_COMPONENT 0
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct {
|
||||
ngx_stream_lua_ffi_str_t key;
|
||||
ngx_stream_lua_ffi_str_t value;
|
||||
} ngx_stream_lua_ffi_table_elt_t;
|
||||
|
||||
|
||||
/* char whose address we use as the key in Lua vm registry for
|
||||
* user code cache table */
|
||||
extern char ngx_stream_lua_code_cache_key;
|
||||
|
||||
|
||||
/* key in Lua vm registry for all the "ngx.ctx" tables */
|
||||
#define ngx_stream_lua_ctx_tables_key "ngx_lua_ctx_tables"
|
||||
|
||||
|
||||
/* char whose address we use as the key in Lua vm registry for
|
||||
* regex cache table */
|
||||
extern char ngx_stream_lua_regex_cache_key;
|
||||
|
||||
/* char whose address we use as the key in Lua vm registry for
|
||||
* socket connection pool table */
|
||||
extern char ngx_stream_lua_socket_pool_key;
|
||||
|
||||
/* char whose address we use as the key for the coroutine parent relationship */
|
||||
extern char ngx_stream_lua_coroutine_parents_key;
|
||||
|
||||
/* coroutine anchoring table key in Lua VM registry */
|
||||
extern char ngx_stream_lua_coroutines_key;
|
||||
|
||||
/* key to the metatable for ngx.req.get_headers() and ngx.resp.get_headers() */
|
||||
extern char ngx_stream_lua_headers_metatable_key;
|
||||
|
||||
|
||||
#ifndef ngx_str_set
|
||||
#define ngx_str_set(str, text) \
|
||||
(str)->len = sizeof(text) - 1; (str)->data = (u_char *) text
|
||||
#endif
|
||||
|
||||
|
||||
#define NGX_STREAM_LUA_CONTEXT_YIELDABLE (NGX_STREAM_LUA_CONTEXT_PREREAD \
|
||||
| NGX_STREAM_LUA_CONTEXT_CONTENT \
|
||||
| NGX_STREAM_LUA_CONTEXT_TIMER \
|
||||
| NGX_STREAM_LUA_CONTEXT_SSL_CLIENT_HELLO \
|
||||
| NGX_STREAM_LUA_CONTEXT_SSL_CERT)
|
||||
|
||||
|
||||
#define ngx_stream_lua_context_name(c) \
|
||||
((c) == NGX_STREAM_LUA_CONTEXT_CONTENT ? "content_by_lua*" \
|
||||
: (c) == NGX_STREAM_LUA_CONTEXT_LOG ? "log_by_lua*" \
|
||||
: (c) == NGX_STREAM_LUA_CONTEXT_TIMER ? "ngx.timer" \
|
||||
: (c) == NGX_STREAM_LUA_CONTEXT_INIT_WORKER ? "init_worker_by_lua*" \
|
||||
: (c) == NGX_STREAM_LUA_CONTEXT_BALANCER ? "balancer_by_lua*" \
|
||||
: (c) == NGX_STREAM_LUA_CONTEXT_PREREAD ? "preread_by_lua*" \
|
||||
: (c) == NGX_STREAM_LUA_CONTEXT_SSL_CLIENT_HELLO ? \
|
||||
"ssl_client_hello_by_lua*" \
|
||||
: (c) == NGX_STREAM_LUA_CONTEXT_SSL_CERT ? "ssl_certificate_by_lua*" \
|
||||
: "(unknown)")
|
||||
|
||||
|
||||
#define ngx_stream_lua_check_context(L, ctx, flags) \
|
||||
if (!((ctx)->context & (flags))) { \
|
||||
return luaL_error(L, "API disabled in the context of %s", \
|
||||
ngx_stream_lua_context_name((ctx)->context)); \
|
||||
}
|
||||
|
||||
|
||||
static ngx_inline ngx_int_t
|
||||
ngx_stream_lua_ffi_check_context(ngx_stream_lua_ctx_t *ctx,
|
||||
unsigned flags, u_char *err, size_t *errlen)
|
||||
{
|
||||
if (!(ctx->context & flags)) {
|
||||
*errlen = ngx_snprintf(err, *errlen,
|
||||
"API disabled in the context of %s",
|
||||
ngx_stream_lua_context_name((ctx)->context))
|
||||
- err;
|
||||
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
#define ngx_stream_lua_check_fake_request(L, r) \
|
||||
if ((r)->connection->fd == (ngx_socket_t) -1) { \
|
||||
return luaL_error(L, "API disabled in the current context"); \
|
||||
}
|
||||
|
||||
|
||||
#define ngx_stream_lua_check_fake_request2(L, r, ctx) \
|
||||
if ((r)->connection->fd == (ngx_socket_t) -1) { \
|
||||
return luaL_error(L, "API disabled in the context of %s", \
|
||||
ngx_stream_lua_context_name((ctx) \
|
||||
->context)); \
|
||||
}
|
||||
|
||||
|
||||
#define ngx_stream_lua_ssl_get_ctx(ssl_conn) \
|
||||
SSL_get_ex_data(ssl_conn, ngx_stream_lua_ssl_ctx_index)
|
||||
|
||||
|
||||
ngx_int_t ngx_stream_lua_init_vm(lua_State **new_vm, lua_State *parent_vm,
|
||||
ngx_cycle_t *cycle, ngx_pool_t *pool,
|
||||
ngx_stream_lua_main_conf_t *lmcf, ngx_log_t *log,
|
||||
ngx_pool_cleanup_t **pcln);
|
||||
|
||||
lua_State *ngx_stream_lua_new_thread(ngx_stream_lua_request_t *r, lua_State *l,
|
||||
int *ref);
|
||||
|
||||
u_char *ngx_stream_lua_rebase_path(ngx_pool_t *pool, u_char *src, size_t len);
|
||||
|
||||
ngx_int_t ngx_stream_lua_send_header_if_needed(ngx_stream_lua_request_t *r,
|
||||
ngx_stream_lua_ctx_t *ctx);
|
||||
|
||||
ngx_int_t ngx_stream_lua_send_chain_link(ngx_stream_lua_request_t *r,
|
||||
ngx_stream_lua_ctx_t *ctx, ngx_chain_t *cl);
|
||||
|
||||
void ngx_stream_lua_discard_bufs(ngx_pool_t *pool, ngx_chain_t *in);
|
||||
|
||||
ngx_int_t ngx_stream_lua_add_copy_chain(ngx_stream_lua_request_t *r,
|
||||
ngx_stream_lua_ctx_t *ctx, ngx_chain_t ***plast, ngx_chain_t *in,
|
||||
ngx_int_t *eof);
|
||||
|
||||
void ngx_stream_lua_reset_ctx(ngx_stream_lua_request_t *r, lua_State *L,
|
||||
ngx_stream_lua_ctx_t *ctx);
|
||||
|
||||
void ngx_stream_lua_generic_phase_post_read(ngx_stream_lua_request_t *r);
|
||||
|
||||
void ngx_stream_lua_request_cleanup(ngx_stream_lua_ctx_t *ctx, int foricible);
|
||||
|
||||
void ngx_stream_lua_request_cleanup_handler(void *data);
|
||||
|
||||
ngx_int_t ngx_stream_lua_run_thread(lua_State *L, ngx_stream_lua_request_t *r,
|
||||
ngx_stream_lua_ctx_t *ctx, volatile int nret);
|
||||
|
||||
ngx_int_t ngx_stream_lua_wev_handler(ngx_stream_lua_request_t *r);
|
||||
|
||||
u_char *ngx_stream_lua_digest_hex(u_char *dest, const u_char *buf,
|
||||
int buf_len);
|
||||
|
||||
void ngx_stream_lua_set_multi_value_table(lua_State *L, int index);
|
||||
|
||||
void ngx_stream_lua_unescape_uri(u_char **dst, u_char **src, size_t size,
|
||||
ngx_uint_t type);
|
||||
|
||||
uintptr_t ngx_stream_lua_escape_uri(u_char *dst, u_char *src,
|
||||
size_t size, ngx_uint_t type);
|
||||
|
||||
void ngx_stream_lua_inject_req_api(ngx_log_t *log, lua_State *L);
|
||||
|
||||
void ngx_stream_lua_process_args_option(ngx_stream_lua_request_t *r,
|
||||
lua_State *L, int table, ngx_str_t *args);
|
||||
|
||||
ngx_int_t ngx_stream_lua_open_and_stat_file(u_char *name,
|
||||
ngx_open_file_info_t *of, ngx_log_t *log);
|
||||
|
||||
ngx_chain_t *ngx_stream_lua_chain_get_free_buf(ngx_log_t *log, ngx_pool_t *p,
|
||||
ngx_chain_t **free, size_t len);
|
||||
|
||||
#ifndef OPENRESTY_LUAJIT
|
||||
void ngx_stream_lua_create_new_globals_table(lua_State *L, int narr, int nrec);
|
||||
#endif
|
||||
|
||||
int ngx_stream_lua_traceback(lua_State *L);
|
||||
|
||||
ngx_stream_lua_co_ctx_t *ngx_stream_lua_get_co_ctx(lua_State *L,
|
||||
ngx_stream_lua_ctx_t *ctx);
|
||||
|
||||
ngx_stream_lua_co_ctx_t *ngx_stream_lua_create_co_ctx(
|
||||
ngx_stream_lua_request_t *r, ngx_stream_lua_ctx_t *ctx);
|
||||
|
||||
ngx_int_t ngx_stream_lua_run_posted_threads(ngx_connection_t *c, lua_State *L,
|
||||
ngx_stream_lua_request_t *r, ngx_stream_lua_ctx_t *ctx, ngx_uint_t nreqs);
|
||||
|
||||
ngx_int_t ngx_stream_lua_post_thread(ngx_stream_lua_request_t *r,
|
||||
ngx_stream_lua_ctx_t *ctx, ngx_stream_lua_co_ctx_t *coctx);
|
||||
|
||||
void ngx_stream_lua_del_thread(ngx_stream_lua_request_t *r, lua_State *L,
|
||||
ngx_stream_lua_ctx_t *ctx, ngx_stream_lua_co_ctx_t *coctx);
|
||||
|
||||
void ngx_stream_lua_rd_check_broken_connection(ngx_stream_lua_request_t *r);
|
||||
|
||||
ngx_int_t ngx_stream_lua_test_expect(ngx_stream_lua_request_t *r);
|
||||
|
||||
ngx_int_t ngx_stream_lua_check_broken_connection(ngx_stream_lua_request_t *r,
|
||||
ngx_event_t *ev);
|
||||
|
||||
void ngx_stream_lua_finalize_request(ngx_stream_lua_request_t *r, ngx_int_t rc);
|
||||
|
||||
void ngx_stream_lua_finalize_fake_request(ngx_stream_lua_request_t *r,
|
||||
ngx_int_t rc);
|
||||
|
||||
void ngx_stream_lua_close_fake_connection(ngx_connection_t *c);
|
||||
|
||||
void ngx_stream_lua_free_fake_request(ngx_stream_lua_request_t *r);
|
||||
|
||||
void ngx_stream_lua_release_ngx_ctx_table(ngx_log_t *log, lua_State *L,
|
||||
ngx_stream_lua_ctx_t *ctx);
|
||||
|
||||
void ngx_stream_lua_cleanup_vm(void *data);
|
||||
|
||||
ngx_connection_t *ngx_stream_lua_create_fake_connection(ngx_pool_t *pool);
|
||||
|
||||
ngx_stream_lua_request_t *
|
||||
ngx_stream_lua_create_fake_request(ngx_stream_session_t *s);
|
||||
|
||||
ngx_stream_session_t *ngx_stream_lua_create_fake_session(ngx_connection_t *c);
|
||||
|
||||
ngx_int_t ngx_stream_lua_report(ngx_log_t *log, lua_State *L, int status,
|
||||
const char *prefix);
|
||||
|
||||
int ngx_stream_lua_do_call(ngx_log_t *log, lua_State *L);
|
||||
|
||||
|
||||
|
||||
void ngx_stream_lua_cleanup_free(ngx_stream_lua_request_t *r,
|
||||
ngx_stream_lua_cleanup_pt *cleanup);
|
||||
|
||||
#if (NGX_STREAM_LUA_HAVE_SA_RESTART)
|
||||
void ngx_stream_lua_set_sa_restart(ngx_log_t *log);
|
||||
#endif
|
||||
|
||||
#define ngx_stream_lua_check_if_abortable(L, ctx) \
|
||||
if ((ctx)->no_abort) { \
|
||||
return luaL_error(L, "attempt to abort with pending subrequests"); \
|
||||
}
|
||||
|
||||
|
||||
static ngx_inline void
|
||||
ngx_stream_lua_init_ctx(ngx_stream_lua_request_t *r, ngx_stream_lua_ctx_t *ctx)
|
||||
{
|
||||
ngx_memzero(ctx, sizeof(ngx_stream_lua_ctx_t));
|
||||
ctx->ctx_ref = LUA_NOREF;
|
||||
ctx->entry_co_ctx.co_ref = LUA_NOREF;
|
||||
ctx->resume_handler = ngx_stream_lua_wev_handler;
|
||||
ctx->request = r;
|
||||
}
|
||||
|
||||
|
||||
static ngx_inline ngx_stream_lua_ctx_t *
|
||||
ngx_stream_lua_create_ctx(ngx_stream_session_t *r)
|
||||
{
|
||||
ngx_int_t rc;
|
||||
lua_State *L = NULL;
|
||||
ngx_stream_lua_ctx_t *ctx;
|
||||
ngx_pool_cleanup_t *cln;
|
||||
ngx_stream_lua_loc_conf_t *llcf;
|
||||
ngx_stream_lua_main_conf_t *lmcf;
|
||||
|
||||
ngx_stream_lua_request_t *sreq;
|
||||
|
||||
ctx = ngx_palloc(r->connection->pool, sizeof(ngx_stream_lua_ctx_t));
|
||||
if (ctx == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sreq = ngx_stream_lua_create_request(r);
|
||||
|
||||
if (sreq == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ngx_stream_lua_init_ctx(sreq, ctx);
|
||||
|
||||
ngx_stream_set_ctx(r, ctx, ngx_stream_lua_module);
|
||||
|
||||
llcf = ngx_stream_get_module_srv_conf(r, ngx_stream_lua_module);
|
||||
|
||||
if (!llcf->enable_code_cache && r->connection->fd != (ngx_socket_t) -1) {
|
||||
lmcf = ngx_stream_get_module_main_conf(r, ngx_stream_lua_module);
|
||||
|
||||
#ifdef DDEBUG
|
||||
dd("lmcf: %p", lmcf);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* caveats: we need to move the vm cleanup hook to the list end
|
||||
* to ensure it will be executed *after* the request cleanup
|
||||
* hook registered by ngx_stream_lua_create_request to preserve
|
||||
* the correct semantics.
|
||||
*/
|
||||
|
||||
rc = ngx_stream_lua_init_vm(&L, lmcf->lua, lmcf->cycle, sreq->pool,
|
||||
lmcf, r->connection->log, &cln);
|
||||
|
||||
while (cln->next != NULL) {
|
||||
cln = cln->next;
|
||||
}
|
||||
|
||||
cln->next = sreq->pool->cleanup;
|
||||
|
||||
cln = sreq->pool->cleanup;
|
||||
sreq->pool->cleanup = cln->next;
|
||||
cln->next = NULL;
|
||||
|
||||
if (rc != NGX_OK) {
|
||||
if (rc == NGX_DECLINED) {
|
||||
ngx_stream_lua_assert(L != NULL);
|
||||
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"failed to load the 'resty.core' module "
|
||||
"(https://github.com/openresty/lua-resty"
|
||||
"-core); ensure you are using an OpenResty "
|
||||
"release from https://openresty.org/en/"
|
||||
"download.html (reason: %s)",
|
||||
lua_tostring(L, -1));
|
||||
|
||||
} else {
|
||||
/* rc == NGX_ERROR */
|
||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||
"failed to initialize Lua VM");
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* rc == NGX_OK */
|
||||
|
||||
ngx_stream_lua_assert(L != NULL);
|
||||
|
||||
if (lmcf->init_handler) {
|
||||
if (lmcf->init_handler(r->connection->log, lmcf, L) != NGX_OK) {
|
||||
/* an error happened */
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->vm_state = cln->data;
|
||||
|
||||
} else {
|
||||
ctx->vm_state = NULL;
|
||||
}
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
||||
static ngx_inline lua_State *
|
||||
ngx_stream_lua_get_lua_vm(ngx_stream_lua_request_t *r,
|
||||
ngx_stream_lua_ctx_t *ctx)
|
||||
{
|
||||
ngx_stream_lua_main_conf_t *lmcf;
|
||||
|
||||
if (ctx == NULL) {
|
||||
ctx = ngx_stream_lua_get_module_ctx(r, ngx_stream_lua_module);
|
||||
}
|
||||
|
||||
if (ctx && ctx->vm_state) {
|
||||
return ctx->vm_state->vm;
|
||||
}
|
||||
|
||||
lmcf = ngx_stream_lua_get_module_main_conf(r, ngx_stream_lua_module);
|
||||
|
||||
#ifdef DDEBUG
|
||||
dd("lmcf->lua: %p", lmcf->lua);
|
||||
#endif
|
||||
|
||||
return lmcf->lua;
|
||||
}
|
||||
|
||||
|
||||
#define ngx_stream_lua_req_key "__ngx_req"
|
||||
|
||||
|
||||
static ngx_inline ngx_stream_lua_request_t *
|
||||
ngx_stream_lua_get_req(lua_State *L)
|
||||
{
|
||||
#ifdef OPENRESTY_LUAJIT
|
||||
return lua_getexdata(L);
|
||||
#else
|
||||
ngx_stream_lua_request_t *r;
|
||||
|
||||
lua_getglobal(L, ngx_stream_lua_req_key);
|
||||
r = lua_touserdata(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
return r;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static ngx_inline void
|
||||
ngx_stream_lua_set_req(lua_State *L, ngx_stream_lua_request_t *r)
|
||||
{
|
||||
#ifdef OPENRESTY_LUAJIT
|
||||
lua_setexdata(L, (void *) r);
|
||||
#else
|
||||
lua_pushlightuserdata(L, r);
|
||||
lua_setglobal(L, ngx_stream_lua_req_key);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static ngx_inline void
|
||||
ngx_stream_lua_get_globals_table(lua_State *L)
|
||||
{
|
||||
lua_pushvalue(L, LUA_GLOBALSINDEX);
|
||||
}
|
||||
|
||||
|
||||
static ngx_inline void
|
||||
ngx_stream_lua_set_globals_table(lua_State *L)
|
||||
{
|
||||
lua_replace(L, LUA_GLOBALSINDEX);
|
||||
}
|
||||
|
||||
|
||||
#define ngx_stream_lua_hash_literal(s) \
|
||||
ngx_stream_lua_hash_str((u_char *) s, sizeof(s) - 1)
|
||||
|
||||
|
||||
static ngx_inline ngx_uint_t
|
||||
ngx_stream_lua_hash_str(u_char *src, size_t n)
|
||||
{
|
||||
ngx_uint_t key;
|
||||
|
||||
key = 0;
|
||||
|
||||
while (n--) {
|
||||
key = ngx_hash(key, *src);
|
||||
src++;
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static ngx_inline void
|
||||
ngx_stream_lua_cleanup_pending_operation(ngx_stream_lua_co_ctx_t *coctx)
|
||||
{
|
||||
if (coctx->cleanup) {
|
||||
coctx->cleanup(coctx);
|
||||
coctx->cleanup = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static ngx_inline ngx_chain_t *
|
||||
ngx_stream_lua_get_flush_chain(ngx_stream_lua_request_t *r,
|
||||
ngx_stream_lua_ctx_t *ctx)
|
||||
{
|
||||
ngx_chain_t *cl;
|
||||
|
||||
cl = ngx_stream_lua_chain_get_free_buf(r->connection->log, r->pool,
|
||||
&ctx->free_bufs, 0);
|
||||
if (cl == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cl->buf->flush = 1;
|
||||
|
||||
return cl;
|
||||
}
|
||||
|
||||
|
||||
#if defined(nginx_version) && nginx_version < 1011002
|
||||
static ngx_inline in_port_t
|
||||
ngx_inet_get_port(struct sockaddr *sa)
|
||||
{
|
||||
struct sockaddr_in *sin;
|
||||
#if (NGX_HAVE_INET6)
|
||||
struct sockaddr_in6 *sin6;
|
||||
#endif
|
||||
|
||||
switch (sa->sa_family) {
|
||||
|
||||
#if (NGX_HAVE_INET6)
|
||||
case AF_INET6:
|
||||
sin6 = (struct sockaddr_in6 *) sa;
|
||||
return ntohs(sin6->sin6_port);
|
||||
#endif
|
||||
|
||||
#if (NGX_HAVE_UNIX_DOMAIN)
|
||||
case AF_UNIX:
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
default: /* AF_INET */
|
||||
sin = (struct sockaddr_in *) sa;
|
||||
return ntohs(sin->sin_port);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
extern ngx_uint_t ngx_stream_lua_location_hash;
|
||||
extern ngx_uint_t ngx_stream_lua_content_length_hash;
|
||||
|
||||
|
||||
#endif /* _NGX_STREAM_LUA_UTIL_H_INCLUDED_ */
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,214 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_variable.c.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Xiaozhe Wang (chaoslawful)
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#include "ngx_stream_lua_util.h"
|
||||
|
||||
|
||||
|
||||
|
||||
int
|
||||
ngx_stream_lua_ffi_var_get(ngx_stream_lua_request_t *r, u_char *name_data,
|
||||
size_t name_len, u_char *lowcase_buf, int capture_id, u_char **value,
|
||||
size_t *value_len, char **err)
|
||||
{
|
||||
ngx_uint_t hash;
|
||||
ngx_str_t name;
|
||||
|
||||
ngx_stream_variable_value_t *vv;
|
||||
|
||||
if (r == NULL) {
|
||||
*err = "no request object found";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if ((r)->connection->fd == (ngx_socket_t) -1) {
|
||||
*err = "API disabled in the current context";
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
|
||||
hash = ngx_hash_strlow(lowcase_buf, name_data, name_len);
|
||||
|
||||
name.data = lowcase_buf;
|
||||
name.len = name_len;
|
||||
|
||||
dd("variable name: %.*s", (int) name_len, lowcase_buf);
|
||||
|
||||
vv = ngx_stream_get_variable(r->session, &name, hash);
|
||||
|
||||
if (vv == NULL || vv->not_found) {
|
||||
return NGX_DECLINED;
|
||||
}
|
||||
|
||||
*value = vv->data;
|
||||
*value_len = vv->len;
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_stream_lua_ffi_var_set(ngx_stream_lua_request_t *r, u_char *name_data,
|
||||
size_t name_len, u_char *lowcase_buf, u_char *value, size_t value_len,
|
||||
u_char *errbuf, size_t *errlen)
|
||||
{
|
||||
u_char *p;
|
||||
ngx_uint_t hash;
|
||||
|
||||
ngx_stream_variable_t *v;
|
||||
ngx_stream_variable_value_t *vv;
|
||||
ngx_stream_core_main_conf_t *cmcf;
|
||||
|
||||
if (r == NULL) {
|
||||
*errlen = ngx_snprintf(errbuf, *errlen, "no request object found")
|
||||
- errbuf;
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if ((r)->connection->fd == (ngx_socket_t) -1) {
|
||||
*errlen = ngx_snprintf(errbuf, *errlen,
|
||||
"API disabled in the current context")
|
||||
- errbuf;
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
hash = ngx_hash_strlow(lowcase_buf, name_data, name_len);
|
||||
|
||||
dd("variable name: %.*s", (int) name_len, lowcase_buf);
|
||||
|
||||
/* we fetch the variable itself */
|
||||
|
||||
cmcf = ngx_stream_lua_get_module_main_conf(r, ngx_stream_core_module);
|
||||
|
||||
v = ngx_hash_find(&cmcf->variables_hash, hash, lowcase_buf, name_len);
|
||||
|
||||
if (v) {
|
||||
if (!(v->flags & NGX_STREAM_VAR_CHANGEABLE)) {
|
||||
dd("variable not changeable");
|
||||
*errlen = ngx_snprintf(errbuf, *errlen,
|
||||
"variable \"%*s\" not changeable",
|
||||
name_len, lowcase_buf)
|
||||
- errbuf;
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (v->set_handler) {
|
||||
|
||||
dd("set variables with set_handler");
|
||||
|
||||
if (value != NULL && value_len) {
|
||||
vv = ngx_palloc(r->connection->pool,
|
||||
sizeof(ngx_stream_variable_value_t)
|
||||
+ value_len);
|
||||
if (vv == NULL) {
|
||||
goto nomem;
|
||||
}
|
||||
|
||||
p = (u_char *) vv + sizeof(ngx_stream_variable_value_t);
|
||||
ngx_memcpy(p, value, value_len);
|
||||
value = p;
|
||||
|
||||
} else {
|
||||
vv = ngx_palloc(r->connection->pool,
|
||||
sizeof(ngx_stream_variable_value_t));
|
||||
if (vv == NULL) {
|
||||
goto nomem;
|
||||
}
|
||||
}
|
||||
|
||||
if (value == NULL) {
|
||||
vv->valid = 0;
|
||||
vv->not_found = 1;
|
||||
vv->no_cacheable = 0;
|
||||
vv->data = NULL;
|
||||
vv->len = 0;
|
||||
|
||||
} else {
|
||||
vv->valid = 1;
|
||||
vv->not_found = 0;
|
||||
vv->no_cacheable = 0;
|
||||
|
||||
vv->data = value;
|
||||
vv->len = value_len;
|
||||
}
|
||||
|
||||
v->set_handler(r->session, vv, v->data);
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
if (v->flags & NGX_STREAM_VAR_INDEXED) {
|
||||
vv = &r->session->variables[v->index];
|
||||
|
||||
dd("set indexed variable");
|
||||
|
||||
if (value == NULL) {
|
||||
vv->valid = 0;
|
||||
vv->not_found = 1;
|
||||
vv->no_cacheable = 0;
|
||||
|
||||
vv->data = NULL;
|
||||
vv->len = 0;
|
||||
|
||||
} else {
|
||||
p = ngx_palloc(r->connection->pool, value_len);
|
||||
if (p == NULL) {
|
||||
goto nomem;
|
||||
}
|
||||
|
||||
ngx_memcpy(p, value, value_len);
|
||||
value = p;
|
||||
|
||||
vv->valid = 1;
|
||||
vv->not_found = 0;
|
||||
vv->no_cacheable = 0;
|
||||
|
||||
vv->data = value;
|
||||
vv->len = value_len;
|
||||
}
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
|
||||
*errlen = ngx_snprintf(errbuf, *errlen,
|
||||
"variable \"%*s\" cannot be assigned "
|
||||
"a value", name_len, lowcase_buf)
|
||||
- errbuf;
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
/* variable not found */
|
||||
|
||||
*errlen = ngx_snprintf(errbuf, *errlen,
|
||||
"variable \"%*s\" not found for writing; "
|
||||
"maybe it is a built-in variable that is not "
|
||||
"changeable or you forgot to use \"set $%*s '';\" "
|
||||
"in the config file to define it first",
|
||||
name_len, lowcase_buf, name_len, lowcase_buf)
|
||||
- errbuf;
|
||||
return NGX_ERROR;
|
||||
|
||||
nomem:
|
||||
|
||||
*errlen = ngx_snprintf(errbuf, *errlen, "no memory") - errbuf;
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,177 @@
|
|||
|
||||
/*
|
||||
* !!! DO NOT EDIT DIRECTLY !!!
|
||||
* This file was automatically generated from the following template:
|
||||
*
|
||||
* src/subsys/ngx_subsys_lua_worker.c.tt2
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (C) Yichun Zhang (agentzh)
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DDEBUG
|
||||
#define DDEBUG 0
|
||||
#endif
|
||||
#include "ddebug.h"
|
||||
|
||||
|
||||
#define NGX_PROCESS_PRIVILEGED_AGENT 99
|
||||
|
||||
|
||||
int
|
||||
ngx_stream_lua_ffi_worker_pid(void)
|
||||
{
|
||||
return (int) ngx_pid;
|
||||
}
|
||||
|
||||
|
||||
#if !(NGX_WIN32)
|
||||
int
|
||||
ngx_stream_lua_ffi_worker_pids(int *pids, size_t *pids_len)
|
||||
{
|
||||
size_t n;
|
||||
ngx_int_t i;
|
||||
|
||||
n = 0;
|
||||
for (i = 0; n < *pids_len && i < NGX_MAX_PROCESSES; i++) {
|
||||
if (i != ngx_process_slot && ngx_processes[i].pid == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* The current process */
|
||||
if (i == ngx_process_slot) {
|
||||
pids[n++] = ngx_pid;
|
||||
}
|
||||
|
||||
if (ngx_processes[i].channel[0] > 0 && ngx_processes[i].pid > 0) {
|
||||
pids[n++] = ngx_processes[i].pid;
|
||||
}
|
||||
}
|
||||
|
||||
if (n == 0) {
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
*pids_len = n;
|
||||
|
||||
return NGX_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int
|
||||
ngx_stream_lua_ffi_worker_id(void)
|
||||
{
|
||||
#if defined(nginx_version) && nginx_version >= 1009001
|
||||
if (ngx_process != NGX_PROCESS_WORKER
|
||||
&& ngx_process != NGX_PROCESS_SINGLE)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (int) ngx_worker;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_stream_lua_ffi_worker_exiting(void)
|
||||
{
|
||||
return (int) ngx_exiting;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_stream_lua_ffi_worker_count(void)
|
||||
{
|
||||
ngx_core_conf_t *ccf;
|
||||
|
||||
ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
|
||||
ngx_core_module);
|
||||
|
||||
return (int) ccf->worker_processes;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_stream_lua_ffi_master_pid(void)
|
||||
{
|
||||
#if defined(nginx_version) && nginx_version >= 1013008
|
||||
if (ngx_process == NGX_PROCESS_SINGLE) {
|
||||
return (int) ngx_pid;
|
||||
}
|
||||
|
||||
return (int) ngx_parent;
|
||||
#else
|
||||
return NGX_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ngx_stream_lua_ffi_get_process_type(void)
|
||||
{
|
||||
ngx_core_conf_t *ccf;
|
||||
|
||||
#if defined(HAVE_PRIVILEGED_PROCESS_PATCH) && !NGX_WIN32
|
||||
if (ngx_process == NGX_PROCESS_HELPER) {
|
||||
if (ngx_is_privileged_agent) {
|
||||
return NGX_PROCESS_PRIVILEGED_AGENT;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ngx_process == NGX_PROCESS_SINGLE) {
|
||||
ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
|
||||
ngx_core_module);
|
||||
|
||||
if (ccf->master) {
|
||||
return NGX_PROCESS_MASTER;
|
||||
}
|
||||
}
|
||||
|
||||
return ngx_process;
|
||||
}
|
||||
|
||||
|
||||
#if defined(nginx_version) && nginx_version >= 1019003
|
||||
int
|
||||
ngx_stream_lua_ffi_enable_privileged_agent(char **err, unsigned int connections)
|
||||
#else
|
||||
int
|
||||
ngx_stream_lua_ffi_enable_privileged_agent(char **err)
|
||||
#endif
|
||||
{
|
||||
#ifdef HAVE_PRIVILEGED_PROCESS_PATCH
|
||||
ngx_core_conf_t *ccf;
|
||||
|
||||
ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
|
||||
ngx_core_module);
|
||||
|
||||
ccf->privileged_agent = 1;
|
||||
#if defined(nginx_version) && nginx_version >= 1019003
|
||||
ccf->privileged_agent_connections = connections;
|
||||
#endif
|
||||
|
||||
return NGX_OK;
|
||||
|
||||
#else
|
||||
*err = "missing privileged agent process patch in the nginx core";
|
||||
return NGX_ERROR;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ngx_stream_lua_ffi_process_signal_graceful_exit(void)
|
||||
{
|
||||
ngx_quit = 1;
|
||||
}
|
||||
|
||||
|
||||
/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
|
|
@ -0,0 +1,248 @@
|
|||
# vim:set ft= ts=4 sw=4 et fdm=marker:
|
||||
|
||||
use Test::Nginx::Socket::Lua::Stream;
|
||||
|
||||
#worker_connections(1014);
|
||||
#master_on();
|
||||
#workers(2);
|
||||
#log_level('warn');
|
||||
|
||||
repeat_each(2);
|
||||
|
||||
plan tests => repeat_each() * (blocks() * 3 + 3);
|
||||
|
||||
#no_diff();
|
||||
#no_long_string();
|
||||
run_tests();
|
||||
|
||||
__DATA__
|
||||
|
||||
=== TEST 1: basic print
|
||||
--- stream_server_config
|
||||
content_by_lua_block {
|
||||
local ok, err = ngx.print("Hello, Lua!\n")
|
||||
if not ok then
|
||||
ngx.log(ngx.ERR, "print failed: ", err)
|
||||
end
|
||||
}
|
||||
--- stream_response
|
||||
Hello, Lua!
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 2: basic say
|
||||
--- stream_server_config
|
||||
content_by_lua_block {
|
||||
local ok, err = ngx.say("Hello, Lua!")
|
||||
if not ok then
|
||||
ngx.log(ngx.ERR, "say failed: ", err)
|
||||
return
|
||||
end
|
||||
local ok, err = ngx.say("Yay! ", 123)
|
||||
if not ok then
|
||||
ngx.log(ngx.ERR, "say failed: ", err)
|
||||
return
|
||||
end
|
||||
}
|
||||
--- stream_response
|
||||
Hello, Lua!
|
||||
Yay! 123
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 3: no ngx.echo
|
||||
--- stream_server_config
|
||||
content_by_lua_block { ngx.echo("Hello, Lua!\n") }
|
||||
--- stream_response
|
||||
--- error_log eval
|
||||
qr/content_by_lua\(nginx\.conf:\d+\):1: attempt to call field 'echo' \(a nil value\)/
|
||||
|
||||
|
||||
|
||||
=== TEST 4: calc expression
|
||||
--- stream_server_config
|
||||
content_by_lua_file html/calc.lua;
|
||||
--- user_files
|
||||
>>> calc.lua
|
||||
local function uri_unescape(uri)
|
||||
local function convert(hex)
|
||||
return string.char(tonumber("0x"..hex))
|
||||
end
|
||||
local s = string.gsub(uri, "%%([0-9a-fA-F][0-9a-fA-F])", convert)
|
||||
return s
|
||||
end
|
||||
|
||||
local function eval_exp(str)
|
||||
return loadstring("return "..str)()
|
||||
end
|
||||
|
||||
local exp_str = 1+2*math.sin(3)/math.exp(4)-math.sqrt(2)
|
||||
-- print("exp: '", exp_str, "'\n")
|
||||
local status, res
|
||||
status, res = pcall(uri_unescape, exp_str)
|
||||
if not status then
|
||||
ngx.print("error: ", res, "\n")
|
||||
return
|
||||
end
|
||||
status, res = pcall(eval_exp, res)
|
||||
if status then
|
||||
ngx.print("result: ", res, "\n")
|
||||
else
|
||||
ngx.print("error: ", res, "\n")
|
||||
end
|
||||
|
||||
--- stream_response
|
||||
result: -0.4090441561579
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 5: nil is "nil"
|
||||
--- stream_server_config
|
||||
content_by_lua_block { ngx.say(nil) }
|
||||
--- stream_response
|
||||
nil
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 6: write boolean
|
||||
--- stream_server_config
|
||||
content_by_lua_block { ngx.say(true, " ", false) }
|
||||
--- stream_response
|
||||
true false
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 7: nginx quote sql string 1
|
||||
--- stream_server_config
|
||||
content_by_lua_block { ngx.say(ngx.quote_sql_str('hello\n\r\'"\\')) }
|
||||
--- stream_response
|
||||
'hello\n\r\'\"\\'
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 8: nginx quote sql string 2
|
||||
--- stream_server_config
|
||||
content_by_lua_block { ngx.say(ngx.quote_sql_str("hello\n\r'\"\\")) }
|
||||
--- stream_response
|
||||
'hello\n\r\'\"\\'
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 9: multiple eof
|
||||
--- stream_server_config
|
||||
content_by_lua_block {
|
||||
ngx.say("Hi")
|
||||
|
||||
local ok, err = ngx.eof()
|
||||
if not ok then
|
||||
ngx.log(ngx.WARN, "eof failed: ", err)
|
||||
return
|
||||
end
|
||||
|
||||
ok, err = ngx.eof()
|
||||
if not ok then
|
||||
ngx.log(ngx.WARN, "eof failed: ", err)
|
||||
return
|
||||
end
|
||||
}
|
||||
--- stream_response
|
||||
Hi
|
||||
--- no_error_log
|
||||
[error]
|
||||
--- error_log
|
||||
lua send eof
|
||||
eof failed: seen eof
|
||||
|
||||
|
||||
|
||||
=== TEST 10: ngx.eof before ngx.say
|
||||
--- stream_server_config
|
||||
content_by_lua_block {
|
||||
local ok, err = ngx.eof()
|
||||
if not ok then
|
||||
ngx.log(ngx.ERR, "eof failed: ", err)
|
||||
return
|
||||
end
|
||||
|
||||
ok, err = ngx.say(ngx.headers_sent)
|
||||
if not ok then
|
||||
ngx.log(ngx.WARN, "failed to say: ", err)
|
||||
return
|
||||
end
|
||||
}
|
||||
--- stream_response
|
||||
--- no_error_log
|
||||
[error]
|
||||
--- error_log
|
||||
failed to say: seen eof
|
||||
|
||||
|
||||
|
||||
=== TEST 11: ngx.print table arguments (github issue #54)
|
||||
--- stream_server_config
|
||||
content_by_lua_block { ngx.print({10, {0, 5}, 15}, 32) }
|
||||
--- stream_response chop
|
||||
10051532
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 12: ngx.say table arguments (github issue #54)
|
||||
--- stream_server_config
|
||||
content_by_lua_block { ngx.say({10, {0, "5"}, 15}, 32) }
|
||||
--- stream_response
|
||||
10051532
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 13: Lua file does not exist
|
||||
--- stream_server_config
|
||||
content_by_lua_file html/test2.lua;
|
||||
--- user_files
|
||||
>>> test.lua
|
||||
v = ngx.var["request_uri"]
|
||||
ngx.print("request_uri: ", v, "\n")
|
||||
--- stream_response
|
||||
--- error_log eval
|
||||
qr/failed to load external Lua file ".*?test2\.lua": cannot open .*? No such file or directory/
|
||||
|
||||
|
||||
|
||||
=== TEST 14: .lua file with shebang
|
||||
--- stream_server_config
|
||||
content_by_lua_file html/test.lua;
|
||||
--- user_files
|
||||
>>> test.lua
|
||||
#!/bin/lua
|
||||
|
||||
ngx.say("line ", debug.getinfo(1).currentline)
|
||||
--- stream_response
|
||||
line 3
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 15: syntax error in inlined Lua code
|
||||
--- stream_server_config
|
||||
content_by_lua_block {for end}
|
||||
--- stream_response
|
||||
--- error_log eval
|
||||
qr/failed to load inlined Lua code: /
|
|
@ -0,0 +1,38 @@
|
|||
# vim:set ft= ts=4 sw=4 et fdm=marker:
|
||||
|
||||
use Test::Nginx::Socket::Lua::Stream;
|
||||
|
||||
repeat_each(2);
|
||||
|
||||
plan tests => blocks() * (repeat_each() * 3);
|
||||
|
||||
#$ENV{LUA_PATH} = $ENV{HOME} . '/work/JSON4Lua-0.9.30/json/?.lua';
|
||||
|
||||
no_long_string();
|
||||
|
||||
run_tests();
|
||||
|
||||
__DATA__
|
||||
|
||||
=== TEST 1: syntax error in lua code chunk
|
||||
--- stream_server_config
|
||||
content_by_lua_block {local a
|
||||
a = a+;
|
||||
return a}
|
||||
--- stream_response
|
||||
--- error_log eval
|
||||
qr/failed to load inlined Lua code: content_by_lua\(nginx\.conf:\d+\):2: unexpected symbol near ';'/
|
||||
|
||||
|
||||
|
||||
=== TEST 2: syntax error in lua file
|
||||
--- stream_server_config
|
||||
content_by_lua_file 'html/test.lua';
|
||||
--- user_files
|
||||
>>> test.lua
|
||||
local a
|
||||
a = 3 +;
|
||||
return a
|
||||
--- stream_response
|
||||
--- error_log eval
|
||||
qr{failed to load external Lua file ".*?html/test\.lua": .*?test\.lua:2: unexpected symbol near ';'}
|
|
@ -0,0 +1,157 @@
|
|||
# vim:set ft= ts=4 sw=4 et fdm=marker:
|
||||
|
||||
use Test::Nginx::Socket::Lua::Stream;
|
||||
|
||||
#worker_connections(1014);
|
||||
#log_level('warn');
|
||||
|
||||
#master_on();
|
||||
#repeat_each(120);
|
||||
repeat_each(2);
|
||||
|
||||
plan tests => blocks() * (repeat_each() * 3);
|
||||
|
||||
our $HtmlDir = html_dir;
|
||||
#warn $html_dir;
|
||||
|
||||
#$ENV{LUA_PATH} = "$html_dir/?.lua";
|
||||
|
||||
#no_diff();
|
||||
no_long_string();
|
||||
run_tests();
|
||||
|
||||
__DATA__
|
||||
|
||||
=== TEST 1: sanity
|
||||
--- stream_config eval
|
||||
"lua_package_path '$::HtmlDir/?.lua;./?.lua;;';"
|
||||
--- stream_server_config
|
||||
# load
|
||||
content_by_lua_block {
|
||||
package.loaded.foo = nil;
|
||||
collectgarbage()
|
||||
local foo = require "foo";
|
||||
foo.hi()
|
||||
}
|
||||
|
||||
--- stream_server_config2
|
||||
# check
|
||||
content_by_lua_block {
|
||||
local foo = package.loaded.foo
|
||||
if foo then
|
||||
ngx.say("found")
|
||||
foo.hi()
|
||||
else
|
||||
ngx.say("not found")
|
||||
end
|
||||
}
|
||||
|
||||
--- stream_server_config3
|
||||
# check
|
||||
content_by_lua_block {
|
||||
local foo = package.loaded.foo
|
||||
if foo then
|
||||
ngx.say("found")
|
||||
foo.hi()
|
||||
else
|
||||
ngx.say("not found")
|
||||
end
|
||||
}
|
||||
--- user_files
|
||||
>>> foo.lua
|
||||
local _M = {}
|
||||
|
||||
ngx.say("loading");
|
||||
|
||||
function _M.hi ()
|
||||
ngx.say("hello, foo")
|
||||
end
|
||||
|
||||
return _M
|
||||
--- stream_response
|
||||
loading
|
||||
hello, foo
|
||||
found
|
||||
hello, foo
|
||||
found
|
||||
hello, foo
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 2: sanity
|
||||
--- stream_config eval
|
||||
"lua_package_cpath '$::HtmlDir/?.so';"
|
||||
--- stream_server_config
|
||||
content_by_lua_block {
|
||||
ngx.print(package.cpath);
|
||||
}
|
||||
--- stream_response_like: ^[^;]+/servroot(_\d+)?/html/\?\.so$
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 3: expand default path (after)
|
||||
--- stream_config eval
|
||||
"lua_package_path '$::HtmlDir/?.lua;;';"
|
||||
--- stream_server_config
|
||||
content_by_lua_block {
|
||||
ngx.print(package.path)
|
||||
}
|
||||
--- stream_response_like: ^[^;]+/servroot(_\d+)?/html/\?\.lua;(.+\.lua)?;*$
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 4: expand default cpath (after)
|
||||
--- stream_config eval
|
||||
"lua_package_cpath '$::HtmlDir/?.so;;';"
|
||||
--- stream_server_config
|
||||
content_by_lua_block {
|
||||
ngx.print(package.cpath)
|
||||
}
|
||||
--- stream_response_like: ^[^;]+/servroot(_\d+)?/html/\?\.so;(.+\.so)?;*$
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 5: expand default path (before)
|
||||
--- stream_config eval
|
||||
"lua_package_path ';;$::HtmlDir/?.lua';"
|
||||
--- stream_server_config
|
||||
content_by_lua_block {
|
||||
ngx.print(package.path);
|
||||
}
|
||||
--- stream_response_like: ^(.+\.lua)?;*?[^;]+/servroot(_\d+)?/html/\?\.lua$
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 6: expand default cpath (before)
|
||||
--- stream_config eval
|
||||
"lua_package_cpath ';;$::HtmlDir/?.so';"
|
||||
--- stream_server_config
|
||||
content_by_lua_block {
|
||||
ngx.print(package.cpath);
|
||||
}
|
||||
--- stream_response_like: ^(.+\.so)?;*?[^;]+/servroot(_\d+)?/html/\?\.so$
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 7: require "ngx" (content_by_lua_block)
|
||||
--- stream_server_config
|
||||
content_by_lua_block {
|
||||
local ngx = require "ngx"
|
||||
ngx.say("hello, world")
|
||||
}
|
||||
--- stream_response
|
||||
hello, world
|
||||
--- no_error_log
|
||||
[error]
|
|
@ -0,0 +1,114 @@
|
|||
# vim:set ft= ts=4 sw=4 et fdm=marker:
|
||||
|
||||
use Test::Nginx::Socket::Lua::Stream;
|
||||
|
||||
#repeat_each(20000);
|
||||
repeat_each(2);
|
||||
#master_on();
|
||||
#workers(1);
|
||||
#log_level('debug');
|
||||
#log_level('warn');
|
||||
#worker_connections(1024);
|
||||
|
||||
plan tests => repeat_each() * (blocks() * 3);
|
||||
|
||||
$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211;
|
||||
$ENV{TEST_NGINX_MYSQL_PORT} ||= 3306;
|
||||
|
||||
our $LuaCpath = $ENV{LUA_CPATH} ||
|
||||
'/usr/local/openresty-debug/lualib/?.so;/usr/local/openresty/lualib/?.so;;';
|
||||
|
||||
#$ENV{LUA_PATH} = $ENV{HOME} . '/work/JSON4Lua-0.9.30/json/?.lua';
|
||||
|
||||
no_long_string();
|
||||
|
||||
run_tests();
|
||||
|
||||
__DATA__
|
||||
|
||||
=== TEST 1: throw error
|
||||
--- stream_server_config
|
||||
content_by_lua_block { ngx.exit(ngx.ERROR);ngx.say('hi') }
|
||||
--- stream_response
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 2: throw error after sending the header and partial body
|
||||
--- stream_server_config
|
||||
content_by_lua_block { ngx.say('hi');ngx.exit(ngx.ERROR);ngx.say(', you') }
|
||||
--- no_error_log
|
||||
[error]
|
||||
--- stream_response
|
||||
hi
|
||||
|
||||
|
||||
|
||||
=== TEST 3: throw 0
|
||||
--- stream_server_config
|
||||
content_by_lua_block { ngx.say('Hi'); ngx.eof(); ngx.exit(0);ngx.say('world') }
|
||||
--- stream_response
|
||||
Hi
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 4: pcall safe
|
||||
--- stream_server_config
|
||||
content_by_lua_block {
|
||||
function f ()
|
||||
ngx.say("hello")
|
||||
ngx.exit(200)
|
||||
end
|
||||
|
||||
pcall(f)
|
||||
ngx.say("world")
|
||||
}
|
||||
--- stream_response
|
||||
hello
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 5: throw 444 after sending out responses
|
||||
--- stream_server_config
|
||||
content_by_lua_block {
|
||||
ngx.say('ok');
|
||||
return ngx.exit(444)
|
||||
}
|
||||
--- stream_response
|
||||
ok
|
||||
--- log_level: debug
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 6: throw 499 after sending out responses
|
||||
--- stream_server_config
|
||||
content_by_lua_block {
|
||||
ngx.say('ok');
|
||||
return ngx.exit(499)
|
||||
}
|
||||
--- stream_response
|
||||
ok
|
||||
--- log_level: debug
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 7: throw 408 after sending out responses
|
||||
--- stream_server_config
|
||||
content_by_lua_block {
|
||||
ngx.say('ok');
|
||||
return ngx.exit(408)
|
||||
}
|
||||
--- stream_response
|
||||
ok
|
||||
--- log_level: debug
|
||||
--- no_error_log
|
||||
[error]
|
|
@ -0,0 +1,173 @@
|
|||
# vim:set ft= ts=4 sw=4 et fdm=marker:
|
||||
|
||||
use Test::Nginx::Socket::Lua::Stream;
|
||||
|
||||
repeat_each(2);
|
||||
|
||||
plan tests => repeat_each() * (blocks() * 3 + 3);
|
||||
|
||||
no_long_string();
|
||||
|
||||
run_tests();
|
||||
|
||||
__DATA__
|
||||
|
||||
=== TEST 1: escape uri in content_by_lua
|
||||
--- stream_server_config
|
||||
content_by_lua_block {ngx.say(ngx.escape_uri('a 你'))}
|
||||
--- stream_response
|
||||
a%20%E4%BD%A0
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 2: unescape uri in content_by_lua
|
||||
--- stream_server_config
|
||||
content_by_lua_block { ngx.say(ngx.unescape_uri('a%20%e4%bd%a0')) }
|
||||
--- stream_response
|
||||
a 你
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 3: escape uri in content_by_lua
|
||||
--- stream_server_config
|
||||
content_by_lua_block { ngx.say(ngx.escape_uri('a+b')) }
|
||||
--- stream_response
|
||||
a%2Bb
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 4: escape uri in content_by_lua
|
||||
--- stream_server_config
|
||||
content_by_lua_block { ngx.say(ngx.escape_uri('"a/b={}:<>;&[]\\^')) }
|
||||
--- stream_response
|
||||
%22a%2Fb%3D%7B%7D%3A%3C%3E%3B%26%5B%5D%5C%5E
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 5: escape a string that cannot be escaped
|
||||
--- stream_server_config
|
||||
content_by_lua_block { ngx.say(ngx.escape_uri('abc')) }
|
||||
--- stream_response
|
||||
abc
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 6: escape an empty string that cannot be escaped
|
||||
--- stream_server_config
|
||||
content_by_lua_block { ngx.say(ngx.escape_uri('')) }
|
||||
--- stream_response eval: "\n"
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 7: escape nil
|
||||
--- stream_server_config
|
||||
content_by_lua_block { ngx.say("[", ngx.escape_uri(nil), "]") }
|
||||
--- stream_response
|
||||
[]
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 8: escape numbers
|
||||
--- stream_server_config
|
||||
content_by_lua_block { ngx.say(ngx.escape_uri(32)) }
|
||||
--- stream_response
|
||||
32
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 9: unescape nil
|
||||
--- stream_server_config
|
||||
content_by_lua_block { ngx.say("[", ngx.unescape_uri(nil), "]") }
|
||||
--- stream_response
|
||||
[]
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 10: unescape numbers
|
||||
--- stream_server_config
|
||||
content_by_lua_block { ngx.say(ngx.unescape_uri(32)) }
|
||||
--- stream_response
|
||||
32
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 11: escape type
|
||||
--- stream_server_config
|
||||
content_by_lua_block {
|
||||
ngx.say(ngx.escape_uri("https://www.google.com/?t=abc@ :", 0))
|
||||
ngx.say(ngx.escape_uri("https://www.google.com/?t=abc@ :", 1))
|
||||
ngx.say(ngx.escape_uri("https://www.google.com/?t=abc@ :", 2))
|
||||
ngx.say(ngx.escape_uri("https://www.google.com/?t=abc@ :", 3))
|
||||
ngx.say(ngx.escape_uri("https://www.google.com/?t=abc@ :", 4))
|
||||
ngx.say(ngx.escape_uri("https://www.google.com/?t=abc@ :", 5))
|
||||
ngx.say(ngx.escape_uri("https://www.google.com/?t=abc@ :", 6))
|
||||
}
|
||||
--- stream_response
|
||||
https://www.google.com/%3Ft=abc@%20:
|
||||
https://www.google.com/%3Ft=abc@%20:
|
||||
https%3A%2F%2Fwww.google.com%2F%3Ft%3Dabc%40%20%3A
|
||||
https://www.google.com/?t=abc@%20:
|
||||
https://www.google.com/?t=abc@%20:
|
||||
https://www.google.com/?t=abc@%20:
|
||||
https://www.google.com/?t=abc@%20:
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 12: escape type error
|
||||
--- stream_server_config
|
||||
content_by_lua_block {
|
||||
ngx.say(ngx.escape_uri("https://www.google.com/?t=abc@ :", true))
|
||||
}
|
||||
--- stream_response
|
||||
--- error_log eval
|
||||
qr/\[error\] \d+#\d+: \*\d+ lua entry thread aborted: runtime error: "type" is not a number/
|
||||
--- no_error_log
|
||||
[alert]
|
||||
|
||||
|
||||
|
||||
=== TEST 13: escape type out of range
|
||||
--- stream_server_config
|
||||
content_by_lua_block {
|
||||
ngx.say(ngx.escape_uri("https://www.google.com/?t=abc@ :", -1))
|
||||
}
|
||||
--- stream_response
|
||||
--- error_log eval
|
||||
qr/\[error\] \d+#\d+: \*\d+ lua entry thread aborted: runtime error: "type" -1 out of range/
|
||||
--- no_error_log
|
||||
[alert]
|
||||
|
||||
|
||||
|
||||
=== TEST 14: escape type error
|
||||
--- stream_server_config
|
||||
content_by_lua_block {
|
||||
ngx.say(ngx.escape_uri("https://www.google.com/?t=abc@ :", 100))
|
||||
}
|
||||
--- stream_response
|
||||
--- error_log eval
|
||||
qr/\[error\] \d+#\d+: \*\d+ lua entry thread aborted: runtime error: "type" 100 out of range/
|
||||
--- no_error_log
|
||||
[alert]
|
|
@ -0,0 +1,55 @@
|
|||
# vim:set ft= ts=4 sw=4 et fdm=marker:
|
||||
|
||||
use Test::Nginx::Socket::Lua::Stream;
|
||||
|
||||
#worker_connections(1014);
|
||||
#master_process_enabled(1);
|
||||
log_level('warn');
|
||||
|
||||
repeat_each(2);
|
||||
|
||||
plan tests => repeat_each() * (blocks() * 3);
|
||||
|
||||
#no_diff();
|
||||
#no_long_string();
|
||||
run_tests();
|
||||
|
||||
__DATA__
|
||||
|
||||
=== TEST 1: set md5 hello
|
||||
--- stream_server_config
|
||||
content_by_lua_block { ngx.say(ngx.md5("hello")) }
|
||||
--- stream_response
|
||||
5d41402abc4b2a76b9719d911017c592
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 2: nil string to ngx.md5
|
||||
--- stream_server_config
|
||||
content_by_lua_block { ngx.say(ngx.md5(nil)) }
|
||||
--- stream_response
|
||||
d41d8cd98f00b204e9800998ecf8427e
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 3: empty string to ngx.md5
|
||||
--- stream_server_config
|
||||
content_by_lua_block { ngx.say(ngx.md5("")) }
|
||||
--- stream_response
|
||||
d41d8cd98f00b204e9800998ecf8427e
|
||||
--- no_error_log
|
||||
[error]
|
||||
|
||||
|
||||
|
||||
=== TEST 4: md5(number)
|
||||
--- stream_server_config
|
||||
content_by_lua_block { ngx.say(ngx.md5(45)) }
|
||||
--- stream_response
|
||||
6c8349cc7260ae62e3b1396831a8398f
|
||||
--- no_error_log
|
||||
[error]
|
|
@ -0,0 +1,24 @@
|
|||
# vim:set ft= ts=4 sw=4 et fdm=marker:
|
||||
|
||||
use Test::Nginx::Socket::Lua::Stream;
|
||||
|
||||
#worker_connections(1014);
|
||||
#master_process_enabled(1);
|
||||
log_level('warn');
|
||||
|
||||
repeat_each(2);
|
||||
|
||||
plan tests => repeat_each() * (blocks() * 3);
|
||||
|
||||
#no_diff();
|
||||
#no_long_string();
|
||||
run_tests();
|
||||
|
||||
__DATA__
|
||||
|
||||
=== TEST 1: use ngx.today in content_by_lua*
|
||||
--- stream_server_config
|
||||
content_by_lua_block { ngx.say(ngx.today()) }
|
||||
--- stream_response_like: ^\d{4}-\d{2}-\d{2}$
|
||||
--- no_error_log
|
||||
[error]
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue