init work on stream support

This commit is contained in:
bunkerity 2023-02-21 18:41:45 +01:00
parent 79036e9751
commit 4f4c8ebf08
244 changed files with 98944 additions and 35 deletions

View File

@ -353,7 +353,10 @@ utils.rand = function(nb)
return result
end
utils.get_deny_status = function()
utils.get_deny_status = function(stream)
if stream then
return 403
end
local status, err = datastore:get("variable_DENY_HTTP_STATUS")
if not status then
logger.log(ngx.ERR, "UTILS", "Can't get DENY_HTTP_STATUS variable " .. err)

View File

@ -1,4 +1,4 @@
# /etc/nginx/base_http.conf
# /etc/nginx/http.conf
# zero copy within the kernel
sendfile on;
@ -67,7 +67,7 @@ server_tokens off;
{% if MULTISITE == "yes" and SERVER_NAME != "" %}
{% set map_servers = {} %}
{% for server_name in SERVER_NAME.split(" ") %}
{% if server_name + "_SERVER_NAME" in all %}
{% if server_name + "_SERVER_NAME" in all and all[server_name + "_SERVER_TYPE"] == "http" %}
{% set x = map_servers.update({server_name : all[server_name + "_SERVER_NAME"].split(" ")}) %}
{% endif %}
{% endfor %}
@ -79,7 +79,7 @@ server_tokens off;
{% set x = found.update({"res" : true}) %}
{% endif %}
{% endfor %}
{% if not found["res"] %}
{% if not found["res"] and all[server_name + "_SERVER_TYPE"] == "stream" %}
{% set x = map_servers.update({server_name : [server_name]}) %}
{% endif %}
{% endif %}
@ -87,6 +87,6 @@ server_tokens off;
{% for first_server in map_servers +%}
include /etc/nginx/{{ first_server }}/server.conf;
{% endfor %}
{% elif MULTISITE == "no" and SERVER_NAME != "" +%}
{% elif MULTISITE == "no" and SERVER_NAME != "" and SERVER_TYPE == "http" +%}
include /etc/nginx/server.conf;
{% endif %}

View File

@ -46,13 +46,13 @@ http {
include /etc/bunkerweb/configs/http/*.conf;
}
#stream {
stream {
# include base stream configuration
# include /etc/nginx/stream.conf;
include /etc/nginx/stream.conf;
# include core and plugins stream configurations
# include /etc/nginx/stream/*.conf;
include /etc/nginx/stream/*.conf;
# include custom stream configurations
# include /etc/bunkerweb/configs/stream/*.conf;
#}
include /etc/bunkerweb/configs/stream/*.conf;
}

View File

@ -0,0 +1,44 @@
log_by_lua_block {
local utils = require "utils"
local logger = require "logger"
local datastore = require "datastore"
local plugins = require "plugins"
logger.log(ngx.INFO, "LOG", "Log phase started")
-- List all plugins
local list, err = plugins:list()
if not list then
logger.log(ngx.ERR, "LOG", "Can't list loaded plugins : " .. err)
list = {}
end
-- Call log method of plugins
for i, plugin in ipairs(list) do
local ret, plugin_lua = pcall(require, plugin.id .. "/" .. plugin.id)
if ret then
local plugin_obj = plugin_lua.new()
if plugin_obj.log ~= nil then
logger.log(ngx.INFO, "LOG", "Executing log() of " .. plugin.id)
local ok, err = plugin_obj:log()
if not ok then
logger.log(ngx.ERR, "LOG", "Error while calling log() on plugin " .. plugin.id .. " : " .. err)
else
logger.log(ngx.INFO, "LOG", "Return value from " .. plugin.id .. ".log() is : " .. err)
end
else
logger.log(ngx.INFO, "LOG", "log() method not found in " .. plugin.id .. ", skipped execution")
end
end
end
-- Display reason at info level
local reason = utils.get_reason()
if reason then
logger.log(ngx.INFO, "LOG", "Client was denied with reason : " .. reason)
end
logger.log(ngx.INFO, "LOG", "Log phase ended")
}

View File

@ -0,0 +1,86 @@
preread_by_lua_block {
local logger = require "logger"
local datastore = require "datastore"
local plugins = require "plugins"
local utils = require "utils"
logger.log(ngx.INFO, "PREREAD", "Preread phase started")
-- Process bans as soon as possible
local banned, err = datastore:get("bans_ip_" .. ngx.var.remote_addr)
if banned then
logger.log(ngx.WARN, "PREREAD", "IP " .. ngx.var.remote_addr .. " is banned with reason : " .. banned)
ngx.exit(utils.get_deny_status(true))
end
-- Redis case
local use_redis = utils.get_variable("USE_REDIS")
if use_redis == "yes" then
-- Connect
local redis_client, err = clusterstore:connect()
if not redis_client then
logger.log(ngx.ERR, "PREREAD", "can't connect to redis server : " .. err)
else
-- Get ban
local ban, err = redis_client:get("ban_" .. ngx.var.remote_addr)
if err then
logger.log(ngx.ERR, "PREREAD", "GET failed : " .. err)
elseif ban then
-- Get TTL
local ttl, err = redis_client:ttl("ban_" .. ngx.var.remote_addr)
if not ttl then
logger.log(ngx.ERR, "PREREAD", "TTL failed : " .. err)
else
local ok, err = datastore:set("bans_ip_" .. ip, ban, ttl)
if not ok then
logger.log(ngx.ERR, "PREREAD", "can't save ban to the datastore : " .. err)
return
end
end
end
redis_client:close()
end
end
-- List all plugins
local list, err = plugins:list()
if not list then
logger.log(ngx.ERR, "PREREAD", "Can't list loaded plugins : " .. err)
list = {}
end
-- Call preread method of plugins
for i, plugin in ipairs(list) do
local ret, plugin_lua = pcall(require, plugin.id .. "/" .. plugin.id)
if ret then
local plugin_obj = plugin_lua.new()
if plugin_obj.preread ~= nil then
logger.log(ngx.INFO, "PREREAD", "Executing preread() of " .. plugin.id)
local ok, err, ret, value = plugin_obj:preread()
if not ok then
logger.log(ngx.ERR, "PREREAD", "Error while calling preread() on plugin " .. plugin.id .. " : " .. err)
else
logger.log(ngx.INFO, "PREREAD", "Return value from " .. plugin.id .. ".preread() is : " .. err)
end
if ret then
if type(value) == "number" then
if value == utils.get_deny_status(true) then
logger.log(ngx.WARN, "PREREAD", "Denied access from " .. plugin.id .. " : " .. err)
ngx.var.reason = plugin.id
else
logger.log(ngx.NOTICE, "PREREAD", plugin.id .. " returned status " .. tostring(value) .. " : " .. err)
end
return ngx.exit(value)
else
return value
end
end
else
logger.log(ngx.INFO, "PREREAD", "preread() method not found in " .. plugin.id .. ", skipped execution")
end
end
end
logger.log(ngx.INFO, "PREREAD", "Preread phase ended")
}

View File

@ -0,0 +1,23 @@
server {
# listen
{% if LISTEN_STREAM == "yes" +%}
listen 0.0.0.0:{{ LISTEN_STREAM_PORT }}{% if USE_UDP == "yes" %} udp {% endif %}{% if USE_PROXY_PROTOCOL == "yes" %} proxy_protocol {% endif %};
{% endif %}
# custom config
include /etc/bunkerweb/configs/server-stream/*.conf;
{% if MULTISITE == "yes" +%}
include /etc/bunkerweb/configs/server-stream/{{ SERVER_NAME.split(" ")[0] }}/*.conf;
{% endif %}
# reason variable
set $reason '';
# include LUA files
include {{ NGINX_PREFIX }}preread-stream-lua.conf;
include {{ NGINX_PREFIX }}log-stream-lua.conf;
# include config files
include {{ NGINX_PREFIX }}server-stream/*.conf;
}

View File

@ -1,52 +1,44 @@
# /etc/nginx/stream.conf
# size of the preread buffer
# preread buffer size
# TODO : global setting STREAM_PREREAD_BUFFER_SIZE
preread_buffer_size 16k;
# timeout of the preread phase
# preread timeout
# TODO : global setting STREAM_PREREAD_TIMEOUT
preread_timeout 30s;
# proxy protocol timeout
# PROXY protocol timeout
# TODO : global setting STREAM_PROXY_PROTOCOL_TIMEOUT
proxy_protocol_timeout 30s;
# resolvers to use
resolver {{ DNS_RESOLVERS }} ipv6=off;
# resolver timeout
# TODO : global setting STREAM_RESOLVER_TIMEOUT
resolver_timeout 30s;
# remove 200ms delay
tcp_nodelay on;
# bucket hash size
variables_hash_bucket_size 64;
variables_hash_max_size 1024;
# log format and level
log_format proxy '$remote_addr [$time_local] '
'$protocol $status $bytes_sent $bytes_received '
'$session_time "$upstream_addr" '
'"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"';
access_log /var/log/nginx/access.log proxy;
# lua path and dicts
lua_package_path "/usr/share/bunkerweb/lua/?.lua;/usr/share/bunkerweb/core/?.lua;/etc/bunkerweb/plugins/?.lua;/usr/share/bunkerweb/deps/lib/lua/?.lua;;";
lua_package_cpath "/usr/share/bunkerweb/deps/lib/?.so;/usr/share/bunkerweb/deps/lib/lua/?.so;;";
lua_ssl_trusted_certificate "/usr/share/bunkerweb/misc/root-ca.pem";
lua_ssl_verify_depth 2;
lua_shared_dict datastore 256m;
lua_shared_dict datastore {{ DATASTORE_MEMORY_SIZE }};
# LUA init block
include /etc/nginx/init-lua.conf;
include /etc/nginx/init-stream-lua.conf;
# default server when MULTISITE=yes
{% if MULTISITE == "yes" %}include /etc/nginx/multisite-default-server.conf;{% endif +%}
# TODO add default stream server if that makes any sense ?
# server config(s)
{% if MULTISITE == "yes" and SERVER_NAME != "" %}
{% set map_servers = {} %}
{% for server_name in SERVER_NAME.split(" ") %}
{% if server_name + "_SERVER_NAME" in all %}
{% if server_name + "_SERVER_NAME" in all and all[server_name + "_SERVER_TYPE"] == "stream" %}
{% set x = map_servers.update({server_name : all[server_name + "_SERVER_NAME"].split(" ")}) %}
{% endif %}
{% endfor %}
@ -58,14 +50,14 @@ include /etc/nginx/init-lua.conf;
{% set x = found.update({"res" : true}) %}
{% endif %}
{% endfor %}
{% if not found["res"] %}
{% if not found["res"] and all[server_name + "_SERVER_TYPE"] == "stream" %}
{% set x = map_servers.update({server_name : [server_name]}) %}
{% endif %}
{% endif %}
{% endif %}
{% endfor %}
{% for first_server in map_servers +%}
include /etc/nginx/{{ first_server }}/server.conf;
include /etc/nginx/{{ first_server }}/server-stream.conf;
{% endfor %}
{% elif MULTISITE == "no" +%}
include /etc/nginx/server.conf;
{% elif MULTISITE == "no" and SERVER_NAME != "" and SERVER_TYPE == "stream" +%}
include /etc/nginx/server-stream.conf;
{% endif %}

View File

@ -81,6 +81,10 @@ function _M:access()
return true, "client IP " .. ngx.var.remote_addr .. " is not blacklisted (country = " .. country .. ")", nil, nil
end
function _M:preread()
return self:access()
end
function _M:is_in_cache(ip)
local data, err = datastore:get("plugin_country_cache_" .. ip)
if not data then

View File

@ -0,0 +1,5 @@
{% if USE_LIMIT_CONN == "yes" +%}
limit_conn sips {{ LIMIT_CONN_MAX_STREAM }};
{% endif %}

View File

@ -0,0 +1,6 @@
{% if has_variable(all, "USE_LIMIT_CONN", "yes") +%}
limit_conn_zone $binary_remote_addr zone=sips:10m;
limit_conn_log_level warn;
{% endif %}

View File

@ -0,0 +1,10 @@
{% if USE_REAL_IP == "yes" +%}
{% for element in read_lines("/var/cache/bunkerweb/realip/combined.list") +%}
set_real_ip_from {{ element }};
{% endfor +%}
{% if REAL_IP_FROM != "" %}
{% for element in REAL_IP_FROM.split(" ") +%}
set_real_ip_from {{ element }};
{% endfor %}
{% endif %}
{% endif %}

View File

@ -0,0 +1,11 @@
{% if USE_REVERSE_PROXY == "yes" +%}
# TODO : more settings specific to stream
{% if REVERSE_PROXY_STREAM_PROXY_PROTOCOL == "yes" +%}
proxy_protocol on;
{% endif +%}
set $backend{{ counter.value }} "{{ host }}";
proxy_pass $backend{{ counter.value }};
{% endif %}

View File

@ -288,3 +288,7 @@ git_secure_clone "https://github.com/google/ngx_brotli.git" "6e975bcb015f62e1f30
# ngx_devel_kit
echo " Downloading ngx_devel_kit"
git_secure_clone "https://github.com/vision5/ngx_devel_kit.git" "b4642d6ca01011bd8cd30b253f5c3872b384fd21"
# stream-lua-nginx-module
echo " Downloading stream-lua-nginx-module"
git_secure_clone "https://github.com/openresty/stream-lua-nginx-module.git" "2ef14f373b991b911c4eb5d09aa333352be9a756"

View File

@ -132,7 +132,7 @@ if [ "$OS" = "fedora" ] ; then
CONFARGS="$(echo -n "$CONFARGS" | sed "s/--with-ld-opt='.*'/--with-ld-opt=-lpcre/" | sed "s/--with-cc-opt='.*'//")"
fi
echo '#!/bin/bash' > "/tmp/bunkerweb/deps/src/nginx-${NGINX_VERSION}/configure-fix.sh"
echo "./configure $CONFARGS --add-dynamic-module=/tmp/bunkerweb/deps/src/ModSecurity-nginx --add-dynamic-module=/tmp/bunkerweb/deps/src/headers-more-nginx-module --add-dynamic-module=/tmp/bunkerweb/deps/src/nginx_cookie_flag_module --add-dynamic-module=/tmp/bunkerweb/deps/src/lua-nginx-module --add-dynamic-module=/tmp/bunkerweb/deps/src/ngx_brotli --add-dynamic-module=/tmp/bunkerweb/deps/src/ngx_devel_kit" >> "/tmp/bunkerweb/deps/src/nginx-${NGINX_VERSION}/configure-fix.sh"
echo "./configure $CONFARGS --add-dynamic-module=/tmp/bunkerweb/deps/src/ModSecurity-nginx --add-dynamic-module=/tmp/bunkerweb/deps/src/headers-more-nginx-module --add-dynamic-module=/tmp/bunkerweb/deps/src/nginx_cookie_flag_module --add-dynamic-module=/tmp/bunkerweb/deps/src/lua-nginx-module --add-dynamic-module=/tmp/bunkerweb/deps/src/ngx_brotli --add-dynamic-module=/tmp/bunkerweb/deps/src/ngx_devel_kit --add-dynamic-module=/tmp/bunkerweb/deps/src/stream-lua-nginx-module" >> "/tmp/bunkerweb/deps/src/nginx-${NGINX_VERSION}/configure-fix.sh"
do_and_check_cmd chmod +x "/tmp/bunkerweb/deps/src/nginx-${NGINX_VERSION}/configure-fix.sh"
CHANGE_DIR="/tmp/bunkerweb/deps/src/nginx-${NGINX_VERSION}" LUAJIT_LIB="/usr/share/bunkerweb/deps/lib -Wl,-rpath,/usr/share/bunkerweb/deps/lib" LUAJIT_INC="/usr/share/bunkerweb/deps/include/luajit-2.1" MODSECURITY_LIB="/usr/share/bunkerweb/deps/lib" MODSECURITY_INC="/usr/share/bunkerweb/deps/include" do_and_check_cmd ./configure-fix.sh
CHANGE_DIR="/tmp/bunkerweb/deps/src/nginx-${NGINX_VERSION}" do_and_check_cmd make -j $NTASK modules

View File

@ -0,0 +1 @@
*.t linguist-language=Text

View File

@ -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

View File

@ -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

View File

@ -0,0 +1,104 @@
sudo: required
dist: bionic
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

View File

@ -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.

View File

@ -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 &lt;path-to-lua-script-file&gt;*
**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&#42;, ngx.timer.&#42;, ssl_certificate_by_lua&#42;*
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&#42;*
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&#42;*
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)

View File

@ -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"

View File

@ -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 12
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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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_ */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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*");
}

View File

@ -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: */

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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_ */

View File

@ -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: */

View File

@ -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);
}

View File

@ -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_ */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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

View File

@ -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: */

View File

@ -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: */

View File

@ -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

View File

@ -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

View File

@ -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: */

View File

@ -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 */

View File

@ -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

View File

@ -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: */

View File

@ -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 */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

View File

@ -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: */

Some files were not shown because too many files have changed in this diff Show More