├── .gitmodules ├── t ├── .gitignore ├── data │ └── fake-module │ │ ├── config │ │ └── ngx_http_fake_module.c ├── 000-sanity.t ├── cert │ ├── test.crl │ ├── test.key │ ├── test.crt │ └── equifax.crt ├── 114-config.t ├── 119-config-prefix.t ├── 125-configure-args.t ├── 046-hmac.t ├── 008-today.t ├── 019-const.t ├── 103-req-http-ver.t ├── 021-cookie-time.t ├── 121-version.t ├── 042-crc32.t ├── 130-internal-api.t ├── 105-pressure.t ├── 070-sha1.t ├── 074-prefix-var.t ├── 115-quote-sql-str.t ├── 078-hup-vars.t ├── 123-lua-path.t ├── 076-no-postpone.t ├── 032-iolist.t ├── 029-http-time.t ├── 092-eof.t ├── 122-worker.t ├── 080-hup-shdict.t ├── 069-null.t ├── 110-etag.t ├── 000--init.t ├── 072-conditional-get.t ├── 007-md5.t ├── lib │ └── ljson.lua ├── 090-log-socket-errors.t ├── 102-req-start-time.t ├── 012-now.t ├── 064-pcall.t ├── 024-access │ ├── redirect.t │ ├── auth.t │ └── request_body.t ├── 023-rewrite │ ├── redirect.t │ └── request_body.t ├── 117-raw-req-socket-timeout.t ├── 118-use-default-type.t ├── 003-errors.t ├── 112-req-header-conn.t ├── 083-bad-sock-self.t ├── 051-sub-jit.t ├── 053-gsub-jit.t ├── 089-phase.t ├── 006-escape.t ├── 059-unix-socket.t ├── 018-ndk.t ├── 022-redirect.t ├── 026-mysql.t └── 048-match-dfa.t ├── .gitattributes ├── misc └── recv-until-pm │ ├── Makefile │ └── t │ └── sanity.t ├── tapset └── ngx_lua.stp ├── util ├── retab ├── update-readme.sh ├── releng ├── run_test.sh ├── gen-lexer-c ├── fix-comments ├── ngx-links ├── reindex ├── revim └── build2.sh ├── src ├── ngx_http_lua_phase.h ├── ngx_http_lua_lex.h ├── ngx_http_lua_worker.h ├── ngx_http_lua_config.h ├── ngx_http_lua_req_method.h ├── ngx_http_lua_ndk.h ├── ngx_http_lua_log.h ├── ngx_http_lua_misc.h ├── ngx_http_lua_sleep.h ├── ngx_http_lua_timer.h ├── ngx_http_lua_string.h ├── ngx_http_lua_uri.h ├── ngx_http_lua_consts.h ├── ngx_http_lua_req_body.h ├── ngx_http_lua_variable.h ├── ngx_http_lua_regex.h ├── ngx_http_lua_control.h ├── ngx_http_lua_capturefilter.h ├── ngx_http_lua_args.h ├── ngx_http_lua_setby.h ├── ngx_http_lua_time.h ├── ngx_http_lua_pcrefix.h ├── ngx_http_lua_headers_in.h ├── ngx_http_lua_initby.h ├── ngx_http_lua_headers.h ├── ngx_http_lua_ctx.h ├── ngx_http_lua_accessby.h ├── ngx_http_lua_clfactory.h ├── ngx_http_lua_logby.h ├── ngx_http_lua_rewriteby.h ├── ngx_http_lua_coroutine.h ├── ngx_http_lua_headers_out.h ├── ngx_http_lua_initworkerby.h ├── ngx_http_lua_cache.h ├── ngx_http_lua_output.h ├── ngx_http_lua_headerfilterby.h ├── ngx_http_lua_exception.h ├── ngx_http_lua_contentby.h ├── ngx_http_lua_bodyfilterby.h ├── ngx_http_lua_initby.c ├── ngx_http_lua_uthread.h ├── api │ └── ngx_http_lua_api.h ├── ngx_http_lua_worker.c ├── ngx_http_lua_subrequest.h ├── ngx_http_lua_exception.c ├── ngx_http_lua_config.c ├── ngx_http_lua_shdict.h ├── ngx_http_lua_socket_udp.h ├── ngx_http_lua_api.c ├── ddebug.h ├── ngx_http_lua_phase.c ├── ngx_http_lua_script.h ├── ngx_http_lua_pcrefix.c ├── ngx_http_lua_uri.c ├── ngx_http_lua_directive.h └── ngx_http_lua_probe.h ├── dtrace └── ngx_lua_provider.d ├── .gitignore ├── valgrind.suppress └── Changes /.gitmodules: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /t/.gitignore: -------------------------------------------------------------------------------- 1 | servroot 2 | 3 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.t linguist-language=Text 2 | -------------------------------------------------------------------------------- /misc/recv-until-pm/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | prove -Ilib -r t 3 | 4 | -------------------------------------------------------------------------------- /tapset/ngx_lua.stp: -------------------------------------------------------------------------------- 1 | function ngx_http_lua_ctx_context(r) 2 | { 3 | 4 | } 5 | 6 | -------------------------------------------------------------------------------- /util/retab: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | for f in $*; do 4 | if [ -f "$f" ]; then 5 | vim -c retab -c x $f 6 | fi 7 | done 8 | 9 | -------------------------------------------------------------------------------- /util/update-readme.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | perl util/wiki2pod.pl doc/manpage.wiki > /tmp/a.pod && pod2text /tmp/a.pod > README 4 | 5 | -------------------------------------------------------------------------------- /t/data/fake-module/config: -------------------------------------------------------------------------------- 1 | ngx_addon_name=ngx_http_fake_module 2 | HTTP_MODULES="$HTTP_MODULES ngx_http_fake_module" 3 | NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_fake_module.c" 4 | -------------------------------------------------------------------------------- /util/releng: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ./update-readme 4 | ack '(?<=\#define)\s*DDEBUG\s*1' src 5 | echo ==================================================== 6 | ack '(?<=_version_string) "\d+\.\d+\.\d+"' src 7 | ack '(?<=This document describes rds-json-nginx-module v)\d+\.\d+' README 8 | 9 | -------------------------------------------------------------------------------- /util/run_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | script_dir=$(dirname $0) 3 | root=$(readlink -f $script_dir/..) 4 | testfile=${1:-$root/t/*.t $root/t/*/*.t} 5 | cd $root 6 | $script_dir/reindex $testfile 7 | export PATH=$root/work/sbin:$PATH 8 | killall nginx 9 | prove -I$root/../test-nginx/lib $testfile 10 | 11 | -------------------------------------------------------------------------------- /src/ngx_http_lua_phase.h: -------------------------------------------------------------------------------- 1 | #ifndef _NGX_HTTP_LUA_PHASE_H_INCLUDED_ 2 | #define _NGX_HTTP_LUA_PHASE_H_INCLUDED_ 3 | 4 | 5 | #include "ngx_http_lua_common.h" 6 | 7 | 8 | void ngx_http_lua_inject_phase_api(lua_State *L); 9 | 10 | 11 | #endif /* _NGX_HTTP_LUA_PHASE_H_INCLUDED_ */ 12 | 13 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 14 | -------------------------------------------------------------------------------- /src/ngx_http_lua_lex.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Yichun Zhang (agentzh) 4 | */ 5 | 6 | 7 | #ifndef _NGX_HTTP_LUA_LEX_H_INCLUDED_ 8 | #define _NGX_HTTP_LUA_LEX_H_INCLUDED_ 9 | 10 | 11 | #include "ngx_http_lua_common.h" 12 | 13 | 14 | int ngx_http_lua_lex(const u_char *const s, size_t len, int *const ovec); 15 | 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /src/ngx_http_lua_worker.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Yichun Zhang (agentzh) 4 | */ 5 | 6 | 7 | #ifndef _NGX_HTTP_LUA_WORKER_H_INCLUDED_ 8 | #define _NGX_HTTP_LUA_WORKER_H_INCLUDED_ 9 | 10 | 11 | #include "ngx_http_lua_common.h" 12 | 13 | 14 | void ngx_http_lua_inject_worker_api(lua_State *L); 15 | 16 | 17 | #endif /* _NGX_HTTP_LUA_WORKER_H_INCLUDED_ */ 18 | -------------------------------------------------------------------------------- /src/ngx_http_lua_config.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Yichun Zhang (agentzh) 4 | */ 5 | 6 | 7 | #ifndef _NGX_HTTP_LUA_CONFIG_H_INCLUDED_ 8 | #define _NGX_HTTP_LUA_CONFIG_H_INCLUDED_ 9 | 10 | 11 | #include "ngx_http_lua_common.h" 12 | 13 | 14 | void ngx_http_lua_inject_config_api(lua_State *L); 15 | 16 | 17 | #endif /* _NGX_HTTP_LUA_CONFIG_H_INCLUDED_ */ 18 | 19 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 20 | -------------------------------------------------------------------------------- /src/ngx_http_lua_req_method.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Yichun Zhang (agentzh) 4 | */ 5 | 6 | 7 | #ifndef _NGX_HTTP_LUA_METHOD_H_INCLUDED_ 8 | #define _NGX_HTTP_LUA_METHOD_H_INCLUDED_ 9 | 10 | 11 | #include "ngx_http_lua_common.h" 12 | 13 | 14 | void ngx_http_lua_inject_req_method_api(lua_State *L); 15 | 16 | 17 | #endif /* _NGX_HTTP_LUA_METHOD_H_INCLUDED_ */ 18 | 19 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 20 | -------------------------------------------------------------------------------- /src/ngx_http_lua_ndk.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Yichun Zhang (agentzh) 4 | */ 5 | 6 | 7 | #ifndef _NGX_HTTP_LUA_NDK_H_INCLUDED_ 8 | #define _NGX_HTTP_LUA_NDK_H_INCLUDED_ 9 | 10 | 11 | #include "ngx_http_lua_common.h" 12 | 13 | 14 | #if defined(NDK) && NDK 15 | void ngx_http_lua_inject_ndk_api(lua_State *L); 16 | #endif 17 | 18 | 19 | #endif /* _NGX_HTTP_LUA_NDK_H_INCLUDED_ */ 20 | 21 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 22 | -------------------------------------------------------------------------------- /src/ngx_http_lua_log.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Xiaozhe Wang (chaoslawful) 4 | * Copyright (C) Yichun Zhang (agentzh) 5 | */ 6 | 7 | 8 | #ifndef _NGX_HTTP_LUA_LOG_H_INCLUDED_ 9 | #define _NGX_HTTP_LUA_LOG_H_INCLUDED_ 10 | 11 | 12 | #include "ngx_http_lua_common.h" 13 | 14 | 15 | void ngx_http_lua_inject_log_api(lua_State *L); 16 | 17 | 18 | #endif /* _NGX_HTTP_LUA_LOG_H_INCLUDED_ */ 19 | 20 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 21 | -------------------------------------------------------------------------------- /src/ngx_http_lua_misc.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Xiaozhe Wang (chaoslawful) 4 | * Copyright (C) Yichun Zhang (agentzh) 5 | */ 6 | 7 | 8 | #ifndef _NGX_HTTP_LUA_MISC_H_INCLUDED_ 9 | #define _NGX_HTTP_LUA_MISC_H_INCLUDED_ 10 | 11 | 12 | #include "ngx_http_lua_common.h" 13 | 14 | 15 | void ngx_http_lua_inject_misc_api(lua_State *L); 16 | 17 | 18 | #endif /* _NGX_HTTP_LUA_MISC_H_INCLUDED_ */ 19 | 20 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 21 | -------------------------------------------------------------------------------- /src/ngx_http_lua_sleep.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Xiaozhe Wang (chaoslawful) 4 | * Copyright (C) Yichun Zhang (agentzh) 5 | */ 6 | 7 | 8 | #ifndef _NGX_HTTP_LUA_SLEEP_H_INCLUDED_ 9 | #define _NGX_HTTP_LUA_SLEEP_H_INCLUDED_ 10 | 11 | 12 | #include "ngx_http_lua_common.h" 13 | 14 | 15 | void ngx_http_lua_inject_sleep_api(lua_State *L); 16 | 17 | 18 | #endif /* _NGX_HTTP_LUA_SLEEP_H_INCLUDED_ */ 19 | 20 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 21 | -------------------------------------------------------------------------------- /src/ngx_http_lua_timer.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Xiaozhe Wang (chaoslawful) 4 | * Copyright (C) Yichun Zhang (agentzh) 5 | */ 6 | 7 | 8 | #ifndef _NGX_HTTP_LUA_TIMER_H_INCLUDED_ 9 | #define _NGX_HTTP_LUA_TIMER_H_INCLUDED_ 10 | 11 | 12 | #include "ngx_http_lua_common.h" 13 | 14 | 15 | void ngx_http_lua_inject_timer_api(lua_State *L); 16 | 17 | 18 | #endif /* _NGX_HTTP_LUA_TIMER_H_INCLUDED_ */ 19 | 20 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 21 | -------------------------------------------------------------------------------- /src/ngx_http_lua_string.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Xiaozhe Wang (chaoslawful) 4 | * Copyright (C) Yichun Zhang (agentzh) 5 | */ 6 | 7 | 8 | #ifndef _NGX_HTTP_LUA_STRING_H_INCLUDED_ 9 | #define _NGX_HTTP_LUA_STRING_H_INCLUDED_ 10 | 11 | 12 | #include "ngx_http_lua_common.h" 13 | 14 | 15 | void ngx_http_lua_inject_string_api(lua_State *L); 16 | 17 | 18 | #endif /* _NGX_HTTP_LUA_STRING_H_INCLUDED_ */ 19 | 20 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 21 | -------------------------------------------------------------------------------- /src/ngx_http_lua_uri.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Xiaozhe Wang (chaoslawful) 4 | * Copyright (C) Yichun Zhang (agentzh) 5 | */ 6 | 7 | 8 | #ifndef _NGX_HTTP_LUA_URI_H_INCLUDED_ 9 | #define _NGX_HTTP_LUA_URI_H_INCLUDED_ 10 | 11 | 12 | #include "ngx_http_lua_common.h" 13 | 14 | 15 | void ngx_http_lua_inject_req_uri_api(ngx_log_t *log, lua_State *L); 16 | 17 | 18 | #endif /* _NGX_HTTP_LUA_URI_H_INCLUDED_ */ 19 | 20 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 21 | -------------------------------------------------------------------------------- /src/ngx_http_lua_consts.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Yichun Zhang (agentzh) 4 | */ 5 | 6 | 7 | #ifndef _NGX_HTTP_LUA_CONSTS_H_INCLUDED_ 8 | #define _NGX_HTTP_LUA_CONSTS_H_INCLUDED_ 9 | 10 | 11 | #include "ngx_http_lua_common.h" 12 | 13 | 14 | void ngx_http_lua_inject_http_consts(lua_State *L); 15 | void ngx_http_lua_inject_core_consts(lua_State *L); 16 | 17 | 18 | #endif /* _NGX_HTTP_LUA_CONSTS_H_INCLUDED_ */ 19 | 20 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 21 | -------------------------------------------------------------------------------- /src/ngx_http_lua_req_body.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Xiaozhe Wang (chaoslawful) 4 | * Copyright (C) Yichun Zhang (agentzh) 5 | */ 6 | 7 | 8 | #ifndef _NGX_HTTP_LUA_REQ_BODY_H_INCLUDED_ 9 | #define _NGX_HTTP_LUA_REQ_BODY_H_INCLUDED_ 10 | 11 | 12 | #include "ngx_http_lua_common.h" 13 | 14 | 15 | void ngx_http_lua_inject_req_body_api(lua_State *L); 16 | 17 | 18 | #endif /* _NGX_HTTP_LUA_REQ_BODY_H_INCLUDED_ */ 19 | 20 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 21 | -------------------------------------------------------------------------------- /src/ngx_http_lua_variable.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Xiaozhe Wang (chaoslawful) 4 | * Copyright (C) Yichun Zhang (agentzh) 5 | */ 6 | 7 | 8 | #ifndef _NGX_HTTP_LUA_VARIABLE_H_INCLUDED_ 9 | #define _NGX_HTTP_LUA_VARIABLE_H_INCLUDED_ 10 | 11 | 12 | #include "ngx_http_lua_common.h" 13 | 14 | 15 | void ngx_http_lua_inject_variable_api(lua_State *L); 16 | 17 | 18 | #endif /* _NGX_HTTP_LUA_VARIABLE_H_INCLUDED_ */ 19 | 20 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 21 | -------------------------------------------------------------------------------- /src/ngx_http_lua_regex.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Yichun Zhang (agentzh) 4 | */ 5 | 6 | 7 | #ifndef _NGX_HTTP_LUA_REGEX_H_INCLUDED_ 8 | #define _NGX_HTTP_LUA_REGEX_H_INCLUDED_ 9 | 10 | 11 | #include "ngx_http_lua_common.h" 12 | #include "ngx_http_lua_script.h" 13 | 14 | 15 | #if (NGX_PCRE) 16 | void ngx_http_lua_inject_regex_api(lua_State *L); 17 | #endif 18 | 19 | 20 | #endif /* _NGX_HTTP_LUA_REGEX_H_INCLUDED_ */ 21 | 22 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 23 | -------------------------------------------------------------------------------- /src/ngx_http_lua_control.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Xiaozhe Wang (chaoslawful) 4 | * Copyright (C) Yichun Zhang (agentzh) 5 | */ 6 | 7 | 8 | #ifndef _NGX_HTTP_LUA_CONTROL_H_INCLUDED_ 9 | #define _NGX_HTTP_LUA_CONTROL_H_INCLUDED_ 10 | 11 | 12 | #include "ngx_http_lua_common.h" 13 | 14 | 15 | void ngx_http_lua_inject_control_api(ngx_log_t *log, lua_State *L); 16 | 17 | 18 | #endif /* _NGX_HTTP_LUA_CONTROL_H_INCLUDED_ */ 19 | 20 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 21 | -------------------------------------------------------------------------------- /src/ngx_http_lua_capturefilter.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Xiaozhe Wang (chaoslawful) 4 | * Copyright (C) Yichun Zhang (agentzh) 5 | */ 6 | 7 | 8 | #ifndef _NGX_HTTP_LUA_CAPTUREFILTER_H_INCLUDED_ 9 | #define _NGX_HTTP_LUA_CAPTUREFILTER_H_INCLUDED_ 10 | 11 | 12 | #include "ngx_http_lua_common.h" 13 | 14 | 15 | ngx_int_t ngx_http_lua_capture_filter_init(ngx_conf_t *cf); 16 | 17 | 18 | #endif /* NGX_HTTP_LUA_CAPTUREFILTER_H */ 19 | 20 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 21 | -------------------------------------------------------------------------------- /src/ngx_http_lua_args.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Yichun Zhang (agentzh) 4 | */ 5 | 6 | 7 | #ifndef _NGX_HTTP_LUA_ARGS_H_INCLUDED_ 8 | #define _NGX_HTTP_LUA_ARGS_H_INCLUDED_ 9 | 10 | 11 | #include "ngx_http_lua_common.h" 12 | 13 | 14 | void ngx_http_lua_inject_req_args_api(lua_State *L); 15 | int ngx_http_lua_parse_args(lua_State *L, u_char *buf, u_char *last, int max); 16 | 17 | 18 | #endif /* _NGX_HTTP_LUA_ARGS_H_INCLUDED_ */ 19 | 20 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 21 | -------------------------------------------------------------------------------- /src/ngx_http_lua_setby.h: -------------------------------------------------------------------------------- 1 | #ifndef _NGX_HTTP_LUA_SET_BY_H_INCLUDED_ 2 | #define _NGX_HTTP_LUA_SET_BY_H_INCLUDED_ 3 | 4 | #include "ngx_http_lua_common.h" 5 | 6 | 7 | ngx_int_t ngx_http_lua_set_by_chunk(lua_State *L, ngx_http_request_t *r, 8 | ngx_str_t *val, ngx_http_variable_value_t *args, size_t nargs, 9 | ngx_str_t *script); 10 | int ngx_http_lua_setby_param_get(lua_State *L); 11 | 12 | 13 | #endif /* _NGX_HTTP_LUA_SET_BY_H_INCLUDED_ */ 14 | 15 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 16 | -------------------------------------------------------------------------------- /src/ngx_http_lua_time.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Xiaozhe Wang (chaoslawful) 4 | * Copyright (C) Yichun Zhang (agentzh) 5 | */ 6 | 7 | 8 | #ifndef _NGX_HTTP_LUA_TIME_H_INCLUDED_ 9 | #define _NGX_HTTP_LUA_TIME_H_INCLUDED_ 10 | 11 | 12 | #include "ngx_http_lua_common.h" 13 | 14 | 15 | void ngx_http_lua_inject_time_api(lua_State *L); 16 | void ngx_http_lua_inject_req_time_api(lua_State *L); 17 | 18 | 19 | #endif /* _NGX_HTTP_LUA_TIME_H_INCLUDED_ */ 20 | 21 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 22 | -------------------------------------------------------------------------------- /src/ngx_http_lua_pcrefix.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Xiaozhe Wang (chaoslawful) 4 | * Copyright (C) Yichun Zhang (agentzh) 5 | */ 6 | 7 | 8 | #ifndef _NGX_HTTP_LUA_PCREFIX_H_INCLUDED_ 9 | #define _NGX_HTTP_LUA_PCREFIX_H_INCLUDED_ 10 | 11 | 12 | #include "ngx_http_lua_common.h" 13 | 14 | 15 | #if (NGX_PCRE) 16 | ngx_pool_t *ngx_http_lua_pcre_malloc_init(ngx_pool_t *pool); 17 | void ngx_http_lua_pcre_malloc_done(ngx_pool_t *old_pool); 18 | #endif 19 | 20 | 21 | #endif /* _NGX_HTTP_LUA_PCREFIX_H_INCLUDED_ */ 22 | 23 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 24 | -------------------------------------------------------------------------------- /src/ngx_http_lua_headers_in.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Xiaozhe Wang (chaoslawful) 4 | * Copyright (C) Yichun Zhang (agentzh) 5 | */ 6 | 7 | 8 | #ifndef _NGX_HTTP_LUA_HEADERS_IN_H_INCLUDED_ 9 | #define _NGX_HTTP_LUA_HEADERS_IN_H_INCLUDED_ 10 | 11 | 12 | #include 13 | #include "ngx_http_lua_common.h" 14 | 15 | 16 | ngx_int_t ngx_http_lua_set_input_header(ngx_http_request_t *r, ngx_str_t key, 17 | ngx_str_t value, unsigned override); 18 | 19 | 20 | #endif /* _NGX_HTTP_LUA_HEADERS_IN_H_INCLUDED_ */ 21 | 22 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 23 | -------------------------------------------------------------------------------- /src/ngx_http_lua_initby.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Yichun Zhang (agentzh) 4 | */ 5 | 6 | 7 | #ifndef _NGX_HTTP_LUA_INITBY_H_INCLUDED_ 8 | #define _NGX_HTTP_LUA_INITBY_H_INCLUDED_ 9 | 10 | 11 | #include "ngx_http_lua_common.h" 12 | 13 | 14 | ngx_int_t ngx_http_lua_init_by_inline(ngx_log_t *log, 15 | ngx_http_lua_main_conf_t *lmcf, lua_State *L); 16 | 17 | ngx_int_t ngx_http_lua_init_by_file(ngx_log_t *log, 18 | ngx_http_lua_main_conf_t *lmcf, lua_State *L); 19 | 20 | 21 | #endif /* _NGX_HTTP_LUA_INITBY_H_INCLUDED_ */ 22 | 23 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 24 | -------------------------------------------------------------------------------- /t/000-sanity.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket::Lua; 4 | 5 | repeat_each(2); 6 | 7 | plan tests => blocks() * repeat_each() * 2; 8 | 9 | run_tests(); 10 | 11 | __DATA__ 12 | 13 | === TEST 1: sanity (integer) 14 | --- config 15 | location /lua { 16 | echo 2; 17 | } 18 | --- request 19 | GET /lua 20 | --- response_body 21 | 2 22 | 23 | 24 | 25 | === TEST 2: sanity (string) 26 | --- config 27 | location /lua { 28 | echo "helloworld"; 29 | } 30 | --- request 31 | GET /lua 32 | --- response_body 33 | helloworld 34 | 35 | -------------------------------------------------------------------------------- /src/ngx_http_lua_headers.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Xiaozhe Wang (chaoslawful) 4 | * Copyright (C) Yichun Zhang (agentzh) 5 | */ 6 | 7 | 8 | #ifndef _NGX_HTTP_LUA_HEADERS_H_INCLUDED_ 9 | #define _NGX_HTTP_LUA_HEADERS_H_INCLUDED_ 10 | 11 | 12 | #include "ngx_http_lua_common.h" 13 | 14 | 15 | void ngx_http_lua_inject_resp_header_api(lua_State *L); 16 | void ngx_http_lua_inject_req_header_api(lua_State *L); 17 | void ngx_http_lua_create_headers_metatable(ngx_log_t *log, lua_State *L); 18 | 19 | 20 | #endif /* _NGX_HTTP_LUA_HEADERS_H_INCLUDED_ */ 21 | 22 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 23 | -------------------------------------------------------------------------------- /src/ngx_http_lua_ctx.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Xiaozhe Wang (chaoslawful) 4 | * Copyright (C) Yichun Zhang (agentzh) 5 | */ 6 | 7 | 8 | #ifndef _NGX_HTTP_LUA_CTX_H_INCLUDED_ 9 | #define _NGX_HTTP_LUA_CTX_H_INCLUDED_ 10 | 11 | 12 | #include "ngx_http_lua_common.h" 13 | 14 | 15 | int ngx_http_lua_ngx_get_ctx(lua_State *L); 16 | int ngx_http_lua_ngx_set_ctx(lua_State *L); 17 | int ngx_http_lua_ngx_set_ctx_helper(lua_State *L, ngx_http_request_t *r, 18 | ngx_http_lua_ctx_t *ctx, int index); 19 | 20 | 21 | #endif /* _NGX_HTTP_LUA_CTX_H_INCLUDED_ */ 22 | 23 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 24 | -------------------------------------------------------------------------------- /src/ngx_http_lua_accessby.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Xiaozhe Wang (chaoslawful) 4 | * Copyright (C) Yichun Zhang (agentzh) 5 | */ 6 | 7 | 8 | #ifndef _NGX_HTTP_LUA_ACCESSBY_H_INCLUDED_ 9 | #define _NGX_HTTP_LUA_ACCESSBY_H_INCLUDED_ 10 | 11 | 12 | #include "ngx_http_lua_common.h" 13 | 14 | 15 | ngx_int_t ngx_http_lua_access_handler(ngx_http_request_t *r); 16 | ngx_int_t ngx_http_lua_access_handler_inline(ngx_http_request_t *r); 17 | ngx_int_t ngx_http_lua_access_handler_file(ngx_http_request_t *r); 18 | 19 | 20 | #endif /* _NGX_HTTP_LUA_ACCESSBY_H_INCLUDED_ */ 21 | 22 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 23 | -------------------------------------------------------------------------------- /src/ngx_http_lua_clfactory.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Xiaozhe Wang (chaoslawful) 4 | * Copyright (C) Yichun Zhang (agentzh) 5 | */ 6 | 7 | 8 | #ifndef _NGX_HTTP_LUA_CLFACTORY_H_INCLUDED_ 9 | #define _NGX_HTTP_LUA_CLFACTORY_H_INCLUDED_ 10 | 11 | 12 | #include "ngx_http_lua_common.h" 13 | 14 | 15 | ngx_int_t ngx_http_lua_clfactory_loadfile(lua_State *L, const char *filename); 16 | ngx_int_t ngx_http_lua_clfactory_loadbuffer(lua_State *L, const char *buff, 17 | size_t size, const char *name); 18 | 19 | 20 | #endif /* _NGX_HTTP_LUA_CLFACTORY_H_INCLUDED_ */ 21 | 22 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 23 | -------------------------------------------------------------------------------- /src/ngx_http_lua_logby.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Yichun Zhang (agentzh) 4 | */ 5 | 6 | 7 | #ifndef _NGX_HTTP_LUA_LOGBY_H_INCLUDED_ 8 | #define _NGX_HTTP_LUA_LOGBY_H_INCLUDED_ 9 | 10 | 11 | #include "ngx_http_lua_common.h" 12 | 13 | 14 | ngx_int_t ngx_http_lua_log_handler(ngx_http_request_t *r); 15 | ngx_int_t ngx_http_lua_log_handler_inline(ngx_http_request_t *r); 16 | ngx_int_t ngx_http_lua_log_handler_file(ngx_http_request_t *r); 17 | void ngx_http_lua_inject_logby_ngx_api(ngx_conf_t *cf, lua_State *L); 18 | 19 | 20 | #endif /* _NGX_HTTP_LUA_LOGBY_H_INCLUDED_ */ 21 | 22 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 23 | -------------------------------------------------------------------------------- /src/ngx_http_lua_rewriteby.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Xiaozhe Wang (chaoslawful) 4 | * Copyright (C) Yichun Zhang (agentzh) 5 | */ 6 | 7 | 8 | #ifndef _NGX_HTTP_LUA_REWRITEBY_H_INCLUDED_ 9 | #define _NGX_HTTP_LUA_REWRITEBY_H_INCLUDED_ 10 | 11 | 12 | #include "ngx_http_lua_common.h" 13 | 14 | 15 | ngx_int_t ngx_http_lua_rewrite_handler(ngx_http_request_t *r); 16 | ngx_int_t ngx_http_lua_rewrite_handler_inline(ngx_http_request_t *r); 17 | ngx_int_t ngx_http_lua_rewrite_handler_file(ngx_http_request_t *r); 18 | 19 | 20 | #endif /* _NGX_HTTP_LUA_REWRITEBY_H_INCLUDED_ */ 21 | 22 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 23 | -------------------------------------------------------------------------------- /t/cert/test.crl: -------------------------------------------------------------------------------- 1 | -----BEGIN X509 CRL----- 2 | MIIBjzCB+QIBATANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UEBhMCVVMxEzARBgNV 3 | BAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xEjAQBgNVBAoM 4 | CU9wZW5SZXN0eTESMBAGA1UECwwJT3BlblJlc3R5MREwDwYDVQQDDAh0ZXN0LmNv 5 | bTEgMB4GCSqGSIb3DQEJARYRYWdlbnR6aEBnbWFpbC5jb20XDTE0MDcyMTIxNDEy 6 | MloXDTE0MDgyMDIxNDEyMlowHDAaAgkApQ5tVpK3luIXDTE0MDcyMTIxNDEwMlqg 7 | DzANMAsGA1UdFAQEAgIQATANBgkqhkiG9w0BAQUFAAOBgQBDZ6UY0Qg7qDoLrXXl 8 | gJElFilZ7LiKPqjE3+Rfx7XkgdbPxjGCr77TfMm+smdvawk7WHv1AOvRH7kGrgGT 9 | kGJZwqJ4vKa/NpEWJIMAZ1Gq9BIH/Ig6ffmPk+S9ozcVHKJDW7x4nMuotyj1hILN 10 | EePv78DZCYMZgf8WwMElNgz6Hw== 11 | -----END X509 CRL----- 12 | -------------------------------------------------------------------------------- /src/ngx_http_lua_coroutine.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Xiaozhe Wang (chaoslawful) 4 | * Copyright (C) Yichun Zhang (agentzh) 5 | */ 6 | 7 | 8 | #ifndef _NGX_HTTP_LUA_COROUTINE_H_INCLUDED_ 9 | #define _NGX_HTTP_LUA_COROUTINE_H_INCLUDED_ 10 | 11 | 12 | #include "ngx_http_lua_common.h" 13 | 14 | 15 | void ngx_http_lua_inject_coroutine_api(ngx_log_t *log, lua_State *L); 16 | 17 | int ngx_http_lua_coroutine_create_helper(lua_State *L, ngx_http_request_t *r, 18 | ngx_http_lua_ctx_t *ctx, ngx_http_lua_co_ctx_t **pcoctx); 19 | 20 | 21 | #endif /* _NGX_HTTP_LUA_COROUTINE_H_INCLUDED_ */ 22 | 23 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 24 | -------------------------------------------------------------------------------- /src/ngx_http_lua_headers_out.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Xiaozhe Wang (chaoslawful) 4 | * Copyright (C) Yichun Zhang (agentzh) 5 | */ 6 | 7 | 8 | #ifndef _NGX_HTTP_LUA_HEADERS_OUT_H_INCLUDED_ 9 | #define _NGX_HTTP_LUA_HEADERS_OUT_H_INCLUDED_ 10 | 11 | 12 | #include "ngx_http_lua_common.h" 13 | 14 | 15 | ngx_int_t ngx_http_lua_set_output_header(ngx_http_request_t *r, ngx_str_t key, 16 | ngx_str_t value, unsigned override); 17 | int ngx_http_lua_get_output_header(lua_State *L, ngx_http_request_t *r, 18 | ngx_str_t *key); 19 | 20 | 21 | #endif /* _NGX_HTTP_LUA_HEADERS_OUT_H_INCLUDED_ */ 22 | 23 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 24 | -------------------------------------------------------------------------------- /t/114-config.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | use Test::Nginx::Socket::Lua; 3 | 4 | #worker_connections(1014); 5 | #master_on(); 6 | #workers(2); 7 | #log_level('warn'); 8 | 9 | repeat_each(2); 10 | 11 | plan tests => repeat_each() * (blocks() * 3); 12 | 13 | #no_diff(); 14 | #no_long_string(); 15 | run_tests(); 16 | 17 | __DATA__ 18 | 19 | === TEST 1: ngx.config.debug 20 | --- config 21 | location /t { 22 | content_by_lua ' 23 | ngx.say("debug: ", ngx.config.debug) 24 | '; 25 | } 26 | --- request 27 | GET /t 28 | --- response_body_like chop 29 | ^debug: (?:true|false)$ 30 | --- no_error_log 31 | [error] 32 | 33 | -------------------------------------------------------------------------------- /util/gen-lexer-c: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [ -z "$1" ]; then 4 | level=0 5 | else 6 | level="$1" 7 | fi 8 | 9 | #echo '{' '}' '\[=*\[' '--\[=*\[' '\]=*\]' '--[^\n]*' '"(?:\\[^\n]|[^"\n\\])*"' $'\'(?:\\\\[^\\n]|[^\'\\n\\\\])*\'' 10 | 11 | # we need the re.pl script here: 12 | # https://github.com/openresty/sregex/blob/dfa-multi-re/re.pl 13 | re.pl -W --no-main -c --cc="clang -O2" \ 14 | --func-name ngx_http_lua_lex \ 15 | --header ngx_http_lua_lex.h -o src/ngx_http_lua_lex.c \ 16 | --debug=$level -n 8 \ 17 | -- '{' '}' '\[=*\[' '--\[=*\[' '\]=*\]' '--[^\n]*' '"(?:\\[^\n]|[^"\n\\])*"' $'\'(?:\\\\[^\\n]|[^\'\\n\\\\])*\'' \ 18 | || exit 1 19 | -------------------------------------------------------------------------------- /util/fix-comments: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | use strict; 4 | use warnings; 5 | 6 | for my $infile (@ARGV) { 7 | warn "Processing $infile...\n"; 8 | open my $in, $infile or 9 | die "Cannot open $infile for reading: $!\n"; 10 | my $s; 11 | my $changed = 0; 12 | while (<$in>) { 13 | $changed += s{//(.*)}{/* $1 */}; 14 | $s .= $_; 15 | } 16 | close $in; 17 | 18 | if ($changed) { 19 | my $outfile = $infile; 20 | open my $out, ">$outfile" or 21 | die "Cannot open $outfile for writing: $!\n"; 22 | print $out $s; 23 | close $out; 24 | warn "Wrote $outfile\n"; 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /t/119-config-prefix.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | use Test::Nginx::Socket::Lua; 3 | 4 | #worker_connections(1014); 5 | #master_on(); 6 | #workers(2); 7 | #log_level('warn'); 8 | 9 | repeat_each(2); 10 | #repeat_each(1); 11 | 12 | plan tests => repeat_each() * (blocks() * 3); 13 | 14 | #no_diff(); 15 | #no_long_string(); 16 | run_tests(); 17 | 18 | __DATA__ 19 | 20 | === TEST 1: content_by_lua 21 | --- config 22 | location /lua { 23 | content_by_lua ' 24 | ngx.say("prefix: ", ngx.config.prefix()) 25 | '; 26 | } 27 | --- request 28 | GET /lua 29 | --- response_body_like chop 30 | ^prefix: \/\S+$ 31 | --- no_error_log 32 | [error] 33 | 34 | -------------------------------------------------------------------------------- /t/125-configure-args.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | use Test::Nginx::Socket::Lua; 3 | 4 | #worker_connections(1014); 5 | #master_on(); 6 | #workers(2); 7 | #log_level('warn'); 8 | 9 | repeat_each(2); 10 | 11 | plan tests => repeat_each() * (blocks() * 3); 12 | 13 | #no_diff(); 14 | #no_long_string(); 15 | run_tests(); 16 | 17 | __DATA__ 18 | 19 | === TEST 1: nginx configure 20 | --- config 21 | location /configure_args { 22 | content_by_lua ' 23 | ngx.say(ngx.config.nginx_configure()) 24 | '; 25 | } 26 | --- request 27 | GET /configure_args 28 | --- response_body_like chop 29 | ^\s*\-\-[^-]+ 30 | --- no_error_log 31 | [error] 32 | 33 | -------------------------------------------------------------------------------- /src/ngx_http_lua_initworkerby.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Yichun Zhang (agentzh) 4 | */ 5 | 6 | 7 | #ifndef _NGX_HTTP_LUA_INITWORKERBY_H_INCLUDED_ 8 | #define _NGX_HTTP_LUA_INITWORKERBY_H_INCLUDED_ 9 | 10 | 11 | #include "ngx_http_lua_common.h" 12 | 13 | 14 | ngx_int_t ngx_http_lua_init_worker_by_inline(ngx_log_t *log, 15 | ngx_http_lua_main_conf_t *lmcf, lua_State *L); 16 | 17 | ngx_int_t ngx_http_lua_init_worker_by_file(ngx_log_t *log, 18 | ngx_http_lua_main_conf_t *lmcf, lua_State *L); 19 | 20 | ngx_int_t ngx_http_lua_init_worker(ngx_cycle_t *cycle); 21 | 22 | 23 | #endif /* _NGX_HTTP_LUA_INITWORKERBY_H_INCLUDED_ */ 24 | 25 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 26 | -------------------------------------------------------------------------------- /src/ngx_http_lua_cache.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Xiaozhe Wang (chaoslawful) 4 | * Copyright (C) Yichun Zhang (agentzh) 5 | */ 6 | 7 | 8 | #ifndef _NGX_HTTP_LUA_CACHE_H_INCLUDED_ 9 | #define _NGX_HTTP_LUA_CACHE_H_INCLUDED_ 10 | 11 | 12 | #include "ngx_http_lua_common.h" 13 | 14 | 15 | ngx_int_t ngx_http_lua_cache_loadbuffer(ngx_http_request_t *r, lua_State *L, 16 | const u_char *src, size_t src_len, const u_char *cache_key, 17 | const char *name); 18 | ngx_int_t ngx_http_lua_cache_loadfile(ngx_http_request_t *r, lua_State *L, 19 | const u_char *script, const u_char *cache_key); 20 | 21 | 22 | #endif /* _NGX_HTTP_LUA_CACHE_H_INCLUDED_ */ 23 | 24 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 25 | -------------------------------------------------------------------------------- /t/046-hmac.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | use Test::Nginx::Socket::Lua; 3 | 4 | #worker_connections(1014); 5 | #master_on(); 6 | #workers(2); 7 | #log_level('warn'); 8 | 9 | repeat_each(2); 10 | #repeat_each(1); 11 | 12 | plan tests => repeat_each() * (blocks() * 2); 13 | 14 | #no_diff(); 15 | #no_long_string(); 16 | run_tests(); 17 | 18 | __DATA__ 19 | 20 | === TEST 1: sanity 21 | --- config 22 | location /lua { 23 | content_by_lua ' 24 | local digest = ngx.hmac_sha1("thisisverysecretstuff", "some string we want to sign") 25 | ngx.say(ngx.encode_base64(digest)) 26 | '; 27 | } 28 | --- request 29 | GET /lua 30 | --- response_body 31 | R/pvxzHC4NLtj7S+kXFg/NePTmk= 32 | 33 | -------------------------------------------------------------------------------- /src/ngx_http_lua_output.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Xiaozhe Wang (chaoslawful) 4 | * Copyright (C) Yichun Zhang (agentzh) 5 | */ 6 | 7 | 8 | #ifndef _NGX_HTTP_LUA_OUTPUT_H_INCLUDED_ 9 | #define _NGX_HTTP_LUA_OUTPUT_H_INCLUDED_ 10 | 11 | 12 | #include "ngx_http_lua_common.h" 13 | 14 | 15 | void ngx_http_lua_inject_output_api(lua_State *L); 16 | 17 | size_t ngx_http_lua_calc_strlen_in_table(lua_State *L, int index, int arg_i, 18 | unsigned strict); 19 | 20 | u_char *ngx_http_lua_copy_str_in_table(lua_State *L, int index, u_char *dst); 21 | 22 | ngx_int_t ngx_http_lua_flush_resume_helper(ngx_http_request_t *r, 23 | ngx_http_lua_ctx_t *ctx); 24 | 25 | 26 | #endif /* _NGX_HTTP_LUA_OUTPUT_H_INCLUDED_ */ 27 | 28 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 29 | -------------------------------------------------------------------------------- /src/ngx_http_lua_headerfilterby.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Yichun Zhang (agentzh) 4 | */ 5 | 6 | 7 | #ifndef _NGX_HTTP_LUA_HEADERFILTERBY_H_INCLUDED_ 8 | #define _NGX_HTTP_LUA_HEADERFILTERBY_H_INCLUDED_ 9 | 10 | 11 | #include "ngx_http_lua_common.h" 12 | 13 | 14 | extern ngx_http_output_header_filter_pt ngx_http_lua_next_filter_header_filter; 15 | 16 | 17 | ngx_int_t ngx_http_lua_header_filter_init(void); 18 | 19 | ngx_int_t ngx_http_lua_header_filter_by_chunk(lua_State *L, 20 | ngx_http_request_t *r); 21 | 22 | ngx_int_t ngx_http_lua_header_filter_inline(ngx_http_request_t *r); 23 | 24 | ngx_int_t ngx_http_lua_header_filter_file(ngx_http_request_t *r); 25 | 26 | 27 | #endif /* _NGX_HTTP_LUA_HEADERFILTERBY_H_INCLUDED_ */ 28 | 29 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 30 | -------------------------------------------------------------------------------- /t/008-today.t: -------------------------------------------------------------------------------- 1 | # vim:set ft=perl ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket::Lua; 4 | 5 | #worker_connections(1014); 6 | #master_process_enabled(1); 7 | log_level('warn'); 8 | 9 | repeat_each(1); 10 | 11 | plan tests => repeat_each() * (blocks() * 2); 12 | 13 | #no_diff(); 14 | #no_long_string(); 15 | run_tests(); 16 | 17 | __DATA__ 18 | 19 | === TEST 1: use ngx.today in content_by_lua 20 | --- config 21 | location = /today { 22 | content_by_lua 'ngx.say(ngx.today())'; 23 | } 24 | --- request 25 | GET /today 26 | --- response_body_like: ^\d{4}-\d{2}-\d{2}$ 27 | 28 | 29 | 30 | === TEST 2: use ngx.today in set_by_lua 31 | --- config 32 | location = /today { 33 | set_by_lua $a 'return ngx.today()'; 34 | echo $a; 35 | } 36 | --- request 37 | GET /today 38 | --- response_body_like: ^\d{4}-\d{2}-\d{2}$ 39 | 40 | -------------------------------------------------------------------------------- /t/019-const.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket::Lua; 4 | 5 | repeat_each(2); 6 | 7 | plan tests => blocks() * repeat_each() * 2; 8 | 9 | #no_diff(); 10 | #no_long_string(); 11 | 12 | run_tests(); 13 | 14 | __DATA__ 15 | 16 | === TEST 1: sanity 17 | --- config 18 | location /read { 19 | content_by_lua ' 20 | ngx.say(ngx.OK) 21 | ngx.say(ngx.AGAIN) 22 | ngx.say(ngx.DONE) 23 | ngx.say(ngx.ERROR) 24 | '; 25 | } 26 | --- request 27 | GET /read 28 | --- response_body 29 | 0 30 | -2 31 | -4 32 | -1 33 | 34 | 35 | 36 | === TEST 2: http constants 37 | --- config 38 | location /read { 39 | content_by_lua ' 40 | ngx.say(ngx.HTTP_GATEWAY_TIMEOUT) 41 | '; 42 | } 43 | --- request 44 | GET /read 45 | --- response_body 46 | 504 47 | 48 | -------------------------------------------------------------------------------- /src/ngx_http_lua_exception.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Xiaozhe Wang (chaoslawful) 4 | * Copyright (C) Yichun Zhang (agentzh) 5 | */ 6 | 7 | 8 | #ifndef _NGX_HTTP_LUA_EXCEPTION_H_INCLUDED_ 9 | #define _NGX_HTTP_LUA_EXCEPTION_H_INCLUDED_ 10 | 11 | 12 | #include "ngx_http_lua_common.h" 13 | 14 | 15 | #define NGX_LUA_EXCEPTION_TRY \ 16 | if (setjmp(ngx_http_lua_exception) == 0) 17 | 18 | #define NGX_LUA_EXCEPTION_CATCH \ 19 | else 20 | 21 | #define NGX_LUA_EXCEPTION_THROW(x) \ 22 | longjmp(ngx_http_lua_exception, (x)) 23 | 24 | 25 | extern jmp_buf ngx_http_lua_exception; 26 | 27 | 28 | int ngx_http_lua_atpanic(lua_State *L); 29 | 30 | 31 | #endif /* _NGX_HTTP_LUA_EXCEPTION_H_INCLUDED_ */ 32 | 33 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 34 | -------------------------------------------------------------------------------- /src/ngx_http_lua_contentby.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Xiaozhe Wang (chaoslawful) 4 | * Copyright (C) Yichun Zhang (agentzh) 5 | */ 6 | 7 | 8 | #ifndef _NGX_HTTP_LUA_CONTENT_BY_H_INCLUDED_ 9 | #define _NGX_HTTP_LUA_CONTENT_BY_H_INCLUDED_ 10 | 11 | 12 | #include "ngx_http_lua_common.h" 13 | 14 | 15 | ngx_int_t ngx_http_lua_content_by_chunk(lua_State *l, ngx_http_request_t *r); 16 | void ngx_http_lua_content_wev_handler(ngx_http_request_t *r); 17 | ngx_int_t ngx_http_lua_content_handler_file(ngx_http_request_t *r); 18 | ngx_int_t ngx_http_lua_content_handler_inline(ngx_http_request_t *r); 19 | ngx_int_t ngx_http_lua_content_handler(ngx_http_request_t *r); 20 | ngx_int_t ngx_http_lua_content_run_posted_threads(lua_State *L, 21 | ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, int n); 22 | 23 | 24 | #endif /* _NGX_HTTP_LUA_CONTENT_BY_H_INCLUDED_ */ 25 | 26 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 27 | -------------------------------------------------------------------------------- /t/103-req-http-ver.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | use Test::Nginx::Socket::Lua; 3 | 4 | #worker_connections(1014); 5 | #master_on(); 6 | #workers(2); 7 | #log_level('warn'); 8 | 9 | repeat_each(2); 10 | #repeat_each(1); 11 | 12 | plan tests => repeat_each() * (blocks() * 3); 13 | 14 | #no_diff(); 15 | #no_long_string(); 16 | run_tests(); 17 | 18 | __DATA__ 19 | 20 | === TEST 1: HTTP 1.1 21 | --- config 22 | location /t { 23 | content_by_lua ' 24 | ngx.say(ngx.req.http_version()) 25 | '; 26 | } 27 | --- request 28 | GET /t 29 | --- response_body 30 | 1.1 31 | --- no_error_log 32 | [error] 33 | 34 | 35 | 36 | === TEST 2: HTTP 1.0 37 | --- config 38 | location /t { 39 | content_by_lua ' 40 | ngx.say(ngx.req.http_version()) 41 | '; 42 | } 43 | --- request 44 | GET /t HTTP/1.0 45 | --- response_body 46 | 1 47 | --- no_error_log 48 | [error] 49 | 50 | -------------------------------------------------------------------------------- /t/cert/test.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIICXgIBAAKBgQDo/XzNS+2ZopArbF4/LxlsXBLJMvD6Nbq315lqJN5zxfeJs31Z 3 | 6avEfORNGKTE/dwBCghNG5mJC8XhDsM7rAyTP9vTPB+Bfm550arTjsAk/qf+bCUM 4 | 6MZI2iYEuhdDOju1V7rSKQSbdnINSqck8ky3eEiY7ldKingw8y5lr1aEVwIDAQAB 5 | AoGBANgB66sKMga2SKN5nQdHS3LDCkevCutu1OWM5ZcbB4Kej5kC57xsf+tzPtab 6 | emeIVGhCPOAALqB4YcT+QtMX967oM1MjcFbtH7si5oq6UYyp3i0G9Si6jIoVHz3+ 7 | 8yOUaqwKbK+bRX8VS0YsHZmBsPK5ryN50iUwsU08nemoA94BAkEA9GS9Q5OPeFkM 8 | tFxsIQ1f2FSsZAuN/1cpZgJqY+YaAN7MSPGTWyfd7nWG/Zgk3GO9/2ihh4gww+7B 9 | To09GkmW4QJBAPQOHC2V+t2TA98+6Lj6+TYwcGEkhOENfVpH25mQ+kXgF/1Bd6rA 10 | nosT1bdAY+SnmWXbSw6Kv5C20Em+bEX8WjcCQCSRRjhsRdVODbaW9Z7kb2jhEoJN 11 | sEt6cTlQNzcHYPCsZYisjM3g4zYg47fiIfHQAsfKkhDDcfh/KvFj9LaQOEECQQCH 12 | eBWYEDpSJ7rsfqT7mQQgWj7nDThdG/nK1TxGP71McBmg0Gg2dfkLRhVJRQqt74Is 13 | kc9V4Rp4n6F6baL4Lh19AkEA6pZZer0kg3Kv9hjhaITIKUYdfIp9vYnDRWbQlBmR 14 | atV8V9u9q2ETZvqfHpN+9Lu6NYR4yXIEIRf1bnIZ/mr9eQ== 15 | -----END RSA PRIVATE KEY----- 16 | -------------------------------------------------------------------------------- /t/021-cookie-time.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket::Lua; 4 | 5 | #worker_connections(1014); 6 | #master_process_enabled(1); 7 | log_level('warn'); 8 | 9 | repeat_each(2); 10 | #repeat_each(1); 11 | 12 | plan tests => repeat_each() * (blocks() * 2); 13 | 14 | #no_diff(); 15 | #no_long_string(); 16 | run_tests(); 17 | 18 | __DATA__ 19 | 20 | === TEST 1: cookie_time 21 | --- config 22 | location /lua { 23 | content_by_lua ' 24 | ngx.say(ngx.cookie_time(1290079655)) 25 | '; 26 | } 27 | --- request 28 | GET /lua 29 | --- response_body 30 | Thu, 18-Nov-10 11:27:35 GMT 31 | 32 | 33 | 34 | === TEST 2: cookie_time in set_by_lua 35 | --- config 36 | location /lua { 37 | set_by_lua $a ' 38 | return ngx.cookie_time(1290079655) 39 | '; 40 | echo $a; 41 | } 42 | --- request 43 | GET /lua 44 | --- response_body 45 | Thu, 18-Nov-10 11:27:35 GMT 46 | 47 | -------------------------------------------------------------------------------- /src/ngx_http_lua_bodyfilterby.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Yichun Zhang (agentzh) 4 | */ 5 | 6 | 7 | #ifndef _NGX_HTTP_LUA_BODYFILTERBY_H_INCLUDED_ 8 | #define _NGX_HTTP_LUA_BODYFILTERBY_H_INCLUDED_ 9 | 10 | 11 | #include "ngx_http_lua_common.h" 12 | 13 | 14 | extern ngx_http_output_body_filter_pt ngx_http_lua_next_filter_body_filter; 15 | 16 | 17 | ngx_int_t ngx_http_lua_body_filter_init(void); 18 | ngx_int_t ngx_http_lua_body_filter_by_chunk(lua_State *L, 19 | ngx_http_request_t *r, ngx_chain_t *in); 20 | ngx_int_t ngx_http_lua_body_filter_inline(ngx_http_request_t *r, 21 | ngx_chain_t *in); 22 | ngx_int_t ngx_http_lua_body_filter_file(ngx_http_request_t *r, 23 | ngx_chain_t *in); 24 | int ngx_http_lua_body_filter_param_get(lua_State *L); 25 | int ngx_http_lua_body_filter_param_set(lua_State *L, ngx_http_request_t *r, 26 | ngx_http_lua_ctx_t *ctx); 27 | 28 | 29 | #endif /* _NGX_HTTP_LUA_BODYFILTERBY_H_INCLUDED_ */ 30 | 31 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 32 | -------------------------------------------------------------------------------- /t/121-version.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | use Test::Nginx::Socket::Lua; 3 | 4 | #worker_connections(1014); 5 | #master_on(); 6 | #workers(2); 7 | #log_level('warn'); 8 | 9 | repeat_each(2); 10 | #repeat_each(1); 11 | 12 | plan tests => repeat_each() * (blocks() * 3); 13 | 14 | #no_diff(); 15 | #no_long_string(); 16 | run_tests(); 17 | 18 | __DATA__ 19 | 20 | === TEST 1: nginx version 21 | --- config 22 | location /lua { 23 | content_by_lua ' 24 | ngx.say("version: ", ngx.config.nginx_version) 25 | '; 26 | } 27 | --- request 28 | GET /lua 29 | --- response_body_like chop 30 | ^version: \d+$ 31 | --- no_error_log 32 | [error] 33 | 34 | 35 | 36 | === TEST 2: ngx_lua_version 37 | --- config 38 | location /lua { 39 | content_by_lua ' 40 | ngx.say("version: ", ngx.config.ngx_lua_version) 41 | '; 42 | } 43 | --- request 44 | GET /lua 45 | --- response_body_like chop 46 | ^version: \d+$ 47 | --- no_error_log 48 | [error] 49 | 50 | -------------------------------------------------------------------------------- /t/cert/test.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICqTCCAhICCQClDm1WkreW4jANBgkqhkiG9w0BAQUFADCBlzELMAkGA1UEBhMC 3 | VVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28x 4 | EjAQBgNVBAoMCU9wZW5SZXN0eTESMBAGA1UECwwJT3BlblJlc3R5MREwDwYDVQQD 5 | DAh0ZXN0LmNvbTEgMB4GCSqGSIb3DQEJARYRYWdlbnR6aEBnbWFpbC5jb20wIBcN 6 | MTQwNzIxMDMyMzQ3WhgPMjE1MTA2MTMwMzIzNDdaMIGXMQswCQYDVQQGEwJVUzET 7 | MBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzESMBAG 8 | A1UECgwJT3BlblJlc3R5MRIwEAYDVQQLDAlPcGVuUmVzdHkxETAPBgNVBAMMCHRl 9 | c3QuY29tMSAwHgYJKoZIhvcNAQkBFhFhZ2VudHpoQGdtYWlsLmNvbTCBnzANBgkq 10 | hkiG9w0BAQEFAAOBjQAwgYkCgYEA6P18zUvtmaKQK2xePy8ZbFwSyTLw+jW6t9eZ 11 | aiTec8X3ibN9WemrxHzkTRikxP3cAQoITRuZiQvF4Q7DO6wMkz/b0zwfgX5uedGq 12 | 047AJP6n/mwlDOjGSNomBLoXQzo7tVe60ikEm3ZyDUqnJPJMt3hImO5XSop4MPMu 13 | Za9WhFcCAwEAATANBgkqhkiG9w0BAQUFAAOBgQA4OBb9bOyWB1//93nSXX1mdENZ 14 | IQeyTK0Dd6My76lnZxnZ4hTWrvvd0b17KLDU6JnS2N5ee3ATVkojPidRLWLIhnh5 15 | 0eXrcKalbO2Ce6nShoFvQCQKXN2Txmq2vO/Mud2bHAWwJALg+qi1Iih/gVYB9sct 16 | FLg8zFOzRlYiU+6Mmw== 17 | -----END CERTIFICATE----- 18 | -------------------------------------------------------------------------------- /src/ngx_http_lua_initby.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Yichun Zhang (agentzh) 4 | */ 5 | 6 | 7 | #ifndef DDEBUG 8 | #define DDEBUG 0 9 | #endif 10 | 11 | #include "ddebug.h" 12 | #include "ngx_http_lua_initby.h" 13 | #include "ngx_http_lua_util.h" 14 | 15 | 16 | ngx_int_t 17 | ngx_http_lua_init_by_inline(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf, 18 | lua_State *L) 19 | { 20 | int status; 21 | 22 | status = luaL_loadbuffer(L, (char *) lmcf->init_src.data, 23 | lmcf->init_src.len, "=init_by_lua") 24 | || ngx_http_lua_do_call(log, L); 25 | 26 | return ngx_http_lua_report(log, L, status, "init_by_lua"); 27 | } 28 | 29 | 30 | ngx_int_t 31 | ngx_http_lua_init_by_file(ngx_log_t *log, ngx_http_lua_main_conf_t *lmcf, 32 | lua_State *L) 33 | { 34 | int status; 35 | 36 | status = luaL_loadfile(L, (char *) lmcf->init_src.data) 37 | || ngx_http_lua_do_call(log, L); 38 | 39 | return ngx_http_lua_report(log, L, status, "init_by_lua_file"); 40 | } 41 | 42 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 43 | -------------------------------------------------------------------------------- /t/042-crc32.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | use Test::Nginx::Socket::Lua; 3 | 4 | #worker_connections(1014); 5 | #master_process_enabled(1); 6 | log_level('warn'); 7 | 8 | repeat_each(2); 9 | 10 | plan tests => repeat_each() * (blocks() * 2); 11 | 12 | #no_diff(); 13 | #no_long_string(); 14 | run_tests(); 15 | 16 | __DATA__ 17 | 18 | === TEST 1: short sanity 19 | --- config 20 | location = /test { 21 | content_by_lua ' 22 | ngx.say(ngx.crc32_short("hello, world")) 23 | '; 24 | } 25 | --- request 26 | GET /test 27 | --- response_body 28 | 4289425978 29 | 30 | 31 | 32 | === TEST 2: long sanity 33 | --- config 34 | location = /test { 35 | content_by_lua ' 36 | ngx.say(ngx.crc32_long("hello, world")) 37 | '; 38 | } 39 | --- request 40 | GET /test 41 | --- response_body 42 | 4289425978 43 | 44 | 45 | 46 | === TEST 3: long sanity (empty) 47 | --- config 48 | location = /test { 49 | content_by_lua ' 50 | ngx.say(ngx.crc32_long("")) 51 | '; 52 | } 53 | --- request 54 | GET /test 55 | --- response_body 56 | 0 57 | 58 | -------------------------------------------------------------------------------- /src/ngx_http_lua_uthread.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Yichun Zhang (agentzh) 4 | */ 5 | 6 | 7 | #ifndef _NGX_HTTP_LUA_UTHREAD_H_INCLUDED_ 8 | #define _NGX_HTTP_LUA_UTHREAD_H_INCLUDED_ 9 | 10 | 11 | #include "ngx_http_lua_common.h" 12 | 13 | 14 | #define ngx_http_lua_is_thread(ctx) \ 15 | ((ctx)->cur_co_ctx->is_uthread || (ctx)->cur_co_ctx == &(ctx)->entry_co_ctx) 16 | 17 | 18 | #define ngx_http_lua_is_entry_thread(ctx) \ 19 | ((ctx)->cur_co_ctx == &(ctx)->entry_co_ctx) 20 | 21 | 22 | #define ngx_http_lua_entry_thread_alive(ctx) \ 23 | ((ctx)->entry_co_ctx.co_ref != LUA_NOREF) 24 | 25 | 26 | #define ngx_http_lua_coroutine_alive(coctx) \ 27 | ((coctx)->co_status != NGX_HTTP_LUA_CO_DEAD \ 28 | && (coctx)->co_status != NGX_HTTP_LUA_CO_ZOMBIE) 29 | 30 | 31 | void ngx_http_lua_inject_uthread_api(ngx_log_t *log, lua_State *L); 32 | 33 | 34 | #endif /* _NGX_HTTP_LUA_UTHREAD_H_INCLUDED_ */ 35 | 36 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 37 | -------------------------------------------------------------------------------- /t/130-internal-api.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket::Lua; 4 | 5 | #worker_connections(1014); 6 | #master_process_enabled(1); 7 | #log_level('warn'); 8 | 9 | repeat_each(2); 10 | 11 | plan tests => repeat_each() * 3; 12 | 13 | #no_diff(); 14 | no_long_string(); 15 | #master_on(); 16 | #workers(2); 17 | 18 | run_tests(); 19 | 20 | __DATA__ 21 | 22 | === TEST 1: __ngx_req and __ngx_cycle 23 | --- http_config 24 | init_by_lua ' 25 | my_cycle = __ngx_cycle 26 | '; 27 | 28 | --- config 29 | location = /t { 30 | content_by_lua ' 31 | local ffi = require "ffi" 32 | local function tonum(ud) 33 | return tonumber(ffi.cast("uintptr_t", ud)) 34 | end 35 | ngx.say(string.format("init: cycle=%#x", tonum(my_cycle))) 36 | ngx.say(string.format("content cycle=%#x", tonum(__ngx_cycle))) 37 | ngx.say(string.format("content req=%#x", tonum(__ngx_req))) 38 | '; 39 | } 40 | --- request 41 | GET /t 42 | 43 | --- response_body_like chop 44 | ^init: cycle=(0x[a-f0-9]{4,}) 45 | content cycle=\1 46 | content req=0x[a-f0-9]{4,} 47 | $ 48 | --- no_error_log 49 | [error] 50 | 51 | -------------------------------------------------------------------------------- /t/cert/equifax.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV 3 | UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy 4 | dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1 5 | MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx 6 | dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B 7 | AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f 8 | BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A 9 | cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC 10 | AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ 11 | MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm 12 | aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw 13 | ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj 14 | IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF 15 | MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA 16 | A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y 17 | 7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh 18 | 1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4 19 | -----END CERTIFICATE----- 20 | -------------------------------------------------------------------------------- /t/105-pressure.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket::Lua; 4 | 5 | #worker_connections(1014); 6 | #master_on(); 7 | #log_level('debug'); 8 | 9 | repeat_each(20); 10 | 11 | plan tests => repeat_each() * (blocks() * 3); 12 | 13 | our $HtmlDir = html_dir; 14 | #warn $html_dir; 15 | 16 | our $Id; 17 | 18 | #no_diff(); 19 | #no_long_string(); 20 | 21 | $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; 22 | 23 | #no_shuffle(); 24 | no_long_string(); 25 | 26 | run_tests(); 27 | 28 | __DATA__ 29 | 30 | === TEST 1: memory issue in the "args" string option for ngx.location.capture 31 | --- config 32 | location /test1 { 33 | content_by_lua ' 34 | local res = ngx.location.capture("/test2/auth", {args = ngx.var.args}) 35 | ngx.print(res.body) 36 | '; 37 | } 38 | location /test2 { 39 | content_by_lua ' 40 | collectgarbage() 41 | ngx.say(ngx.var.args) 42 | '; 43 | } 44 | 45 | --- request eval 46 | $::Id = int rand 10000; 47 | "GET /test1?parent=$::Id&name=2013031816214284300707&footprint=dsfasfwefklds" 48 | 49 | --- response_body eval 50 | "parent=$::Id&name=2013031816214284300707&footprint=dsfasfwefklds\n" 51 | 52 | --- no_error_log 53 | [error] 54 | 55 | -------------------------------------------------------------------------------- /src/api/ngx_http_lua_api.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Yichun Zhang (agentzh) 4 | */ 5 | 6 | 7 | #ifndef _NGX_HTTP_LUA_API_H_INCLUDED_ 8 | #define _NGX_HTTP_LUA_API_H_INCLUDED_ 9 | 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | 19 | /* Public API for other Nginx modules */ 20 | 21 | 22 | #define ngx_http_lua_version 9020 23 | 24 | 25 | typedef struct { 26 | uint8_t type; 27 | 28 | union { 29 | int b; /* boolean */ 30 | lua_Number n; /* number */ 31 | ngx_str_t s; /* string */ 32 | } value; 33 | 34 | } ngx_http_lua_value_t; 35 | 36 | 37 | lua_State *ngx_http_lua_get_global_state(ngx_conf_t *cf); 38 | 39 | ngx_http_request_t *ngx_http_lua_get_request(lua_State *L); 40 | 41 | ngx_int_t ngx_http_lua_add_package_preload(ngx_conf_t *cf, const char *package, 42 | lua_CFunction func); 43 | 44 | ngx_int_t ngx_http_lua_shared_dict_get(ngx_shm_zone_t *shm_zone, 45 | u_char *key_data, size_t key_len, ngx_http_lua_value_t *value); 46 | 47 | ngx_shm_zone_t *ngx_http_lua_find_zone(u_char *name_data, size_t name_len); 48 | 49 | 50 | #endif /* _NGX_HTTP_LUA_API_H_INCLUDED_ */ 51 | 52 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 53 | -------------------------------------------------------------------------------- /src/ngx_http_lua_worker.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Yichun Zhang (agentzh) 4 | */ 5 | 6 | 7 | #ifndef DDEBUG 8 | #define DDEBUG 0 9 | #endif 10 | #include "ddebug.h" 11 | 12 | 13 | #include "ngx_http_lua_worker.h" 14 | 15 | 16 | static int ngx_http_lua_ngx_worker_exiting(lua_State *L); 17 | static int ngx_http_lua_ngx_worker_pid(lua_State *L); 18 | 19 | 20 | void 21 | ngx_http_lua_inject_worker_api(lua_State *L) 22 | { 23 | lua_createtable(L, 0 /* narr */, 2 /* nrec */); /* ngx.worker. */ 24 | 25 | lua_pushcfunction(L, ngx_http_lua_ngx_worker_exiting); 26 | lua_setfield(L, -2, "exiting"); 27 | 28 | lua_pushcfunction(L, ngx_http_lua_ngx_worker_pid); 29 | lua_setfield(L, -2, "pid"); 30 | 31 | lua_setfield(L, -2, "worker"); 32 | } 33 | 34 | 35 | static int 36 | ngx_http_lua_ngx_worker_exiting(lua_State *L) 37 | { 38 | lua_pushboolean(L, ngx_exiting); 39 | return 1; 40 | } 41 | 42 | 43 | static int 44 | ngx_http_lua_ngx_worker_pid(lua_State *L) 45 | { 46 | lua_pushinteger(L, (lua_Integer) ngx_pid); 47 | return 1; 48 | } 49 | 50 | 51 | #ifndef NGX_LUA_NO_FFI_API 52 | int 53 | ngx_http_lua_ffi_worker_pid(void) 54 | { 55 | return (int) ngx_pid; 56 | } 57 | 58 | 59 | int 60 | ngx_http_lua_ffi_worker_exiting(void) 61 | { 62 | return (int) ngx_exiting; 63 | } 64 | #endif 65 | -------------------------------------------------------------------------------- /t/070-sha1.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | use Test::Nginx::Socket::Lua; 3 | 4 | #worker_connections(1014); 5 | #master_process_enabled(1); 6 | log_level('warn'); 7 | 8 | repeat_each(2); 9 | 10 | plan tests => repeat_each() * (blocks() * 2 + 1); 11 | 12 | #no_diff(); 13 | #no_long_string(); 14 | run_tests(); 15 | 16 | __DATA__ 17 | 18 | === TEST 1: set sha1 hello 19 | --- config 20 | location = /sha1 { 21 | content_by_lua 'ngx.say(ngx.encode_base64(ngx.sha1_bin("hello")))'; 22 | } 23 | --- request 24 | GET /sha1 25 | --- response_body 26 | qvTGHdzF6KLavt4PO0gs2a6pQ00= 27 | 28 | 29 | 30 | === TEST 2: set sha1 "" 31 | --- config 32 | location = /sha1 { 33 | content_by_lua 'ngx.say(ngx.encode_base64(ngx.sha1_bin("")))'; 34 | } 35 | --- request 36 | GET /sha1 37 | --- response_body 38 | 2jmj7l5rSw0yVb/vlWAYkK/YBwk= 39 | 40 | 41 | 42 | === TEST 3: set sha1 nil 43 | --- config 44 | location = /sha1 { 45 | content_by_lua 'ngx.say(ngx.encode_base64(ngx.sha1_bin(nil)))'; 46 | } 47 | --- request 48 | GET /sha1 49 | --- response_body 50 | 2jmj7l5rSw0yVb/vlWAYkK/YBwk= 51 | 52 | 53 | 54 | === TEST 4: set sha1 number 55 | --- config 56 | location = /sha1 { 57 | content_by_lua 'ngx.say(ngx.encode_base64(ngx.sha1_bin(512)))'; 58 | } 59 | --- request 60 | GET /sha1 61 | --- response_body 62 | zgmxJ9SPg4aKRWReJG07UvS97L4= 63 | --- no_error_log 64 | [error] 65 | 66 | -------------------------------------------------------------------------------- /t/074-prefix-var.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | use Test::Nginx::Socket::Lua; 3 | 4 | #worker_connections(1014); 5 | #master_on(); 6 | #workers(2); 7 | #log_level('warn'); 8 | 9 | repeat_each(2); 10 | #repeat_each(1); 11 | 12 | plan tests => repeat_each() * (blocks() * 3); 13 | 14 | #no_diff(); 15 | #no_long_string(); 16 | run_tests(); 17 | 18 | __DATA__ 19 | 20 | === TEST 1: $prefix 21 | --- http_config: lua_package_path "$prefix/html/?.lua;;"; 22 | --- config 23 | location /t { 24 | content_by_lua ' 25 | local foo = require "foo" 26 | foo.go() 27 | '; 28 | } 29 | --- user_files 30 | >>> foo.lua 31 | module("foo", package.seeall) 32 | 33 | function go() 34 | ngx.say("Greetings from module foo.") 35 | end 36 | --- request 37 | GET /t 38 | --- response_body 39 | Greetings from module foo. 40 | --- no_error_log 41 | [error] 42 | 43 | 44 | 45 | === TEST 2: ${prefix} 46 | --- http_config: lua_package_path "${prefix}html/?.lua;;"; 47 | --- config 48 | location /t { 49 | content_by_lua ' 50 | local foo = require "foo" 51 | foo.go() 52 | '; 53 | } 54 | --- user_files 55 | >>> foo.lua 56 | module("foo", package.seeall) 57 | 58 | function go() 59 | ngx.say("Greetings from module foo.") 60 | end 61 | --- request 62 | GET /t 63 | --- response_body 64 | Greetings from module foo. 65 | --- no_error_log 66 | [error] 67 | 68 | -------------------------------------------------------------------------------- /t/115-quote-sql-str.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket::Lua; 4 | 5 | repeat_each(2); 6 | 7 | plan tests => repeat_each() * (blocks() * 3); 8 | 9 | #log_level("warn"); 10 | no_long_string(); 11 | 12 | run_tests(); 13 | 14 | __DATA__ 15 | 16 | === TEST 1: \0 17 | --- config 18 | location = /set { 19 | content_by_lua ' 20 | ngx.say(ngx.quote_sql_str("a\\0b\\0")) 21 | '; 22 | } 23 | --- request 24 | GET /set 25 | --- response_body 26 | 'a\0b\0' 27 | --- no_error_log 28 | [error] 29 | 30 | 31 | 32 | === TEST 2: \t 33 | --- config 34 | location = /set { 35 | content_by_lua ' 36 | ngx.say(ngx.quote_sql_str("a\\tb\\t")) 37 | '; 38 | } 39 | --- request 40 | GET /set 41 | --- response_body 42 | 'a\tb\t' 43 | --- no_error_log 44 | [error] 45 | 46 | 47 | 48 | === TEST 3: \b 49 | --- config 50 | location = /set { 51 | content_by_lua ' 52 | ngx.say(ngx.quote_sql_str("a\\bb\\b")) 53 | '; 54 | } 55 | --- request 56 | GET /set 57 | --- response_body 58 | 'a\bb\b' 59 | --- no_error_log 60 | [error] 61 | 62 | 63 | 64 | === TEST 4: \Z 65 | --- config 66 | location = /set { 67 | content_by_lua ' 68 | ngx.say(ngx.quote_sql_str("a\\026b\\026")) 69 | '; 70 | } 71 | --- request 72 | GET /set 73 | --- response_body 74 | 'a\Zb\Z' 75 | --- no_error_log 76 | [error] 77 | 78 | -------------------------------------------------------------------------------- /t/078-hup-vars.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | 3 | our $SkipReason; 4 | 5 | BEGIN { 6 | if ($ENV{TEST_NGINX_CHECK_LEAK}) { 7 | $SkipReason = "unavailable for the hup tests"; 8 | 9 | } else { 10 | $ENV{TEST_NGINX_USE_HUP} = 1; 11 | undef $ENV{TEST_NGINX_USE_STAP}; 12 | } 13 | } 14 | 15 | use Test::Nginx::Socket::Lua $SkipReason ? (skip_all => $SkipReason) : (); 16 | 17 | #worker_connections(1014); 18 | #master_on(); 19 | #workers(2); 20 | #log_level('debug'); 21 | 22 | repeat_each(2); 23 | 24 | plan tests => repeat_each() * (3 * blocks()); 25 | 26 | #no_diff(); 27 | #no_long_string(); 28 | no_shuffle(); 29 | 30 | run_tests(); 31 | 32 | __DATA__ 33 | 34 | === TEST 1: nginx variable hup bug (step 1) 35 | http://mailman.nginx.org/pipermail/nginx-devel/2012-May/002223.html 36 | --- config 37 | location /t { 38 | set $vv $http_host; 39 | set_by_lua $i 'return ngx.var.http_host'; 40 | echo $i; 41 | } 42 | --- request 43 | GET /t 44 | --- response_body 45 | localhost 46 | --- no_error_log 47 | [error] 48 | 49 | 50 | 51 | === TEST 2: nginx variable hup bug (step 2) 52 | http://mailman.nginx.org/pipermail/nginx-devel/2012-May/002223.html 53 | --- config 54 | location /t { 55 | #set $vv $http_host; 56 | set_by_lua $i 'return ngx.var.http_host'; 57 | echo $i; 58 | } 59 | --- request 60 | GET /t 61 | --- response_body 62 | localhost 63 | --- no_error_log 64 | [error] 65 | 66 | -------------------------------------------------------------------------------- /t/123-lua-path.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | use Test::Nginx::Socket::Lua; 3 | 4 | #worker_connections(1014); 5 | #master_on(); 6 | #workers(2); 7 | #log_level('warn'); 8 | 9 | repeat_each(2); 10 | #repeat_each(1); 11 | 12 | plan tests => repeat_each() * (blocks() * 3 + 1); 13 | 14 | $ENV{LUA_PATH} = "/foo/bar/baz"; 15 | $ENV{LUA_CPATH} = "/baz/bar/foo"; 16 | #no_diff(); 17 | #no_long_string(); 18 | master_on(); 19 | no_shuffle(); 20 | check_accum_error_log(); 21 | run_tests(); 22 | 23 | __DATA__ 24 | 25 | === TEST 1: LUA_PATH & LUA_CPATH env (code cache on) 26 | --- main_config 27 | env LUA_PATH; 28 | env LUA_CPATH; 29 | 30 | --- config 31 | location /lua { 32 | content_by_lua ' 33 | ngx.say(package.path) 34 | ngx.say(package.cpath) 35 | '; 36 | } 37 | --- request 38 | GET /lua 39 | --- response_body 40 | /foo/bar/baz 41 | /baz/bar/foo 42 | 43 | --- no_error_log 44 | [error] 45 | 46 | 47 | 48 | === TEST 2: LUA_PATH & LUA_CPATH env (code cache off) 49 | --- main_config 50 | env LUA_PATH; 51 | env LUA_CPATH; 52 | 53 | --- config 54 | lua_code_cache off; 55 | location /lua { 56 | content_by_lua ' 57 | ngx.say(package.path) 58 | ngx.say(package.cpath) 59 | '; 60 | } 61 | --- request 62 | GET /lua 63 | --- response_body 64 | /foo/bar/baz 65 | /baz/bar/foo 66 | 67 | --- no_error_log 68 | [error] 69 | --- error_log eval 70 | qr/\[alert\] .*? lua_code_cache is off/ 71 | 72 | -------------------------------------------------------------------------------- /src/ngx_http_lua_subrequest.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Xiaozhe Wang (chaoslawful) 4 | * Copyright (C) Yichun Zhang (agentzh) 5 | */ 6 | 7 | 8 | #ifndef _NGX_HTTP_LUA_SUBREQUEST_H_INCLUDED_ 9 | #define _NGX_HTTP_LUA_SUBREQUEST_H_INCLUDED_ 10 | 11 | 12 | #include "ngx_http_lua_common.h" 13 | 14 | 15 | void ngx_http_lua_inject_subrequest_api(lua_State *L); 16 | ngx_int_t ngx_http_lua_post_subrequest(ngx_http_request_t *r, void *data, 17 | ngx_int_t rc); 18 | 19 | 20 | extern ngx_str_t ngx_http_lua_get_method; 21 | extern ngx_str_t ngx_http_lua_put_method; 22 | extern ngx_str_t ngx_http_lua_post_method; 23 | extern ngx_str_t ngx_http_lua_head_method; 24 | extern ngx_str_t ngx_http_lua_delete_method; 25 | extern ngx_str_t ngx_http_lua_options_method; 26 | extern ngx_str_t ngx_http_lua_copy_method; 27 | extern ngx_str_t ngx_http_lua_move_method; 28 | extern ngx_str_t ngx_http_lua_lock_method; 29 | extern ngx_str_t ngx_http_lua_mkcol_method; 30 | extern ngx_str_t ngx_http_lua_propfind_method; 31 | extern ngx_str_t ngx_http_lua_proppatch_method; 32 | extern ngx_str_t ngx_http_lua_unlock_method; 33 | extern ngx_str_t ngx_http_lua_patch_method; 34 | extern ngx_str_t ngx_http_lua_trace_method; 35 | 36 | 37 | typedef struct ngx_http_lua_post_subrequest_data_s { 38 | ngx_http_lua_ctx_t *ctx; 39 | ngx_http_lua_co_ctx_t *pr_co_ctx; 40 | 41 | } ngx_http_lua_post_subrequest_data_t; 42 | 43 | 44 | #endif /* _NGX_HTTP_LUA_SUBREQUEST_H_INCLUDED_ */ 45 | 46 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 47 | -------------------------------------------------------------------------------- /util/ngx-links: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | use strict; 4 | use warnings; 5 | 6 | use Cwd qw( cwd ); 7 | use Getopt::Std; 8 | 9 | my %opts; 10 | getopts('f', \%opts) or 11 | die "Usage: $0 [-f] 12 | Options: 13 | -f Override exising symbolic links with force 14 | "; 15 | 16 | my $root = shift || 'src'; 17 | 18 | my $force = $opts{f}; 19 | 20 | opendir my $dir, $root 21 | or die "Can't open directory src/ for reading: $!\n"; 22 | 23 | my @links; 24 | 25 | while (my $entry = readdir $dir) { 26 | my ($base, $ext); 27 | 28 | my $source = "$root/$entry"; 29 | 30 | if (-l $source || -d $source) { 31 | warn "skipping $source\n"; 32 | next; 33 | } 34 | 35 | if ($entry =~ m{ ^ ngx_ (?: \w+ _ )+ (\w+) \. ([ch]|rl) $}x) { 36 | ($base, $ext) = ($1, $2); 37 | } else { 38 | next; 39 | } 40 | 41 | my $target = "$root/$base.$ext"; 42 | if (-e $target && ! -l $target) { 43 | die "target $target already exists, and not a symlink, not overriding...Abort.\n"; 44 | } elsif (-l $target) { 45 | #warn "it's a link"; 46 | if ( ! $force ) { 47 | die "target $target already exists, not overriding...Abort.\n"; 48 | } 49 | warn "overriding existing symlink $target\n"; 50 | } 51 | #warn "creating $target --> $root/$entry\n"; 52 | system("ln -svf `pwd`/$source $target") == 0 or 53 | die "Failed to create the symlink\n";; 54 | 55 | push @links, $target; 56 | } 57 | 58 | print join("\n", @links), "\n"; 59 | 60 | close $dir; 61 | 62 | 63 | -------------------------------------------------------------------------------- /src/ngx_http_lua_exception.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Xiaozhe Wang (chaoslawful) 4 | * Copyright (C) Yichun Zhang (agentzh) 5 | */ 6 | 7 | 8 | #ifndef DDEBUG 9 | #define DDEBUG 0 10 | #endif 11 | #include "ddebug.h" 12 | 13 | 14 | #include "ngx_http_lua_exception.h" 15 | #include "ngx_http_lua_util.h" 16 | 17 | 18 | /* longjmp mark for restoring nginx execution after Lua VM crashing */ 19 | jmp_buf ngx_http_lua_exception; 20 | 21 | /** 22 | * Override default Lua panic handler, output VM crash reason to nginx error 23 | * log, and restore execution to the nearest jmp-mark. 24 | * 25 | * @param L Lua state pointer 26 | * @retval Long jump to the nearest jmp-mark, never returns. 27 | * @note nginx request pointer should be stored in Lua thread's globals table 28 | * in order to make logging working. 29 | * */ 30 | int 31 | ngx_http_lua_atpanic(lua_State *L) 32 | { 33 | #ifdef NGX_LUA_ABORT_AT_PANIC 34 | abort(); 35 | #else 36 | u_char *s = NULL; 37 | size_t len = 0; 38 | 39 | if (lua_type(L, -1) == LUA_TSTRING) { 40 | s = (u_char *) lua_tolstring(L, -1, &len); 41 | } 42 | 43 | if (s == NULL) { 44 | s = (u_char *) "unknown reason"; 45 | len = sizeof("unknown reason") - 1; 46 | } 47 | 48 | ngx_log_stderr(0, "lua atpanic: Lua VM crashed, reason: %*s", len, s); 49 | ngx_quit = 1; 50 | 51 | /* restore nginx execution */ 52 | NGX_LUA_EXCEPTION_THROW(1); 53 | 54 | /* impossible to reach here */ 55 | #endif 56 | } 57 | 58 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 59 | -------------------------------------------------------------------------------- /src/ngx_http_lua_config.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Yichun Zhang (agentzh) 4 | */ 5 | 6 | 7 | #ifndef DDEBUG 8 | #define DDEBUG 0 9 | #endif 10 | #include "ddebug.h" 11 | 12 | 13 | #include "ngx_http_lua_config.h" 14 | #include "api/ngx_http_lua_api.h" 15 | 16 | 17 | static int ngx_http_lua_config_prefix(lua_State *L); 18 | static int ngx_http_lua_config_configure(lua_State *L); 19 | 20 | 21 | void 22 | ngx_http_lua_inject_config_api(lua_State *L) 23 | { 24 | /* ngx.config */ 25 | 26 | lua_createtable(L, 0, 5 /* nrec */); /* .config */ 27 | 28 | #if (NGX_DEBUG) 29 | lua_pushboolean(L, 1); 30 | #else 31 | lua_pushboolean(L, 0); 32 | #endif 33 | lua_setfield(L, -2, "debug"); 34 | 35 | lua_pushcfunction(L, ngx_http_lua_config_prefix); 36 | lua_setfield(L, -2, "prefix"); 37 | 38 | lua_pushinteger(L, nginx_version); 39 | lua_setfield(L, -2, "nginx_version"); 40 | 41 | lua_pushinteger(L, ngx_http_lua_version); 42 | lua_setfield(L, -2, "ngx_lua_version"); 43 | 44 | lua_pushcfunction(L, ngx_http_lua_config_configure); 45 | lua_setfield(L, -2, "nginx_configure"); 46 | 47 | lua_setfield(L, -2, "config"); 48 | } 49 | 50 | 51 | static int 52 | ngx_http_lua_config_prefix(lua_State *L) 53 | { 54 | lua_pushlstring(L, (char *) ngx_cycle->prefix.data, 55 | ngx_cycle->prefix.len); 56 | return 1; 57 | } 58 | 59 | 60 | static int 61 | ngx_http_lua_config_configure(lua_State *L) 62 | { 63 | lua_pushliteral(L, NGX_CONFIGURE); 64 | return 1; 65 | } 66 | 67 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 68 | -------------------------------------------------------------------------------- /src/ngx_http_lua_shdict.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Yichun Zhang (agentzh) 4 | */ 5 | 6 | 7 | #ifndef _NGX_HTTP_LUA_SHDICT_H_INCLUDED_ 8 | #define _NGX_HTTP_LUA_SHDICT_H_INCLUDED_ 9 | 10 | 11 | #include "ngx_http_lua_common.h" 12 | 13 | 14 | typedef struct { 15 | u_char color; 16 | u_char dummy; 17 | u_short key_len; 18 | ngx_queue_t queue; 19 | uint64_t expires; 20 | uint8_t value_type; 21 | uint32_t value_len; 22 | uint32_t user_flags; 23 | u_char data[1]; 24 | } ngx_http_lua_shdict_node_t; 25 | 26 | 27 | typedef struct { 28 | ngx_rbtree_t rbtree; 29 | ngx_rbtree_node_t sentinel; 30 | ngx_queue_t queue; 31 | } ngx_http_lua_shdict_shctx_t; 32 | 33 | 34 | typedef struct { 35 | ngx_http_lua_shdict_shctx_t *sh; 36 | ngx_slab_pool_t *shpool; 37 | ngx_str_t name; 38 | ngx_http_lua_main_conf_t *main_conf; 39 | ngx_log_t *log; 40 | } ngx_http_lua_shdict_ctx_t; 41 | 42 | 43 | ngx_int_t ngx_http_lua_shdict_init_zone(ngx_shm_zone_t *shm_zone, void *data); 44 | void ngx_http_lua_shdict_rbtree_insert_value(ngx_rbtree_node_t *temp, 45 | ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); 46 | void ngx_http_lua_inject_shdict_api(ngx_http_lua_main_conf_t *lmcf, 47 | lua_State *L); 48 | 49 | 50 | #endif /* _NGX_HTTP_LUA_SHDICT_H_INCLUDED_ */ 51 | 52 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 53 | -------------------------------------------------------------------------------- /util/reindex: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | #: reindex.pl 3 | #: reindex .t files for Test::Base based test files 4 | #: Copyright (c) 2006 Agent Zhang 5 | #: 2006-04-27 2006-05-09 6 | 7 | use strict; 8 | use warnings; 9 | 10 | #use File::Copy; 11 | use Getopt::Std; 12 | 13 | my %opts; 14 | getopts('hb:', \%opts); 15 | if ($opts{h} or ! @ARGV) { 16 | die "Usage: reindex [-b 0] t/*.t\n"; 17 | } 18 | 19 | my $init = $opts{b}; 20 | $init = 1 if not defined $init; 21 | 22 | my @files = map glob, @ARGV; 23 | for my $file (@files) { 24 | next if -d $file or $file !~ /\.t_?$/; 25 | reindex($file); 26 | } 27 | 28 | sub reindex { 29 | my $file = $_[0]; 30 | open my $in, $file or 31 | die "Can't open $file for reading: $!"; 32 | my @lines; 33 | my $counter = $init; 34 | my $changed; 35 | while (<$in>) { 36 | s/\r$//; 37 | my $num; 38 | s/ ^ === \s+ TEST \s+ (\d+)/$num=$1; "=== TEST " . $counter++/xie; 39 | next if !defined $num; 40 | if ($num != $counter-1) { 41 | $changed++; 42 | } 43 | } continue { 44 | push @lines, $_; 45 | } 46 | close $in; 47 | my $text = join '', @lines; 48 | $text =~ s/(?x) \n+ === \s+ TEST/\n\n\n\n=== TEST/ixsg; 49 | $text =~ s/__(DATA|END)__\n+=== TEST/__${1}__\n\n=== TEST/; 50 | #$text =~ s/\n+$/\n\n/s; 51 | if (! $changed and $text eq join '', @lines) { 52 | warn "reindex: $file:\tskipped.\n"; 53 | return; 54 | } 55 | #File::Copy::copy( $file, "$file.bak" ); 56 | open my $out, "> $file" or 57 | die "Can't open $file for writing: $!"; 58 | binmode $out; 59 | print $out $text; 60 | close $out; 61 | 62 | warn "reindex: $file:\tdone.\n"; 63 | } 64 | 65 | -------------------------------------------------------------------------------- /t/076-no-postpone.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | use Test::Nginx::Socket::Lua; 3 | 4 | #worker_connections(1014); 5 | #master_on(); 6 | #workers(2); 7 | #log_level('warn'); 8 | 9 | repeat_each(2); 10 | #repeat_each(1); 11 | 12 | plan tests => repeat_each() * (blocks() * 3); 13 | 14 | #no_diff(); 15 | #no_long_string(); 16 | run_tests(); 17 | 18 | __DATA__ 19 | 20 | === TEST 1: rewrite no postpone on 21 | --- http_config 22 | rewrite_by_lua_no_postpone on; 23 | --- config 24 | set $foo ''; 25 | location /t { 26 | rewrite_by_lua ' 27 | ngx.var.foo = 1 28 | '; 29 | if ($foo = 1) { 30 | echo "foo: $foo"; 31 | } 32 | echo "no foo: $foo"; 33 | } 34 | --- request 35 | GET /t 36 | --- response_body 37 | foo: 1 38 | --- no_error_log 39 | [error] 40 | 41 | 42 | 43 | === TEST 2: rewrite no postpone explicitly off 44 | --- http_config 45 | rewrite_by_lua_no_postpone off; 46 | --- config 47 | set $foo ''; 48 | location /t { 49 | rewrite_by_lua ' 50 | ngx.var.foo = 1 51 | '; 52 | if ($foo = 1) { 53 | echo "foo: $foo"; 54 | } 55 | echo "no foo: $foo"; 56 | } 57 | --- request 58 | GET /t 59 | --- response_body 60 | no foo: 1 61 | --- no_error_log 62 | [error] 63 | 64 | 65 | 66 | === TEST 3: rewrite no postpone off by default 67 | --- config 68 | set $foo ''; 69 | location /t { 70 | rewrite_by_lua ' 71 | ngx.var.foo = 1 72 | '; 73 | if ($foo = 1) { 74 | echo "foo: $foo"; 75 | } 76 | echo "no foo: $foo"; 77 | } 78 | --- request 79 | GET /t 80 | --- response_body 81 | no foo: 1 82 | --- no_error_log 83 | [error] 84 | 85 | -------------------------------------------------------------------------------- /src/ngx_http_lua_socket_udp.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Yichun Zhang (agentzh) 4 | */ 5 | 6 | 7 | #ifndef _NGX_HTTP_LUA_SOCKET_UDP_H_INCLUDED_ 8 | #define _NGX_HTTP_LUA_SOCKET_UDP_H_INCLUDED_ 9 | 10 | 11 | #include "ngx_http_lua_common.h" 12 | 13 | 14 | typedef struct ngx_http_lua_socket_udp_upstream_s 15 | ngx_http_lua_socket_udp_upstream_t; 16 | 17 | 18 | typedef 19 | int (*ngx_http_lua_socket_udp_retval_handler)(ngx_http_request_t *r, 20 | ngx_http_lua_socket_udp_upstream_t *u, lua_State *L); 21 | 22 | 23 | typedef void (*ngx_http_lua_socket_udp_upstream_handler_pt)( 24 | ngx_http_request_t *r, ngx_http_lua_socket_udp_upstream_t *u); 25 | 26 | 27 | struct ngx_http_lua_socket_udp_upstream_s { 28 | ngx_http_lua_socket_udp_retval_handler prepare_retvals; 29 | ngx_http_lua_socket_udp_upstream_handler_pt read_event_handler; 30 | 31 | ngx_http_lua_loc_conf_t *conf; 32 | ngx_http_cleanup_pt *cleanup; 33 | ngx_http_request_t *request; 34 | ngx_udp_connection_t udp_connection; 35 | 36 | ngx_msec_t read_timeout; 37 | 38 | ngx_http_upstream_resolved_t *resolved; 39 | 40 | ngx_uint_t ft_type; 41 | ngx_err_t socket_errno; 42 | size_t received; /* for receive */ 43 | size_t recv_buf_size; 44 | 45 | ngx_http_lua_co_ctx_t *co_ctx; 46 | 47 | unsigned waiting; /* :1 */ 48 | }; 49 | 50 | 51 | void ngx_http_lua_inject_socket_udp_api(ngx_log_t *log, lua_State *L); 52 | 53 | 54 | #endif /* _NGX_HTTP_LUA_SOCKET_UDP_H_INCLUDED_ */ 55 | 56 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 57 | -------------------------------------------------------------------------------- /t/032-iolist.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | use Test::Nginx::Socket::Lua; 3 | 4 | #worker_connections(1014); 5 | #master_on(); 6 | #workers(2); 7 | #log_level('warn'); 8 | 9 | repeat_each(2); 10 | #repeat_each(1); 11 | 12 | plan tests => repeat_each() * (blocks() * 2); 13 | 14 | #no_diff(); 15 | #no_long_string(); 16 | run_tests(); 17 | 18 | __DATA__ 19 | 20 | === TEST 1: sanity 21 | --- config 22 | location /lua { 23 | content_by_lua ' 24 | local table = {"hello", nil, true, false, 32.5, 56} 25 | ngx.say(table) 26 | '; 27 | } 28 | --- request 29 | GET /lua 30 | --- response_body 31 | helloniltruefalse32.556 32 | 33 | 34 | 35 | === TEST 2: nested table 36 | --- config 37 | location /lua { 38 | content_by_lua ' 39 | local table = {"hello", nil, true, false, 32.5, 56} 40 | local table2 = {table, "--", table} 41 | ngx.say(table2) 42 | '; 43 | } 44 | --- request 45 | GET /lua 46 | --- response_body 47 | helloniltruefalse32.556--helloniltruefalse32.556 48 | 49 | 50 | 51 | === TEST 3: non-array table 52 | --- config 53 | location /lua { 54 | content_by_lua ' 55 | local table = {foo = 3} 56 | ngx.say(table) 57 | '; 58 | } 59 | --- request 60 | GET /lua 61 | --- response_body_like: 500 Internal Server Error 62 | --- error_code: 500 63 | 64 | 65 | 66 | === TEST 4: bad data type in table 67 | --- config 68 | location /lua { 69 | content_by_lua ' 70 | local f = function () return end 71 | local table = {1, 3, f} 72 | ngx.say(table) 73 | '; 74 | } 75 | --- request 76 | GET /lua 77 | --- response_body_like: 500 Internal Server Error 78 | --- error_code: 500 79 | 80 | -------------------------------------------------------------------------------- /src/ngx_http_lua_api.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Yichun Zhang (agentzh) 4 | */ 5 | 6 | 7 | #include "ddebug.h" 8 | 9 | #include "ngx_http_lua_common.h" 10 | #include "api/ngx_http_lua_api.h" 11 | #include "ngx_http_lua_util.h" 12 | 13 | 14 | lua_State * 15 | ngx_http_lua_get_global_state(ngx_conf_t *cf) 16 | { 17 | ngx_http_lua_main_conf_t *lmcf; 18 | 19 | lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); 20 | 21 | return lmcf->lua; 22 | } 23 | 24 | 25 | ngx_http_request_t * 26 | ngx_http_lua_get_request(lua_State *L) 27 | { 28 | return ngx_http_lua_get_req(L); 29 | } 30 | 31 | 32 | ngx_int_t 33 | ngx_http_lua_add_package_preload(ngx_conf_t *cf, const char *package, 34 | lua_CFunction func) 35 | { 36 | lua_State *L; 37 | ngx_http_lua_main_conf_t *lmcf; 38 | ngx_http_lua_preload_hook_t *hook; 39 | 40 | lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); 41 | 42 | L = lmcf->lua; 43 | 44 | if (L) { 45 | lua_getglobal(L, "package"); 46 | lua_getfield(L, -1, "preload"); 47 | lua_pushcfunction(L, func); 48 | lua_setfield(L, -2, package); 49 | lua_pop(L, 2); 50 | 51 | return NGX_OK; 52 | } 53 | 54 | /* L == NULL */ 55 | 56 | if (lmcf->preload_hooks == NULL) { 57 | lmcf->preload_hooks = 58 | ngx_array_create(cf->pool, 4, 59 | sizeof(ngx_http_lua_preload_hook_t)); 60 | 61 | if (lmcf->preload_hooks == NULL) { 62 | return NGX_ERROR; 63 | } 64 | } 65 | 66 | hook = ngx_array_push(lmcf->preload_hooks); 67 | if (hook == NULL) { 68 | return NGX_ERROR; 69 | } 70 | 71 | hook->package = (u_char *) package; 72 | hook->loader = func; 73 | 74 | return NGX_OK; 75 | } 76 | 77 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 78 | -------------------------------------------------------------------------------- /t/029-http-time.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | use Test::Nginx::Socket::Lua; 3 | 4 | #worker_connections(1014); 5 | #master_process_enabled(1); 6 | log_level('warn'); 7 | 8 | repeat_each(2); 9 | #repeat_each(1); 10 | 11 | plan tests => repeat_each() * (blocks() * 2); 12 | 13 | #no_diff(); 14 | #no_long_string(); 15 | run_tests(); 16 | 17 | __DATA__ 18 | 19 | === TEST 1: http_time in content_by_lua 20 | --- config 21 | location /lua { 22 | content_by_lua ' 23 | ngx.say(ngx.http_time(1290079655)) 24 | '; 25 | } 26 | --- request 27 | GET /lua 28 | --- response_body 29 | Thu, 18 Nov 2010 11:27:35 GMT 30 | 31 | 32 | 33 | === TEST 2: http_time in set_by_lua 34 | --- config 35 | location /lua { 36 | set_by_lua $a ' 37 | return ngx.http_time(1290079655) 38 | '; 39 | echo $a; 40 | } 41 | --- request 42 | GET /lua 43 | --- response_body 44 | Thu, 18 Nov 2010 11:27:35 GMT 45 | 46 | 47 | 48 | === TEST 3: parse_http_time in set_by_lua 49 | --- config 50 | location /lua { 51 | set_by_lua $a ' 52 | return ngx.parse_http_time("Thu, 18 Nov 2010 11:27:35 GMT") 53 | '; 54 | echo $a; 55 | } 56 | --- request 57 | GET /lua 58 | --- response_body 59 | 1290079655 60 | 61 | 62 | 63 | === TEST 4: parse_http_time in content_by_lua 64 | --- config 65 | location /lua { 66 | content_by_lua ' 67 | ngx.say(ngx.parse_http_time("Thu, 18 Nov 2010 11:27:35 GMT")) 68 | '; 69 | } 70 | --- request 71 | GET /lua 72 | --- response_body 73 | 1290079655 74 | 75 | 76 | 77 | === TEST 5: bad arg for parse_http_time in content_by_lua 78 | --- config 79 | location /lua { 80 | content_by_lua ' 81 | ngx.say(ngx.parse_http_time("abc") or "nil") 82 | '; 83 | } 84 | --- request 85 | GET /lua 86 | --- response_body 87 | nil 88 | 89 | -------------------------------------------------------------------------------- /t/092-eof.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | use Test::Nginx::Socket::Lua; 3 | 4 | #worker_connections(1014); 5 | #master_on(); 6 | #workers(2); 7 | #log_level('warn'); 8 | 9 | repeat_each(2); 10 | #repeat_each(1); 11 | 12 | plan tests => repeat_each() * (blocks() * 6); 13 | 14 | master_on(); 15 | workers(2); 16 | no_root_location(); 17 | #no_diff(); 18 | #no_long_string(); 19 | run_tests(); 20 | 21 | __DATA__ 22 | 23 | === TEST 1: 404 parallel subrequests after ngx.eof() 24 | --- config 25 | location = /lua { 26 | content_by_lua ' 27 | ngx.say(1) 28 | ngx.eof() 29 | local res1, res2 = ngx.location.capture_multi{ 30 | { "/bad1" }, 31 | { "/bad2" } 32 | } 33 | ngx.log(ngx.WARN, "res1: ", res1.status) 34 | ngx.log(ngx.WARN, "res2: ", res2.status) 35 | '; 36 | } 37 | --- request 38 | GET /lua 39 | --- response_body 40 | 1 41 | --- no_error_log 42 | [alert] 43 | --- error_log 44 | res1: 404 45 | res2: 404 46 | No such file or directory 47 | 48 | 49 | 50 | === TEST 2: parallel normal subrequests after ngx.eof() 51 | --- config 52 | location = /t { 53 | content_by_lua ' 54 | ngx.say(1) 55 | ngx.eof() 56 | local r1, r2 = ngx.location.capture_multi{ 57 | { "/proxy/tom" }, 58 | { "/proxy/jim" } 59 | } 60 | ngx.log(ngx.WARN, r1.body) 61 | ngx.log(ngx.WARN, r2.body) 62 | '; 63 | } 64 | 65 | location ~ '^/proxy/(\w+)' { 66 | proxy_pass http://127.0.0.1:$server_port/hello?a=$1; 67 | } 68 | 69 | location = /hello { 70 | echo_sleep 0.5; 71 | echo -n "hello, $arg_a"; 72 | } 73 | --- request 74 | GET /t 75 | --- response_body 76 | 1 77 | --- no_error_log 78 | [alert] 79 | [error] 80 | --- error_log 81 | hello, tom 82 | hello, jim 83 | 84 | -------------------------------------------------------------------------------- /t/122-worker.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket::Lua; 4 | 5 | #worker_connections(1014); 6 | #master_on(); 7 | #workers(2); 8 | #log_level('warn'); 9 | 10 | repeat_each(2); 11 | 12 | plan tests => repeat_each() * (blocks() * 3); 13 | 14 | #no_diff(); 15 | no_long_string(); 16 | run_tests(); 17 | 18 | __DATA__ 19 | 20 | === TEST 1: content_by_lua + ngx.worker.exiting 21 | --- config 22 | location /lua { 23 | content_by_lua ' 24 | ngx.say("worker exiting: ", ngx.worker.exiting()) 25 | '; 26 | } 27 | --- request 28 | GET /lua 29 | --- response_body 30 | worker exiting: false 31 | --- no_error_log 32 | [error] 33 | 34 | 35 | 36 | === TEST 2: content_by_lua + ngx.worker.pid 37 | --- config 38 | location /lua { 39 | content_by_lua ' 40 | local pid = ngx.worker.pid() 41 | ngx.say("worker pid: ", pid) 42 | if pid ~= tonumber(ngx.var.pid) then 43 | ngx.say("worker pid is wrong.") 44 | else 45 | ngx.say("worker pid is correct.") 46 | end 47 | '; 48 | } 49 | --- request 50 | GET /lua 51 | --- response_body_like 52 | worker pid: \d+ 53 | worker pid is correct\. 54 | --- no_error_log 55 | [error] 56 | 57 | 58 | 59 | === TEST 3: init_worker_by_lua + ngx.worker.pid 60 | --- http_config 61 | init_worker_by_lua ' 62 | my_pid = ngx.worker.pid() 63 | '; 64 | --- config 65 | location /lua { 66 | content_by_lua ' 67 | ngx.say("worker pid: ", my_pid) 68 | if my_pid ~= tonumber(ngx.var.pid) then 69 | ngx.say("worker pid is wrong.") 70 | else 71 | ngx.say("worker pid is correct.") 72 | end 73 | '; 74 | } 75 | --- request 76 | GET /lua 77 | --- response_body_like 78 | worker pid: \d+ 79 | worker pid is correct\. 80 | --- no_error_log 81 | [error] 82 | 83 | -------------------------------------------------------------------------------- /t/080-hup-shdict.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | 3 | our $SkipReason; 4 | 5 | BEGIN { 6 | if ($ENV{TEST_NGINX_CHECK_LEAK}) { 7 | $SkipReason = "unavailable for the hup tests"; 8 | 9 | } else { 10 | $ENV{TEST_NGINX_USE_HUP} = 1; 11 | undef $ENV{TEST_NGINX_USE_STAP}; 12 | } 13 | } 14 | 15 | use Test::Nginx::Socket::Lua $SkipReason ? (skip_all => $SkipReason) : (); 16 | 17 | #worker_connections(1014); 18 | #master_process_enabled(1); 19 | #log_level('warn'); 20 | 21 | repeat_each(2); 22 | 23 | plan tests => repeat_each() * (blocks() * 3); 24 | 25 | #no_diff(); 26 | no_long_string(); 27 | #master_on(); 28 | #workers(2); 29 | 30 | no_shuffle(); 31 | 32 | run_tests(); 33 | 34 | __DATA__ 35 | 36 | === TEST 1: initialize the fields in shdict 37 | --- http_config 38 | lua_shared_dict dogs 1m; 39 | --- config 40 | location = /test { 41 | content_by_lua ' 42 | local dogs = ngx.shared.dogs 43 | dogs:set("foo", 32) 44 | dogs:set("bah", 10502) 45 | local val = dogs:get("foo") 46 | ngx.say(val, " ", type(val)) 47 | val = dogs:get("bah") 48 | ngx.say(val, " ", type(val)) 49 | '; 50 | } 51 | --- request 52 | GET /test 53 | --- response_body 54 | 32 number 55 | 10502 number 56 | --- no_error_log 57 | [error] 58 | 59 | 60 | 61 | === TEST 2: retrieve the fields in shdict after HUP reload 62 | --- http_config 63 | lua_shared_dict dogs 1m; 64 | --- config 65 | location = /test { 66 | content_by_lua ' 67 | local dogs = ngx.shared.dogs 68 | 69 | -- dogs:set("foo", 32) 70 | -- dogs:set("bah", 10502) 71 | 72 | local val = dogs:get("foo") 73 | ngx.say(val, " ", type(val)) 74 | val = dogs:get("bah") 75 | ngx.say(val, " ", type(val)) 76 | '; 77 | } 78 | --- request 79 | GET /test 80 | --- response_body 81 | 32 number 82 | 10502 number 83 | --- no_error_log 84 | [error] 85 | 86 | -------------------------------------------------------------------------------- /t/069-null.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket::Lua; 4 | 5 | repeat_each(2); 6 | 7 | #master_on(); 8 | #workers(1); 9 | #log_level('debug'); 10 | #log_level('warn'); 11 | #worker_connections(1024); 12 | 13 | plan tests => repeat_each() * (blocks() * 3 + 1); 14 | 15 | $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; 16 | $ENV{TEST_NGINX_MYSQL_PORT} ||= 3306; 17 | 18 | our $LuaCpath = $ENV{LUA_CPATH} || 19 | '/usr/local/openresty-debug/lualib/?.so;/usr/local/openresty/lualib/?.so;;'; 20 | 21 | no_long_string(); 22 | 23 | run_tests(); 24 | 25 | __DATA__ 26 | 27 | === TEST 1: compare ngx.null with cjson.null 28 | --- http_config eval 29 | "lua_package_cpath '$::LuaCpath';"; 30 | --- config 31 | location /lua { 32 | content_by_lua ' 33 | local cjson = require "cjson" 34 | ngx.say(cjson.null == ngx.null) 35 | ngx.say(cjson.encode(ngx.null)) 36 | '; 37 | } 38 | --- request 39 | GET /lua 40 | --- response_body 41 | true 42 | null 43 | --- no_error_log 44 | [error] 45 | 46 | 47 | 48 | === TEST 2: output ngx.null 49 | --- config 50 | location /lua { 51 | content_by_lua ' 52 | ngx.say("ngx.null: ", ngx.null) 53 | '; 54 | } 55 | --- request 56 | GET /lua 57 | --- response_body 58 | ngx.null: null 59 | --- no_error_log 60 | [error] 61 | 62 | 63 | 64 | === TEST 3: output ngx.null in a table 65 | --- config 66 | location /lua { 67 | content_by_lua ' 68 | ngx.say({"ngx.null: ", ngx.null}) 69 | '; 70 | } 71 | --- request 72 | GET /lua 73 | --- response_body 74 | ngx.null: null 75 | --- no_error_log 76 | [error] 77 | 78 | 79 | 80 | === TEST 4: log ngx.null 81 | --- config 82 | location /lua { 83 | content_by_lua ' 84 | print("ngx.null: ", ngx.null) 85 | ngx.say("done") 86 | '; 87 | } 88 | --- request 89 | GET /lua 90 | --- response_body 91 | done 92 | --- error_log 93 | ngx.null: null 94 | --- no_error_log 95 | [error] 96 | 97 | -------------------------------------------------------------------------------- /t/110-etag.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | use Test::Nginx::Socket::Lua; 3 | 4 | #worker_connections(1014); 5 | #master_on(); 6 | #workers(2); 7 | #log_level('warn'); 8 | 9 | repeat_each(2); 10 | 11 | plan tests => repeat_each() * (blocks() * 3); 12 | 13 | #no_diff(); 14 | #no_long_string(); 15 | run_tests(); 16 | 17 | __DATA__ 18 | 19 | === TEST 1: If-None-Match true 20 | --- config 21 | location /t { 22 | content_by_lua ' 23 | ngx.header["ETag"] = "123456789" 24 | ngx.header.last_modified = "Thu, 10 May 2012 07:50:59 GMT" 25 | ngx.say(ngx.var.http_if_none_match) 26 | '; 27 | } 28 | --- request 29 | GET /t 30 | --- more_headers 31 | If-None-Match: 123456789 32 | If-Modified-Since: Thu, 10 May 2012 07:50:59 GMT 33 | --- response_body 34 | --- error_code: 304 35 | --- no_error_log 36 | [error] 37 | 38 | 39 | 40 | === TEST 2: If-None-Match false 41 | --- config 42 | location /t { 43 | etag on; 44 | content_by_lua ' 45 | ngx.header["ETag"] = "123456789" 46 | ngx.header.last_modified = "Thu, 10 May 2012 07:50:59 GMT" 47 | ngx.say(ngx.var.http_if_none_match) 48 | '; 49 | } 50 | --- request 51 | GET /t 52 | --- more_headers 53 | If-None-Match: 123456780 54 | If-Modified-Since: Thu, 10 May 2012 07:50:59 GMT 55 | --- response_body 56 | 123456780 57 | --- no_error_log 58 | [error] 59 | --- skip_nginx: 3: < 1.3.3 60 | 61 | 62 | 63 | === TEST 3: Etag clear 64 | --- config 65 | location /t { 66 | etag on; 67 | content_by_lua ' 68 | ngx.header["ETag"] = "123456789" 69 | ngx.header.last_modified = "Thu, 10 May 2012 07:50:59 GMT" 70 | ngx.header["ETag"] = nil 71 | ngx.say(ngx.var.http_if_none_match) 72 | '; 73 | } 74 | --- request 75 | GET /t 76 | --- more_headers 77 | If-None-Match: 123456789 78 | If-Modified-Since: Thu, 10 May 2012 07:50:59 GMT 79 | --- response_body 80 | 123456789 81 | --- no_error_log 82 | [error] 83 | --- skip_nginx: 3: < 1.3.3 84 | 85 | -------------------------------------------------------------------------------- /t/000--init.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket::Lua; 4 | 5 | repeat_each(1); 6 | 7 | plan tests => repeat_each() * (blocks() * 2 + 1); 8 | 9 | $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; 10 | $ENV{TEST_NGINX_MYSQL_PORT} ||= 3306; 11 | 12 | our $http_config = <<'_EOC_'; 13 | upstream database { 14 | drizzle_server 127.0.0.1:$TEST_NGINX_MYSQL_PORT protocol=mysql 15 | dbname=ngx_test user=ngx_test password=ngx_test; 16 | } 17 | _EOC_ 18 | 19 | no_shuffle(); 20 | run_tests(); 21 | 22 | __DATA__ 23 | 24 | === TEST 1: conv_uid - drop table 25 | --- http_config eval: $::http_config 26 | --- config 27 | location = /init { 28 | drizzle_pass database; 29 | drizzle_query "DROP TABLE IF EXISTS conv_uid"; 30 | } 31 | --- request 32 | GET /init 33 | --- error_code: 200 34 | --- timeout: 10 35 | --- no_error_log 36 | [error] 37 | 38 | 39 | 40 | === TEST 2: conv_uid - create table 41 | --- http_config eval: $::http_config 42 | --- config 43 | location = /init { 44 | drizzle_pass database; 45 | drizzle_query "CREATE TABLE conv_uid(id serial primary key, new_uid integer, old_uid integer)"; 46 | } 47 | --- request 48 | GET /init 49 | --- error_code: 200 50 | --- timeout: 10 51 | --- no_error_log 52 | [error] 53 | 54 | 55 | 56 | === TEST 3: conv_uid - insert value 57 | --- http_config eval: $::http_config 58 | --- config 59 | location = /init { 60 | drizzle_pass database; 61 | drizzle_query "INSERT INTO conv_uid(old_uid,new_uid) VALUES(32,56),(35,78)"; 62 | } 63 | --- request 64 | GET /init 65 | --- error_code: 200 66 | --- timeout: 10 67 | --- no_error_log 68 | [error] 69 | 70 | 71 | 72 | === TEST 4: flush data from memcached 73 | --- config 74 | location /flush { 75 | set $memc_cmd flush_all; 76 | memc_pass 127.0.0.1:$TEST_NGINX_MEMCACHED_PORT; 77 | } 78 | --- request 79 | GET /flush 80 | --- error_code: 200 81 | --- response_body eval 82 | "OK\r 83 | " 84 | --- timeout: 10 85 | --- no_error_log 86 | [error] 87 | 88 | -------------------------------------------------------------------------------- /src/ddebug.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Yichun Zhang (agentzh) 4 | */ 5 | 6 | 7 | #ifndef _DDEBUG_H_INCLUDED_ 8 | #define _DDEBUG_H_INCLUDED_ 9 | 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | #if defined(DDEBUG) && (DDEBUG) 17 | 18 | # if (NGX_HAVE_VARIADIC_MACROS) 19 | 20 | # define dd(...) fprintf(stderr, "lua *** %s: ", __func__); \ 21 | fprintf(stderr, __VA_ARGS__); \ 22 | fprintf(stderr, " at %s line %d.\n", __FILE__, __LINE__) 23 | 24 | # else 25 | 26 | #include 27 | #include 28 | 29 | #include 30 | 31 | static ngx_inline void 32 | dd(const char *fmt, ...) { 33 | } 34 | 35 | # endif 36 | 37 | #else 38 | 39 | # if (NGX_HAVE_VARIADIC_MACROS) 40 | 41 | # define dd(...) 42 | 43 | # else 44 | 45 | #include 46 | 47 | static ngx_inline void 48 | dd(const char *fmt, ...) { 49 | } 50 | 51 | # endif 52 | 53 | #endif 54 | 55 | #if defined(DDEBUG) && (DDEBUG) 56 | 57 | #define dd_check_read_event_handler(r) \ 58 | dd("r->read_event_handler = %s", \ 59 | r->read_event_handler == ngx_http_block_reading ? \ 60 | "ngx_http_block_reading" : \ 61 | r->read_event_handler == ngx_http_test_reading ? \ 62 | "ngx_http_test_reading" : \ 63 | r->read_event_handler == ngx_http_request_empty_handler ? \ 64 | "ngx_http_request_empty_handler" : "UNKNOWN") 65 | 66 | #define dd_check_write_event_handler(r) \ 67 | dd("r->write_event_handler = %s", \ 68 | r->write_event_handler == ngx_http_handler ? \ 69 | "ngx_http_handler" : \ 70 | r->write_event_handler == ngx_http_core_run_phases ? \ 71 | "ngx_http_core_run_phases" : \ 72 | r->write_event_handler == ngx_http_request_empty_handler ? \ 73 | "ngx_http_request_empty_handler" : "UNKNOWN") 74 | 75 | #else 76 | 77 | #define dd_check_read_event_handler(r) 78 | #define dd_check_write_event_handler(r) 79 | 80 | #endif 81 | 82 | 83 | #endif /* _DDEBUG_H_INCLUDED_ */ 84 | 85 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 86 | -------------------------------------------------------------------------------- /t/072-conditional-get.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | use Test::Nginx::Socket::Lua; 3 | use t::StapThread; 4 | 5 | our $GCScript = $t::StapThread::GCScript; 6 | our $StapScript = $t::StapThread::StapScript; 7 | 8 | #worker_connections(1014); 9 | #master_on(); 10 | #workers(2); 11 | #log_level('warn'); 12 | 13 | repeat_each(2); 14 | 15 | plan tests => repeat_each() * (blocks() * 3 + 2); 16 | 17 | #no_diff(); 18 | #no_long_string(); 19 | run_tests(); 20 | 21 | __DATA__ 22 | 23 | === TEST 1: If-Modified-Since true 24 | --- config 25 | location /lua { 26 | content_by_lua ' 27 | ngx.header.last_modified = "Thu, 10 May 2012 07:50:59 GMT" 28 | ngx.say("hello") 29 | '; 30 | } 31 | --- request 32 | GET /lua 33 | --- more_headers 34 | If-Modified-Since: Thu, 10 May 2012 07:50:59 GMT 35 | --- response_body 36 | --- error_code: 304 37 | --- no_error_log 38 | [error] 39 | 40 | 41 | 42 | === TEST 2: If-Modified-Since true 43 | --- config 44 | location /lua { 45 | if_modified_since before; 46 | content_by_lua ' 47 | ngx.header.last_modified = "Thu, 10 May 2012 07:50:48 GMT" 48 | ngx.say("hello") 49 | '; 50 | } 51 | --- request 52 | GET /lua 53 | --- more_headers 54 | If-Modified-Since: Thu, 10 May 2012 07:50:59 GMT 55 | --- response_body 56 | --- error_code: 304 57 | --- no_error_log 58 | [error] 59 | 60 | 61 | 62 | === TEST 3: If-Unmodified-Since false 63 | --- config 64 | location /lua { 65 | #if_modified_since before; 66 | content_by_lua ' 67 | ngx.header.last_modified = "Thu, 10 May 2012 07:50:48 GMT" 68 | local ok, err = ngx.say("hello") 69 | if not ok then 70 | ngx.log(ngx.WARN, "say failed: ", err) 71 | end 72 | '; 73 | } 74 | --- request 75 | GET /lua 76 | --- more_headers 77 | If-Unmodified-Since: Thu, 10 May 2012 07:50:47 GMT 78 | 79 | --- stap2 eval: $::StapScript 80 | --- stap eval: $::GCScript 81 | --- stap_out 82 | terminate 1: ok 83 | delete thread 1 84 | 85 | --- response_body_like: 412 Precondition Failed 86 | --- error_code: 412 87 | --- error_log 88 | say failed: nginx output filter error 89 | --- no_error_log 90 | [error] 91 | 92 | -------------------------------------------------------------------------------- /t/007-md5.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket::Lua; 4 | 5 | #worker_connections(1014); 6 | #master_process_enabled(1); 7 | log_level('warn'); 8 | 9 | repeat_each(2); 10 | 11 | plan tests => repeat_each() * (blocks() * 2); 12 | 13 | #no_diff(); 14 | #no_long_string(); 15 | run_tests(); 16 | 17 | __DATA__ 18 | 19 | === TEST 1: set md5 hello 20 | --- config 21 | location = /md5 { 22 | content_by_lua 'ngx.say(ngx.md5("hello"))'; 23 | } 24 | --- request 25 | GET /md5 26 | --- response_body 27 | 5d41402abc4b2a76b9719d911017c592 28 | 29 | 30 | 31 | === TEST 2: nil string to ngx.md5 32 | --- config 33 | location = /md5 { 34 | content_by_lua 'ngx.say(ngx.md5(nil))'; 35 | } 36 | --- request 37 | GET /md5 38 | --- response_body 39 | d41d8cd98f00b204e9800998ecf8427e 40 | 41 | 42 | 43 | === TEST 3: null string to ngx.md5 44 | --- config 45 | location /md5 { 46 | content_by_lua 'ngx.say(ngx.md5(""))'; 47 | } 48 | --- request 49 | GET /md5 50 | --- response_body 51 | d41d8cd98f00b204e9800998ecf8427e 52 | 53 | 54 | 55 | === TEST 4: use ngx.md5 in set_by_lua 56 | --- config 57 | location = /md5 { 58 | set_by_lua $a 'return ngx.md5("hello")'; 59 | echo $a; 60 | } 61 | --- request 62 | GET /md5 63 | --- response_body 64 | 5d41402abc4b2a76b9719d911017c592 65 | 66 | 67 | 68 | === TEST 5: use ngx.md5 in set_by_lua (nil) 69 | --- config 70 | location = /md5 { 71 | set_by_lua $a 'return ngx.md5(nil)'; 72 | echo $a; 73 | } 74 | --- request 75 | GET /md5 76 | --- response_body 77 | d41d8cd98f00b204e9800998ecf8427e 78 | 79 | 80 | 81 | === TEST 6: use ngx.md5 in set_by_lua (null string) 82 | --- config 83 | location /md5 { 84 | set_by_lua $a 'return ngx.md5("")'; 85 | echo $a; 86 | } 87 | --- request 88 | GET /md5 89 | --- response_body 90 | d41d8cd98f00b204e9800998ecf8427e 91 | 92 | 93 | 94 | === TEST 7: md5(number) 95 | --- config 96 | location = /md5 { 97 | content_by_lua 'ngx.say(ngx.md5(45))'; 98 | } 99 | --- request 100 | GET /md5 101 | --- response_body 102 | 6c8349cc7260ae62e3b1396831a8398f 103 | 104 | -------------------------------------------------------------------------------- /t/lib/ljson.lua: -------------------------------------------------------------------------------- 1 | local ngx_null = ngx.null 2 | local tostring = tostring 3 | local byte = string.byte 4 | local gsub = string.gsub 5 | local sort = table.sort 6 | local pairs = pairs 7 | local ipairs = ipairs 8 | local concat = table.concat 9 | 10 | local ok, new_tab = pcall(require, "table.new") 11 | if not ok then 12 | new_tab = function (narr, nrec) return {} end 13 | end 14 | 15 | local _M = {} 16 | 17 | local metachars = { 18 | ['\t'] = '\\t', 19 | ["\\"] = "\\\\", 20 | ['"'] = '\\"', 21 | ['\r'] = '\\r', 22 | ['\n'] = '\\n', 23 | } 24 | 25 | local function encode_str(s) 26 | -- XXX we will rewrite this when string.buffer is implemented 27 | -- in LuaJIT 2.1 because string.gsub cannot be JIT compiled. 28 | return gsub(s, '["\\\r\n\t]', metachars) 29 | end 30 | 31 | local function is_arr(t) 32 | local exp = 1 33 | for k, _ in pairs(t) do 34 | if k ~= exp then 35 | return nil 36 | end 37 | exp = exp + 1 38 | end 39 | return exp - 1 40 | end 41 | 42 | local encode 43 | 44 | encode = function (v) 45 | if v == nil or v == ngx_null then 46 | return "null" 47 | end 48 | 49 | local typ = type(v) 50 | if typ == 'string' then 51 | return '"' .. encode_str(v) .. '"' 52 | end 53 | 54 | if typ == 'number' or typ == 'boolean' then 55 | return tostring(v) 56 | end 57 | 58 | if typ == 'table' then 59 | local n = is_arr(v) 60 | if n then 61 | local bits = new_tab(n, 0) 62 | for i, elem in ipairs(v) do 63 | bits[i] = encode(elem) 64 | end 65 | return "[" .. concat(bits, ",") .. "]" 66 | end 67 | 68 | local keys = {} 69 | local i = 0 70 | for key, _ in pairs(v) do 71 | i = i + 1 72 | keys[i] = key 73 | end 74 | sort(keys) 75 | 76 | local bits = new_tab(0, i) 77 | i = 0 78 | for _, key in ipairs(keys) do 79 | i = i + 1 80 | bits[i] = encode(key) .. ":" .. encode(v[key]) 81 | end 82 | return "{" .. concat(bits, ",") .. "}" 83 | end 84 | 85 | return '"<' .. typ .. '>"' 86 | end 87 | _M.encode = encode 88 | 89 | return _M 90 | -------------------------------------------------------------------------------- /src/ngx_http_lua_phase.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Yichun Zhang (agentzh) 4 | */ 5 | 6 | 7 | #ifndef DDEBUG 8 | #define DDEBUG 0 9 | #endif 10 | #include "ddebug.h" 11 | 12 | 13 | #include "ngx_http_lua_phase.h" 14 | #include "ngx_http_lua_util.h" 15 | #include "ngx_http_lua_ctx.h" 16 | 17 | 18 | static int ngx_http_lua_ngx_get_phase(lua_State *L); 19 | 20 | 21 | static int 22 | ngx_http_lua_ngx_get_phase(lua_State *L) 23 | { 24 | ngx_http_request_t *r; 25 | ngx_http_lua_ctx_t *ctx; 26 | 27 | r = ngx_http_lua_get_req(L); 28 | 29 | /* If we have no request object, assume we are called from the "init" 30 | * phase. */ 31 | 32 | if (r == NULL) { 33 | lua_pushliteral(L, "init"); 34 | return 1; 35 | } 36 | 37 | ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); 38 | if (ctx == NULL) { 39 | return luaL_error(L, "no request ctx found"); 40 | } 41 | 42 | switch (ctx->context) { 43 | case NGX_HTTP_LUA_CONTEXT_INIT_WORKER: 44 | lua_pushliteral(L, "init_worker"); 45 | break; 46 | 47 | case NGX_HTTP_LUA_CONTEXT_SET: 48 | lua_pushliteral(L, "set"); 49 | break; 50 | 51 | case NGX_HTTP_LUA_CONTEXT_REWRITE: 52 | lua_pushliteral(L, "rewrite"); 53 | break; 54 | 55 | case NGX_HTTP_LUA_CONTEXT_ACCESS: 56 | lua_pushliteral(L, "access"); 57 | break; 58 | 59 | case NGX_HTTP_LUA_CONTEXT_CONTENT: 60 | lua_pushliteral(L, "content"); 61 | break; 62 | 63 | case NGX_HTTP_LUA_CONTEXT_LOG: 64 | lua_pushliteral(L, "log"); 65 | break; 66 | 67 | case NGX_HTTP_LUA_CONTEXT_HEADER_FILTER: 68 | lua_pushliteral(L, "header_filter"); 69 | break; 70 | 71 | case NGX_HTTP_LUA_CONTEXT_BODY_FILTER: 72 | lua_pushliteral(L, "body_filter"); 73 | break; 74 | 75 | case NGX_HTTP_LUA_CONTEXT_TIMER: 76 | lua_pushliteral(L, "timer"); 77 | break; 78 | 79 | default: 80 | return luaL_error(L, "unknown phase: %d", (int) ctx->context); 81 | } 82 | 83 | return 1; 84 | } 85 | 86 | 87 | void 88 | ngx_http_lua_inject_phase_api(lua_State *L) 89 | { 90 | lua_pushcfunction(L, ngx_http_lua_ngx_get_phase); 91 | lua_setfield(L, -2, "get_phase"); 92 | } 93 | 94 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 95 | -------------------------------------------------------------------------------- /misc/recv-until-pm/t/sanity.t: -------------------------------------------------------------------------------- 1 | # vi:ft= 2 | 3 | use 5.10.1; 4 | use Test::Base; 5 | use RecvUntil; 6 | 7 | plan tests => 1 * blocks(); 8 | 9 | run { 10 | my $block = shift; 11 | my $name = $block->name; 12 | my $pat = $block->pat // die "$name: No --- pat found"; 13 | my $txt = $block->txt // die "$name: No --- txt found"; 14 | 15 | my $expected = $block->out // die "$name: No --- out found"; 16 | 17 | my $it = RecvUntil::recv_until($pat); 18 | is $it->($txt), $expected, "$name: output ok"; 19 | }; 20 | 21 | __DATA__ 22 | 23 | === TEST 1: 24 | --- pat: abcabd 25 | --- txt: abcabcabd 26 | --- out: abc 27 | 28 | 29 | 30 | === TEST 2: 31 | --- pat: aa 32 | --- txt: abcabcaad 33 | --- out: abcabc 34 | 35 | 36 | 37 | === TEST 3: 38 | --- pat: ab 39 | --- txt: bbcabcaad 40 | --- out: bbc 41 | 42 | 43 | 44 | === TEST 4: 45 | --- pat: aaa 46 | --- txt: abaabcaaaef 47 | --- out: abaabc 48 | 49 | 50 | 51 | === TEST 5: 52 | --- pat: aaaaad 53 | --- txt: baaaaaaaaeaaaaaaadf 54 | --- out: baaaaaaaaeaa 55 | 56 | 57 | 58 | === TEST 6: 59 | --- pat: abacadae 60 | --- txt: a 61 | --- out: 62 | 63 | 64 | 65 | === TEST 7: 66 | --- pat: abacadae 67 | --- txt: ababacadae 68 | --- out: ab 69 | 70 | 71 | 72 | === TEST 8: 73 | --- pat: abacadae 74 | --- txt: abacabacadae 75 | --- out: abac 76 | 77 | 78 | 79 | === TEST 9: 80 | --- pat: abacadae 81 | --- txt: abaabacadae 82 | --- out: aba 83 | 84 | 85 | 86 | === TEST 10: 87 | --- pat: abacadae 88 | --- txt: abacadabacadae 89 | --- out: abacad 90 | 91 | 92 | 93 | === TEST 11: 94 | --- pat: abcabdabcabe 95 | --- txt: abcabdabcabdabcabe 96 | --- out: abcabd 97 | 98 | 99 | 100 | === TEST 12: 101 | --- pat: abcabdabcabe 102 | --- txt: abcabdabcabcabdabcabe 103 | --- out: abcabdabc 104 | 105 | 106 | 107 | === TEST 13: 108 | --- pat: abcabdabcabe 109 | --- txt: abcabcabdabcabe 110 | --- out: abc 111 | 112 | 113 | 114 | === TEST 14: 115 | --- pat: abcabdabcabe 116 | --- txt: ababcabdabcabe 117 | --- out: ab 118 | 119 | 120 | 121 | === TEST 15: 122 | --- pat: abcdef 123 | --- txt: abcabcdef 124 | --- out: abc 125 | 126 | 127 | 128 | === TEST 16: 129 | --- pat: -- abc 130 | --- txt: ---- abc 131 | --- out: -- 132 | 133 | 134 | 135 | === TEST 17: 136 | --- pat: yz--ababyz 137 | --- txt: 138 | --- out: -- 139 | --- SKIP 140 | 141 | -------------------------------------------------------------------------------- /t/090-log-socket-errors.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | use Test::Nginx::Socket::Lua; 3 | 4 | #worker_connections(1014); 5 | #master_on(); 6 | #workers(2); 7 | log_level('warn'); 8 | 9 | repeat_each(2); 10 | #repeat_each(1); 11 | 12 | plan tests => repeat_each() * (blocks() * 3); 13 | 14 | #no_diff(); 15 | #no_long_string(); 16 | run_tests(); 17 | 18 | __DATA__ 19 | 20 | === TEST 1: log socket errors off (tcp) 21 | --- config 22 | location /t { 23 | lua_socket_connect_timeout 1ms; 24 | lua_socket_log_errors off; 25 | content_by_lua ' 26 | local sock = ngx.socket.tcp() 27 | local ok, err = sock:connect("8.8.8.8", 80) 28 | ngx.say(err) 29 | '; 30 | } 31 | --- request 32 | GET /t 33 | --- response_body 34 | timeout 35 | --- no_error_log 36 | [error] 37 | 38 | 39 | 40 | === TEST 2: log socket errors on (tcp) 41 | --- config 42 | location /t { 43 | lua_socket_connect_timeout 1ms; 44 | lua_socket_log_errors on; 45 | content_by_lua ' 46 | local sock = ngx.socket.tcp() 47 | local ok, err = sock:connect("8.8.8.8", 80) 48 | ngx.say(err) 49 | '; 50 | } 51 | --- request 52 | GET /t 53 | --- response_body 54 | timeout 55 | --- error_log 56 | lua tcp socket connect timed out 57 | 58 | 59 | 60 | === TEST 3: log socket errors on (udp) 61 | --- config 62 | location /t { 63 | lua_socket_log_errors on; 64 | lua_socket_read_timeout 1ms; 65 | content_by_lua ' 66 | local sock = ngx.socket.udp() 67 | local ok, err = sock:setpeername("8.8.8.8", 80) 68 | ok, err = sock:receive() 69 | ngx.say(err) 70 | '; 71 | } 72 | --- request 73 | GET /t 74 | --- response_body 75 | timeout 76 | --- error_log 77 | lua udp socket read timed out 78 | 79 | 80 | 81 | === TEST 4: log socket errors off (udp) 82 | --- config 83 | location /t { 84 | lua_socket_log_errors off; 85 | lua_socket_read_timeout 1ms; 86 | content_by_lua ' 87 | local sock = ngx.socket.udp() 88 | local ok, err = sock:setpeername("8.8.8.8", 80) 89 | ok, err = sock:receive() 90 | ngx.say(err) 91 | '; 92 | } 93 | --- request 94 | GET /t 95 | --- response_body 96 | timeout 97 | --- no_error_log 98 | [error] 99 | 100 | -------------------------------------------------------------------------------- /src/ngx_http_lua_script.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Yichun Zhang (agentzh) 4 | */ 5 | 6 | 7 | #ifndef _NGX_HTTP_LUA_SCRIPT_H_INCLUDED_ 8 | #define _NGX_HTTP_LUA_SCRIPT_H_INCLUDED_ 9 | 10 | 11 | #include "ngx_http_lua_common.h" 12 | 13 | 14 | typedef struct { 15 | ngx_log_t *log; 16 | ngx_pool_t *pool; 17 | ngx_str_t *source; 18 | 19 | ngx_array_t **lengths; 20 | ngx_array_t **values; 21 | 22 | ngx_uint_t variables; 23 | 24 | unsigned complete_lengths:1; 25 | unsigned complete_values:1; 26 | } ngx_http_lua_script_compile_t; 27 | 28 | 29 | typedef struct { 30 | ngx_str_t value; 31 | void *lengths; 32 | void *values; 33 | } ngx_http_lua_complex_value_t; 34 | 35 | 36 | typedef struct { 37 | ngx_log_t *log; 38 | ngx_pool_t *pool; 39 | ngx_str_t *value; 40 | ngx_http_lua_complex_value_t *complex_value; 41 | } ngx_http_lua_compile_complex_value_t; 42 | 43 | 44 | typedef struct { 45 | u_char *ip; 46 | u_char *pos; 47 | 48 | ngx_str_t buf; 49 | 50 | int *captures; 51 | ngx_uint_t ncaptures; 52 | u_char *captures_data; 53 | 54 | unsigned skip:1; 55 | 56 | ngx_log_t *log; 57 | } ngx_http_lua_script_engine_t; 58 | 59 | 60 | typedef void (*ngx_http_lua_script_code_pt) (ngx_http_lua_script_engine_t *e); 61 | typedef size_t (*ngx_http_lua_script_len_code_pt) 62 | (ngx_http_lua_script_engine_t *e); 63 | 64 | 65 | typedef struct { 66 | ngx_http_lua_script_code_pt code; 67 | uintptr_t len; 68 | } ngx_http_lua_script_copy_code_t; 69 | 70 | 71 | typedef struct { 72 | ngx_http_lua_script_code_pt code; 73 | uintptr_t n; 74 | } ngx_http_lua_script_capture_code_t; 75 | 76 | 77 | ngx_int_t ngx_http_lua_compile_complex_value( 78 | ngx_http_lua_compile_complex_value_t *ccv); 79 | ngx_int_t ngx_http_lua_complex_value(ngx_http_request_t *r, ngx_str_t *subj, 80 | size_t offset, ngx_int_t count, int *cap, 81 | ngx_http_lua_complex_value_t *val, luaL_Buffer *luabuf); 82 | 83 | 84 | #endif /* _NGX_HTTP_LUA_SCRIPT_H_INCLUDED_ */ 85 | 86 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 87 | -------------------------------------------------------------------------------- /t/102-req-start-time.t: -------------------------------------------------------------------------------- 1 | # -*- mode: conf -*- 2 | # vim:set ft= ts=4 sw=4 et fdm=marker: 3 | 4 | use Test::Nginx::Socket::Lua; 5 | 6 | #worker_connections(1014); 7 | #master_process_enabled(1); 8 | log_level('warn'); 9 | 10 | repeat_each(2); 11 | 12 | plan tests => repeat_each() * (blocks() * 3); 13 | 14 | #no_diff(); 15 | no_long_string(); 16 | run_tests(); 17 | 18 | __DATA__ 19 | 20 | === TEST 1: start time 21 | --- config 22 | location = /start { 23 | content_by_lua 'ngx.say(ngx.req.start_time())'; 24 | } 25 | --- request 26 | GET /start 27 | --- response_body_like: ^\d{10,}(\.\d+)?$ 28 | --- no_error_log 29 | [error] 30 | 31 | 32 | 33 | === TEST 2: start time in set_by_lua 34 | --- config 35 | location = /start { 36 | set_by_lua $a 'return ngx.req.start_time()'; 37 | echo $a; 38 | } 39 | --- request 40 | GET /start 41 | --- response_body_like: ^\d{10,}(\.\d+)?$ 42 | --- no_error_log 43 | [error] 44 | 45 | 46 | 47 | === TEST 3: request time 48 | --- config 49 | location = /req_time { 50 | content_by_lua ' 51 | ngx.sleep(0.1) 52 | 53 | local req_time = ngx.now() - ngx.req.start_time() 54 | 55 | ngx.say(req_time) 56 | ngx.say(ngx.req.start_time() < ngx.now()) 57 | '; 58 | } 59 | --- request 60 | GET /req_time 61 | --- response_body_like chop 62 | ^(?:0\.[12]|0\.099)\d* 63 | true$ 64 | --- no_error_log 65 | [error] 66 | 67 | 68 | 69 | === TEST 4: request time update 70 | --- config 71 | location = /req_time { 72 | content_by_lua ' 73 | ngx.sleep(0.1) 74 | 75 | local req_time = ngx.now() - ngx.req.start_time() 76 | 77 | ngx.sleep(0.1) 78 | 79 | ngx.update_time() 80 | 81 | local req_time_updated = ngx.now() - ngx.req.start_time() 82 | 83 | ngx.say(req_time) 84 | ngx.say(req_time_updated) 85 | ngx.say(req_time_updated > req_time) 86 | '; 87 | } 88 | --- request 89 | GET /req_time 90 | --- response_body_like chomp 91 | ^(?:0\.[12]|0\.099)\d* 92 | 0\.\d+ 93 | true$ 94 | --- no_error_log 95 | [error] 96 | 97 | 98 | 99 | === TEST 5: init_by_lua 100 | --- http_config 101 | init_by_lua ' 102 | time = ngx.req.start_time() 103 | '; 104 | --- config 105 | location = /t { 106 | content_by_lua ' 107 | ngx.say(time) 108 | '; 109 | } 110 | --- request 111 | GET /t 112 | --- response_body 113 | --- no_error_log 114 | [error] 115 | --- SKIP 116 | 117 | -------------------------------------------------------------------------------- /util/revim: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # vim:set ft=perl ts=4 sw=4 et fdm=marker: 3 | # 4 | # revim - add customized vim modeline for given files 5 | # Copyright (c) 2010 chaoslawful 6 | 7 | use strict; 8 | use warnings; 9 | use Getopt::Std; 10 | 11 | my %opts; 12 | 13 | getopts('hm:', \%opts); 14 | 15 | if($opts{h} or !@ARGV) { 16 | die <] src/* 18 | 19 | In , the following placeholder(s) can be used: 20 | 21 | * %t - Expands to vim file type. E.g. 'c' for .c files, 'perl' for .pl files. 22 | EOT 23 | } 24 | 25 | my $vim_ml = $opts{m} || "vim:set ft=%t ts=4 sw=4 et fdm=marker:"; 26 | my @files = map glob, @ARGV; 27 | for my $file (@files) { 28 | next if -d $file; 29 | my ($ft, $ml) = detect_filetype($file, $vim_ml); 30 | next if !defined($ft); 31 | revim($file, $ml); 32 | } 33 | 34 | sub detect_filetype 35 | { 36 | my ($f, $tmpl) = @_; 37 | my ($ft, $lcmt, $rcmt); 38 | my %phs; 39 | 40 | if($f =~ /.([cC]|[hH])$/) { 41 | $ft = "c"; 42 | ($lcmt, $rcmt) = ("/* ", " */"); 43 | } elsif($f =~ /.(pl|pm)$/) { 44 | $ft = "perl"; 45 | ($lcmt, $rcmt) = ("# ", ""); 46 | } elsif($f =~ /.t_?$/) { 47 | # assuming tests are written in perl 48 | $ft = "perl"; 49 | ($lcmt, $rcmt) = ("# ", ""); 50 | } else { 51 | $ft = undef; 52 | } 53 | 54 | if(defined($ft)) { 55 | %phs = ( 56 | "%t" => $ft, 57 | ); 58 | 59 | $tmpl =~ s/(%[a-z])/$phs{$1}/ge; 60 | $tmpl =~ s/^/$lcmt/; 61 | $tmpl =~ s/$/$rcmt/; 62 | 63 | return ($ft, $tmpl); 64 | } 65 | 66 | return (undef, undef); 67 | } 68 | 69 | sub revim 70 | { 71 | my ($f, $ml) = @_; 72 | my @lines; 73 | 74 | open my $in, $f 75 | or die "Can't open $f for reading: $!"; 76 | while(<$in>) { 77 | push(@lines, $_); 78 | } 79 | close $in; 80 | 81 | my @nlines = grep {!/\bvim?:/} @lines; 82 | warn "revim: $f:\tremoved existing vim modeline.\n" 83 | if(@nlines != @lines); 84 | 85 | if($nlines[0] =~ /^#!/) { # has shebang line 86 | my $shebang = shift @nlines; 87 | unshift(@nlines, $shebang, "$ml\n"); 88 | } else { 89 | unshift(@nlines, "$ml\n"); 90 | } 91 | 92 | my $text = join '', @nlines; 93 | 94 | open my $out, "> $f" 95 | or die "Can't open $f for writing: $!"; 96 | binmode $out; 97 | print $out $text; 98 | close $out; 99 | 100 | warn "revim: $f:\tdone.\n"; 101 | } 102 | 103 | -------------------------------------------------------------------------------- /util/build2.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # this script is for developers only. 4 | # dependent on the ngx-build script from the nginx-devel-utils repostory: 5 | # https://github.com/openresty/nginx-devel-utils/blob/master/ngx-build 6 | # the resulting nginx is located at ./work/nginx/sbin/nginx 7 | 8 | root=`pwd` 9 | version=${1:-1.4.1} 10 | home=~ 11 | force=$2 12 | 13 | # the ngx-build script is from https://github.com/agentzh/nginx-devel-utils 14 | 15 | #--add-module=$home/work/nginx_upload_module-2.2.0 \ 16 | 17 | #--without-pcre \ 18 | #--without-http_rewrite_module \ 19 | #--without-http_autoindex_module \ 20 | #--with-cc=gcc46 \ 21 | #--with-cc=clang \ 22 | #--without-http_referer_module \ 23 | #--with-http_v2_module \ 24 | #--with-http_spdy_module \ 25 | 26 | time ngx-build $force $version \ 27 | --with-ipv6 \ 28 | --with-cc-opt="-I$PCRE_INC" \ 29 | --with-http_realip_module \ 30 | --with-http_ssl_module \ 31 | --add-module=$root/../ndk-nginx-module \ 32 | --add-module=$root/../set-misc-nginx-module \ 33 | --with-ld-opt="-L$PCRE_LIB -Wl,-rpath,$PCRE_LIB:$LIBDRIZZLE_LIB:/usr/local/lib" \ 34 | --without-mail_pop3_module \ 35 | --without-mail_imap_module \ 36 | --with-http_image_filter_module \ 37 | --without-mail_smtp_module \ 38 | --without-http_upstream_ip_hash_module \ 39 | --without-http_memcached_module \ 40 | --without-http_auth_basic_module \ 41 | --without-http_userid_module \ 42 | --add-module=$home/work/nginx/ngx_http_auth_request_module-0.2 \ 43 | --add-module=$root/../echo-nginx-module \ 44 | --add-module=$root/../memc-nginx-module \ 45 | --add-module=$root/../srcache-nginx-module \ 46 | --add-module=$root \ 47 | --add-module=$root/../lua-upstream-nginx-module \ 48 | --add-module=$root/../headers-more-nginx-module \ 49 | --add-module=$root/../drizzle-nginx-module \ 50 | --add-module=$root/../rds-json-nginx-module \ 51 | --add-module=$root/../coolkit-nginx-module \ 52 | --add-module=$root/../redis2-nginx-module \ 53 | --add-module=$root/t/data/fake-module \ 54 | --with-http_gunzip_module \ 55 | --with-http_dav_module \ 56 | --with-select_module \ 57 | --with-poll_module \ 58 | $opts \ 59 | --with-debug 60 | 61 | -------------------------------------------------------------------------------- /dtrace/ngx_lua_provider.d: -------------------------------------------------------------------------------- 1 | provider nginx_lua { 2 | probe http__lua__info(char *s); 3 | 4 | /* lua_State *L */ 5 | probe http__lua__register__preload__package(void *L, u_char *pkg); 6 | 7 | probe http__lua__req__socket__consume__preread(ngx_http_request_t *r, 8 | u_char *data, size_t len); 9 | 10 | /* lua_State *parent, lua_State *child */ 11 | probe http__lua__user__coroutine__create(ngx_http_request_t *r, 12 | void *parent, void *child); 13 | 14 | /* lua_State *parent, lua_State *child */ 15 | probe http__lua__user__coroutine__resume(ngx_http_request_t *r, 16 | void *parent, void *child); 17 | 18 | /* lua_State *parent, lua_State *child */ 19 | probe http__lua__user__coroutine__yield(ngx_http_request_t *r, 20 | void *parent, void *child); 21 | 22 | /* lua_State *L */ 23 | probe http__lua__thread__yield(ngx_http_request_t *r, void *L); 24 | 25 | /* ngx_http_lua_socket_tcp_upstream_t *u */ 26 | probe http__lua__socket__tcp__send__start(ngx_http_request_t *r, 27 | void *u, u_char *data, size_t len); 28 | 29 | /* ngx_http_lua_socket_tcp_upstream_t *u */ 30 | probe http__lua__socket__tcp__receive__done(ngx_http_request_t *r, 31 | void *u, u_char *data, size_t len); 32 | 33 | /* ngx_http_lua_socket_tcp_upstream_t *u */ 34 | probe http__lua__socket__tcp__setkeepalive__buf__unread( 35 | ngx_http_request_t *r, void *u, u_char *data, size_t len); 36 | 37 | /* lua_State *creator, lua_State *newthread */ 38 | probe http__lua__user__thread__spawn(ngx_http_request_t *r, 39 | void *creator, void *newthread); 40 | 41 | /* lua_State *thread, ngx_http_lua_ctx_t *ctx */ 42 | probe http__lua__thread__delete(ngx_http_request_t *r, void *thread, void *ctx); 43 | 44 | /* lua_State *thread */ 45 | probe http__lua__run__posted__thread(ngx_http_request_t *r, void *thread, 46 | int status); 47 | 48 | probe http__lua__coroutine__done(ngx_http_request_t *r, void *co, 49 | int success); 50 | 51 | /* lua_State *parent, lua_State *child */ 52 | probe http__lua__user__thread__wait(void *parent, void *child); 53 | }; 54 | 55 | 56 | #pragma D attributes Evolving/Evolving/Common provider nginx_lua provider 57 | #pragma D attributes Private/Private/Unknown provider nginx_lua module 58 | #pragma D attributes Private/Private/Unknown provider nginx_lua function 59 | #pragma D attributes Private/Private/Common provider nginx_lua name 60 | #pragma D attributes Evolving/Evolving/Common provider nginx_lua args 61 | 62 | -------------------------------------------------------------------------------- /t/012-now.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket::Lua; 4 | 5 | #worker_connections(1014); 6 | #master_process_enabled(1); 7 | log_level('warn'); 8 | 9 | repeat_each(1); 10 | 11 | plan tests => repeat_each() * (blocks() * 2); 12 | 13 | #no_diff(); 14 | no_long_string(); 15 | run_tests(); 16 | 17 | __DATA__ 18 | 19 | === TEST 1: use ngx.localtime in content_by_lua 20 | --- config 21 | location = /now { 22 | content_by_lua 'ngx.say(ngx.localtime())'; 23 | } 24 | --- request 25 | GET /now 26 | --- response_body_like: ^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$ 27 | 28 | 29 | 30 | === TEST 2: use ngx.localtime in set_by_lua 31 | --- config 32 | location = /now { 33 | set_by_lua $a 'return ngx.localtime()'; 34 | echo $a; 35 | } 36 | --- request 37 | GET /now 38 | --- response_body_like: ^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$ 39 | 40 | 41 | 42 | === TEST 3: use ngx.time in set_by_lua 43 | --- config 44 | location = /time { 45 | set_by_lua $a 'return ngx.time()'; 46 | echo $a; 47 | } 48 | --- request 49 | GET /time 50 | --- response_body_like: ^\d{10,}$ 51 | 52 | 53 | 54 | === TEST 4: use ngx.time in content_by_lua 55 | --- config 56 | location = /time { 57 | content_by_lua 'ngx.say(ngx.time())'; 58 | } 59 | --- request 60 | GET /time 61 | --- response_body_like: ^\d{10,}$ 62 | 63 | 64 | 65 | === TEST 5: use ngx.time in content_by_lua 66 | --- config 67 | location = /time { 68 | content_by_lua ' 69 | ngx.say(ngx.time()) 70 | ngx.say(ngx.localtime()) 71 | ngx.say(ngx.utctime()) 72 | ngx.say(ngx.cookie_time(ngx.time())) 73 | '; 74 | } 75 | --- request 76 | GET /time 77 | --- response_body_like chomp 78 | ^\d{10,} 79 | \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} 80 | \d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} 81 | \w+, .*? GMT$ 82 | 83 | 84 | 85 | === TEST 6: use ngx.now in set_by_lua 86 | --- config 87 | location = /time { 88 | set_by_lua $a 'return ngx.now()'; 89 | echo $a; 90 | } 91 | --- request 92 | GET /time 93 | --- response_body_like: ^\d{10,}(\.\d{1,3})?$ 94 | 95 | 96 | 97 | === TEST 7: use ngx.now in content_by_lua 98 | --- config 99 | location = /time { 100 | content_by_lua 'ngx.say(ngx.now())'; 101 | } 102 | --- request 103 | GET /time 104 | --- response_body_like: ^\d{10,}(\.\d{1,3})?$ 105 | 106 | 107 | 108 | === TEST 8: use ngx.update_time & ngx.now in content_by_lua 109 | --- config 110 | location = /time { 111 | content_by_lua ' 112 | ngx.update_time() 113 | ngx.say(ngx.now()) 114 | '; 115 | } 116 | --- request 117 | GET /time 118 | --- response_body_like: ^\d{10,}(\.\d{1,3})?$ 119 | 120 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | work/ 3 | tags 4 | cscope.* 5 | *.mobi 6 | genmobi.sh 7 | .libs 8 | *.swp 9 | *.slo 10 | *.la 11 | *.swo 12 | *.lo 13 | *~ 14 | *.o 15 | print.txt 16 | .rsync 17 | *.tar.gz 18 | dist 19 | build[789] 20 | build 21 | tags 22 | update-readme 23 | *.tmp 24 | test/Makefile 25 | test/blib 26 | test.sh 27 | t.sh 28 | t/t.sh 29 | test/t/servroot/ 30 | releng 31 | reset 32 | *.t_ 33 | src/handler.h 34 | src/util.c 35 | src/module.h 36 | src/module.c 37 | src/drizzle.c 38 | src/processor.h 39 | src/handler.c 40 | src/util.h 41 | src/drizzle.h 42 | src/processor.c 43 | src/output.c 44 | src/output.h 45 | libdrizzle 46 | ctags 47 | src/stream.h 48 | nginx 49 | keepalive 50 | reindex 51 | src/keepalive.c 52 | src/keepalive.h 53 | src/checker.h 54 | src/checker.c 55 | src/quoting.h 56 | src/quoting.c 57 | src/module.h 58 | src/module.c 59 | src/util.h 60 | src/util.c 61 | src/processor.h 62 | src/processor.c 63 | src/rds.h 64 | src/utils.h 65 | src/handler.c 66 | src/handler.h 67 | util/bench 68 | *.html 69 | trace.out* 70 | try.sh 71 | src/cache.c 72 | src/cache.h 73 | src/common.h 74 | src/directive.c 75 | src/directive.h 76 | src/consts.[ch] 77 | src/contentby.[ch] 78 | src/pcrefix.[ch] 79 | src/util.c 80 | src/clfactory.c 81 | src/directive.c 82 | src/conf.h 83 | src/setby.h 84 | src/cache.h 85 | src/hook.c 86 | src/util.h 87 | src/hook.h 88 | src/common.h 89 | src/directive.h 90 | src/conf.c 91 | src/setby.c 92 | src/cache.c 93 | src/module.c 94 | src/clfactory.h 95 | src/capturefilter.[ch] 96 | src/contentby.c 97 | pack 98 | b.sh 99 | src/in.[ch] 100 | src/out.[ch] 101 | go 102 | all.sh 103 | src/accessby.[ch] 104 | src/rewriteby.[ch] 105 | src/patch.[ch] 106 | src/ndk.[ch] 107 | src/control.[ch] 108 | src/output.[ch] 109 | src/variable.[ch] 110 | src/string.[ch] 111 | src/misc.[ch] 112 | src/log.[ch] 113 | src/exception.[ch] 114 | src/subrequest.[ch] 115 | src/time.[ch] 116 | src/regex.[ch] 117 | src/ctx.[ch] 118 | src/args.[ch] 119 | src/headers.[ch] 120 | src/script.[ch] 121 | src/filter.[ch] 122 | src/shdict.[ch] 123 | src/body.[ch] 124 | src/uri.[ch] 125 | src/api.[ch] 126 | src/coroutine.[ch] 127 | src/logby.[ch] 128 | src/sleep.[ch] 129 | a.patch 130 | all 131 | build1[0-9] 132 | g 133 | buildroot/ 134 | src/headerfilterby.[ch] 135 | *.patch 136 | analyze 137 | tsock 138 | a.c 139 | test.lua 140 | build12 141 | ERRORS 142 | src/bodyfilterby.[ch] 143 | src/tcp.[ch] 144 | src/initby.[ch] 145 | src/initworkerby.[ch] 146 | src/socket.[ch] 147 | src/udp.[ch] 148 | src/method.[ch] 149 | tre 150 | src/phase.[ch] 151 | src/probe.h 152 | src/uthread.[ch] 153 | src/timer.[ch] 154 | src/config.[ch] 155 | src/worker.[ch] 156 | src/lex.[ch] 157 | *.plist 158 | lua 159 | ttimer 160 | Makefile 161 | tsubreq 162 | tthread 163 | addr2line 164 | hup 165 | theaders 166 | -------------------------------------------------------------------------------- /src/ngx_http_lua_pcrefix.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Xiaozhe Wang (chaoslawful) 4 | * Copyright (C) Yichun Zhang (agentzh) 5 | */ 6 | 7 | 8 | #ifndef DDEBUG 9 | #define DDEBUG 0 10 | #endif 11 | #include "ddebug.h" 12 | 13 | 14 | #include "ngx_http_lua_pcrefix.h" 15 | #include "stdio.h" 16 | 17 | #if (NGX_PCRE) 18 | 19 | static ngx_pool_t *ngx_http_lua_pcre_pool = NULL; 20 | 21 | static void *(*old_pcre_malloc)(size_t); 22 | static void (*old_pcre_free)(void *ptr); 23 | 24 | 25 | /* XXX: work-around to nginx regex subsystem, must init a memory pool 26 | * to use PCRE functions. As PCRE still has memory-leaking problems, 27 | * and nginx overwrote pcre_malloc/free hooks with its own static 28 | * functions, so nobody else can reuse nginx regex subsystem... */ 29 | static void * 30 | ngx_http_lua_pcre_malloc(size_t size) 31 | { 32 | dd("lua pcre pool is %p", ngx_http_lua_pcre_pool); 33 | 34 | if (ngx_http_lua_pcre_pool) { 35 | return ngx_palloc(ngx_http_lua_pcre_pool, size); 36 | } 37 | 38 | fprintf(stderr, "error: lua pcre malloc failed due to empty pcre pool"); 39 | 40 | return NULL; 41 | } 42 | 43 | 44 | static void 45 | ngx_http_lua_pcre_free(void *ptr) 46 | { 47 | dd("lua pcre pool is %p", ngx_http_lua_pcre_pool); 48 | 49 | if (ngx_http_lua_pcre_pool) { 50 | ngx_pfree(ngx_http_lua_pcre_pool, ptr); 51 | return; 52 | } 53 | 54 | fprintf(stderr, "error: lua pcre free failed due to empty pcre pool"); 55 | } 56 | 57 | 58 | ngx_pool_t * 59 | ngx_http_lua_pcre_malloc_init(ngx_pool_t *pool) 60 | { 61 | ngx_pool_t *old_pool; 62 | 63 | if (pcre_malloc != ngx_http_lua_pcre_malloc) { 64 | 65 | dd("overriding nginx pcre malloc and free"); 66 | 67 | ngx_http_lua_pcre_pool = pool; 68 | 69 | old_pcre_malloc = pcre_malloc; 70 | old_pcre_free = pcre_free; 71 | 72 | pcre_malloc = ngx_http_lua_pcre_malloc; 73 | pcre_free = ngx_http_lua_pcre_free; 74 | 75 | return NULL; 76 | } 77 | 78 | dd("lua pcre pool was %p", ngx_http_lua_pcre_pool); 79 | 80 | old_pool = ngx_http_lua_pcre_pool; 81 | ngx_http_lua_pcre_pool = pool; 82 | 83 | dd("lua pcre pool is %p", ngx_http_lua_pcre_pool); 84 | 85 | return old_pool; 86 | } 87 | 88 | 89 | void 90 | ngx_http_lua_pcre_malloc_done(ngx_pool_t *old_pool) 91 | { 92 | dd("lua pcre pool was %p", ngx_http_lua_pcre_pool); 93 | 94 | ngx_http_lua_pcre_pool = old_pool; 95 | 96 | dd("lua pcre pool is %p", ngx_http_lua_pcre_pool); 97 | 98 | if (old_pool == NULL) { 99 | pcre_malloc = old_pcre_malloc; 100 | pcre_free = old_pcre_free; 101 | } 102 | } 103 | 104 | #endif /* NGX_PCRE */ 105 | 106 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 107 | -------------------------------------------------------------------------------- /src/ngx_http_lua_uri.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Xiaozhe Wang (chaoslawful) 4 | * Copyright (C) Yichun Zhang (agentzh) 5 | */ 6 | 7 | 8 | #ifndef DDEBUG 9 | #define DDEBUG 0 10 | #endif 11 | #include "ddebug.h" 12 | 13 | 14 | #include "ngx_http_lua_uri.h" 15 | #include "ngx_http_lua_util.h" 16 | 17 | 18 | static int ngx_http_lua_ngx_req_set_uri(lua_State *L); 19 | 20 | 21 | void 22 | ngx_http_lua_inject_req_uri_api(ngx_log_t *log, lua_State *L) 23 | { 24 | lua_pushcfunction(L, ngx_http_lua_ngx_req_set_uri); 25 | lua_setfield(L, -2, "set_uri"); 26 | } 27 | 28 | 29 | static int 30 | ngx_http_lua_ngx_req_set_uri(lua_State *L) 31 | { 32 | ngx_http_request_t *r; 33 | size_t len; 34 | u_char *p; 35 | int n; 36 | int jump = 0; 37 | ngx_http_lua_ctx_t *ctx; 38 | 39 | n = lua_gettop(L); 40 | 41 | if (n != 1 && n != 2) { 42 | return luaL_error(L, "expecting 1 or 2 arguments but seen %d", n); 43 | } 44 | 45 | r = ngx_http_lua_get_req(L); 46 | if (r == NULL) { 47 | return luaL_error(L, "no request found"); 48 | } 49 | 50 | ngx_http_lua_check_fake_request(L, r); 51 | 52 | p = (u_char *) luaL_checklstring(L, 1, &len); 53 | 54 | if (len == 0) { 55 | return luaL_error(L, "attempt to use zero-length uri"); 56 | } 57 | 58 | if (n == 2) { 59 | 60 | luaL_checktype(L, 2, LUA_TBOOLEAN); 61 | jump = lua_toboolean(L, 2); 62 | 63 | if (jump) { 64 | 65 | ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); 66 | if (ctx == NULL) { 67 | return luaL_error(L, "no ctx found"); 68 | } 69 | 70 | dd("rewrite: %d, access: %d, content: %d", 71 | (int) ctx->entered_rewrite_phase, 72 | (int) ctx->entered_access_phase, 73 | (int) ctx->entered_content_phase); 74 | 75 | ngx_http_lua_check_context(L, ctx, NGX_HTTP_LUA_CONTEXT_REWRITE); 76 | 77 | ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 78 | "lua set uri jump to \"%*s\"", len, p); 79 | 80 | ngx_http_lua_check_if_abortable(L, ctx); 81 | } 82 | } 83 | 84 | r->uri.data = ngx_palloc(r->pool, len); 85 | if (r->uri.data == NULL) { 86 | return luaL_error(L, "no memory"); 87 | } 88 | 89 | ngx_memcpy(r->uri.data, p, len); 90 | 91 | r->uri.len = len; 92 | 93 | r->internal = 1; 94 | r->valid_unparsed_uri = 0; 95 | 96 | ngx_http_set_exten(r); 97 | 98 | if (jump) { 99 | r->uri_changed = 1; 100 | 101 | return lua_yield(L, 0); 102 | } 103 | 104 | r->valid_location = 0; 105 | r->uri_changed = 0; 106 | 107 | return 0; 108 | } 109 | 110 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 111 | -------------------------------------------------------------------------------- /t/064-pcall.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | use Test::Nginx::Socket::Lua; 3 | 4 | worker_connections(1014); 5 | #master_on(); 6 | #workers(4); 7 | #log_level('warn'); 8 | no_root_location(); 9 | 10 | repeat_each(2); 11 | 12 | plan tests => repeat_each() * (blocks() * 3); 13 | 14 | our $HtmlDir = html_dir; 15 | 16 | #$ENV{LUA_CPATH} = "/usr/local/openresty/lualib/?.so;" . $ENV{LUA_CPATH}; 17 | 18 | no_long_string(); 19 | run_tests(); 20 | 21 | __DATA__ 22 | 23 | === TEST 1: pcall works 24 | --- http_config eval 25 | "lua_package_path '$::HtmlDir/?.lua;./?.lua';" 26 | --- config 27 | location = /test { 28 | content_by_lua ' 29 | function f(a, b) 30 | if a == 0 and b == 0 then 31 | error("zero error") 32 | end 33 | 34 | return 23, "hello", true 35 | end 36 | 37 | local res = {pcall(f, 0, 0)} 38 | ngx.say("res len: ", #res) 39 | ngx.say("res: ", unpack(res)) 40 | 41 | res = {pcall(f, 0)} 42 | ngx.say("res len: ", #res) 43 | ngx.say("res: ", unpack(res)) 44 | '; 45 | } 46 | --- request 47 | GET /test 48 | --- response_body eval 49 | qr/^res len: 2 50 | res: falsecontent_by_lua\(nginx\.conf:\d+\):4: zero error 51 | res len: 4 52 | res: true23hellotrue 53 | $/s 54 | --- no_error_log 55 | [error] 56 | 57 | 58 | 59 | === TEST 2: xpcall works 60 | --- http_config eval 61 | "lua_package_path '$::HtmlDir/?.lua;./?.lua';" 62 | --- config 63 | location = /test { 64 | content_by_lua ' 65 | function f(a, b) 66 | if a == 0 and b == 0 then 67 | error("zero error") 68 | end 69 | 70 | return 23, "hello", true 71 | end 72 | 73 | function g() 74 | return f(0, 0) 75 | end 76 | 77 | function h() 78 | return f(0) 79 | end 80 | 81 | function err(...) 82 | ngx.say("error handler called: ", ...) 83 | return "this is the new err" 84 | end 85 | 86 | local res = {xpcall(g, err)} 87 | ngx.say("res len: ", #res) 88 | ngx.say("res: ", unpack(res)) 89 | 90 | res = {xpcall(h, err)} 91 | ngx.say("res len: ", #res) 92 | ngx.say("res: ", unpack(res)) 93 | '; 94 | } 95 | --- request 96 | GET /test 97 | --- response_body eval 98 | qr/^error handler called: content_by_lua\(nginx\.conf:\d+\):4: zero error 99 | res len: 2 100 | res: falsethis is the new err 101 | res len: 4 102 | res: true23hellotrue 103 | $/ 104 | 105 | --- no_error_log 106 | [error] 107 | 108 | -------------------------------------------------------------------------------- /t/024-access/redirect.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket::Lua; 4 | 5 | #worker_connections(1014); 6 | #master_process_enabled(1); 7 | #log_level('warn'); 8 | 9 | repeat_each(2); 10 | #repeat_each(1); 11 | 12 | plan tests => blocks() * repeat_each() * 3; 13 | 14 | #no_diff(); 15 | #no_long_string(); 16 | 17 | run_tests(); 18 | 19 | __DATA__ 20 | 21 | === TEST 1: default 302 22 | --- config 23 | location /read { 24 | access_by_lua ' 25 | ngx.redirect("http://www.taobao.com/foo"); 26 | ngx.say("hi") 27 | '; 28 | content_by_lua 'return'; 29 | } 30 | --- request 31 | GET /read 32 | --- response_headers 33 | Location: http://www.taobao.com/foo 34 | --- response_body_like: 302 Found 35 | --- error_code: 302 36 | 37 | 38 | 39 | === TEST 2: explicit 302 40 | --- config 41 | location /read { 42 | access_by_lua ' 43 | ngx.redirect("http://www.taobao.com/foo", ngx.HTTP_MOVED_TEMPORARILY); 44 | ngx.say("hi") 45 | '; 46 | content_by_lua 'return'; 47 | } 48 | --- request 49 | GET /read 50 | --- response_headers 51 | Location: http://www.taobao.com/foo 52 | --- response_body_like: 302 Found 53 | --- error_code: 302 54 | 55 | 56 | 57 | === TEST 3: explicit 301 58 | --- config 59 | location /read { 60 | access_by_lua ' 61 | ngx.redirect("http://www.taobao.com/foo", ngx.HTTP_MOVED_PERMANENTLY); 62 | ngx.say("hi") 63 | '; 64 | content_by_lua 'return'; 65 | } 66 | --- request 67 | GET /read 68 | --- response_headers 69 | Location: http://www.taobao.com/foo 70 | --- response_body_like: 301 Moved Permanently 71 | --- error_code: 301 72 | 73 | 74 | 75 | === TEST 4: bad rc 76 | --- config 77 | location /read { 78 | access_by_lua ' 79 | ngx.redirect("http://www.taobao.com/foo", 404); 80 | ngx.say("hi") 81 | '; 82 | content_by_lua 'return'; 83 | } 84 | --- request 85 | GET /read 86 | --- response_headers 87 | !Location 88 | --- response_body_like: 500 Internal Server Error 89 | --- error_code: 500 90 | 91 | 92 | 93 | === TEST 5: no args 94 | --- config 95 | location /read { 96 | access_by_lua ' 97 | ngx.redirect() 98 | ngx.say("hi") 99 | '; 100 | content_by_lua 'return'; 101 | } 102 | --- request 103 | GET /read 104 | --- response_headers 105 | !Location 106 | --- response_body_like: 500 Internal Server Error 107 | --- error_code: 500 108 | 109 | 110 | 111 | === TEST 6: relative uri 112 | --- config 113 | location /read { 114 | access_by_lua ' 115 | ngx.redirect("/foo") 116 | ngx.say("hi") 117 | '; 118 | content_by_lua 'return'; 119 | } 120 | --- request 121 | GET /read 122 | --- raw_response_headers_like: Location: /foo\r\n 123 | --- response_body_like: 302 Found 124 | --- error_code: 302 125 | 126 | -------------------------------------------------------------------------------- /t/023-rewrite/redirect.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket::Lua; 4 | 5 | #worker_connections(1014); 6 | #master_process_enabled(1); 7 | #log_level('warn'); 8 | 9 | repeat_each(2); 10 | #repeat_each(1); 11 | 12 | plan tests => blocks() * repeat_each() * 3; 13 | 14 | #no_diff(); 15 | #no_long_string(); 16 | 17 | run_tests(); 18 | 19 | __DATA__ 20 | 21 | === TEST 1: default 302 22 | --- config 23 | location /read { 24 | rewrite_by_lua ' 25 | ngx.redirect("http://www.taobao.com/foo"); 26 | ngx.say("hi") 27 | '; 28 | content_by_lua 'return'; 29 | } 30 | --- request 31 | GET /read 32 | --- response_headers 33 | Location: http://www.taobao.com/foo 34 | --- response_body_like: 302 Found 35 | --- error_code: 302 36 | 37 | 38 | 39 | === TEST 2: explicit 302 40 | --- config 41 | location /read { 42 | rewrite_by_lua ' 43 | ngx.redirect("http://www.taobao.com/foo", ngx.HTTP_MOVED_TEMPORARILY); 44 | ngx.say("hi") 45 | '; 46 | content_by_lua 'return'; 47 | } 48 | --- request 49 | GET /read 50 | --- response_headers 51 | Location: http://www.taobao.com/foo 52 | --- response_body_like: 302 Found 53 | --- error_code: 302 54 | 55 | 56 | 57 | === TEST 3: explicit 301 58 | --- config 59 | location /read { 60 | rewrite_by_lua ' 61 | ngx.redirect("http://www.taobao.com/foo", ngx.HTTP_MOVED_PERMANENTLY); 62 | ngx.say("hi") 63 | '; 64 | content_by_lua 'return'; 65 | } 66 | --- request 67 | GET /read 68 | --- response_headers 69 | Location: http://www.taobao.com/foo 70 | --- response_body_like: 301 Moved Permanently 71 | --- error_code: 301 72 | 73 | 74 | 75 | === TEST 4: bad rc 76 | --- config 77 | location /read { 78 | rewrite_by_lua ' 79 | ngx.redirect("http://www.taobao.com/foo", 404); 80 | ngx.say("hi") 81 | '; 82 | content_by_lua 'return'; 83 | } 84 | --- request 85 | GET /read 86 | --- response_headers 87 | !Location 88 | --- response_body_like: 500 Internal Server Error 89 | --- error_code: 500 90 | 91 | 92 | 93 | === TEST 5: no args 94 | --- config 95 | location /read { 96 | rewrite_by_lua ' 97 | ngx.redirect() 98 | ngx.say("hi") 99 | '; 100 | content_by_lua 'return'; 101 | } 102 | --- request 103 | GET /read 104 | --- response_headers 105 | !Location 106 | --- response_body_like: 500 Internal Server Error 107 | --- error_code: 500 108 | 109 | 110 | 111 | === TEST 6: relative uri 112 | --- config 113 | location /read { 114 | rewrite_by_lua ' 115 | ngx.redirect("/foo") 116 | ngx.say("hi") 117 | '; 118 | content_by_lua 'return'; 119 | } 120 | --- request 121 | GET /read 122 | --- raw_response_headers_like: Location: /foo\r\n 123 | --- response_body_like: 302 Found 124 | --- error_code: 302 125 | 126 | -------------------------------------------------------------------------------- /src/ngx_http_lua_directive.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Xiaozhe Wang (chaoslawful) 4 | * Copyright (C) Yichun Zhang (agentzh) 5 | */ 6 | 7 | 8 | #ifndef _NGX_HTTP_LUA_DIRECTIVE_H_INCLUDED_ 9 | #define _NGX_HTTP_LUA_DIRECTIVE_H_INCLUDED_ 10 | 11 | 12 | #include "ngx_http_lua_common.h" 13 | 14 | 15 | char *ngx_http_lua_shared_dict(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); 16 | char *ngx_http_lua_package_cpath(ngx_conf_t *cf, ngx_command_t *cmd, 17 | void *conf); 18 | char *ngx_http_lua_package_path(ngx_conf_t *cf, ngx_command_t *cmd, 19 | void *conf); 20 | char *ngx_http_lua_content_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, 21 | void *conf); 22 | char *ngx_http_lua_content_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, 23 | void *conf); 24 | char *ngx_http_lua_rewrite_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, 25 | void *conf); 26 | char *ngx_http_lua_rewrite_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, 27 | void *conf); 28 | char *ngx_http_lua_access_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, 29 | void *conf); 30 | char *ngx_http_lua_access_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, 31 | void *conf); 32 | char *ngx_http_lua_log_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, 33 | void *conf); 34 | char *ngx_http_lua_log_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, 35 | void *conf); 36 | char *ngx_http_lua_header_filter_by_lua_block(ngx_conf_t *cf, 37 | ngx_command_t *cmd, void *conf); 38 | char *ngx_http_lua_header_filter_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, 39 | void *conf); 40 | char *ngx_http_lua_body_filter_by_lua_block(ngx_conf_t *cf, 41 | ngx_command_t *cmd, void *conf); 42 | char *ngx_http_lua_body_filter_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, 43 | void *conf); 44 | char *ngx_http_lua_init_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, 45 | void *conf); 46 | char *ngx_http_lua_init_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, 47 | void *conf); 48 | char *ngx_http_lua_init_worker_by_lua_block(ngx_conf_t *cf, 49 | ngx_command_t *cmd, void *conf); 50 | char *ngx_http_lua_init_worker_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, 51 | void *conf); 52 | char *ngx_http_lua_code_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); 53 | 54 | #if defined(NDK) && NDK 55 | 56 | char *ngx_http_lua_set_by_lua_block(ngx_conf_t *cf, ngx_command_t *cmd, 57 | void *conf); 58 | char *ngx_http_lua_set_by_lua(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); 59 | char *ngx_http_lua_set_by_lua_file(ngx_conf_t *cf, ngx_command_t *cmd, 60 | void *conf); 61 | ngx_int_t ngx_http_lua_filter_set_by_lua_inline(ngx_http_request_t *r, 62 | ngx_str_t *val, ngx_http_variable_value_t *v, void *data); 63 | ngx_int_t ngx_http_lua_filter_set_by_lua_file(ngx_http_request_t *r, 64 | ngx_str_t *val, ngx_http_variable_value_t *v, void *data); 65 | 66 | #endif 67 | 68 | char *ngx_http_lua_rewrite_no_postpone(ngx_conf_t *cf, ngx_command_t *cmd, 69 | void *conf); 70 | 71 | 72 | #endif /* _NGX_HTTP_LUA_DIRECTIVE_H_INCLUDED_ */ 73 | 74 | /* vi:set ft=c ts=4 sw=4 et fdm=marker: */ 75 | -------------------------------------------------------------------------------- /t/117-raw-req-socket-timeout.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | 3 | BEGIN { 4 | if (!defined $ENV{LD_PRELOAD}) { 5 | $ENV{LD_PRELOAD} = ''; 6 | } 7 | 8 | if ($ENV{LD_PRELOAD} !~ /\bmockeagain\.so\b/) { 9 | $ENV{LD_PRELOAD} = "mockeagain.so $ENV{LD_PRELOAD}"; 10 | } 11 | 12 | if ($ENV{MOCKEAGAIN} eq 'r') { 13 | $ENV{MOCKEAGAIN} = 'rw'; 14 | 15 | } else { 16 | $ENV{MOCKEAGAIN} = 'w'; 17 | } 18 | 19 | $ENV{TEST_NGINX_EVENT_TYPE} = 'poll'; 20 | $ENV{MOCKEAGAIN_WRITE_TIMEOUT_PATTERN} = 'hello, world'; 21 | $ENV{TEST_NGINX_POSTPONE_OUTPUT} = 1; 22 | } 23 | 24 | use Test::Nginx::Socket::Lua; 25 | use t::StapThread; 26 | 27 | our $GCScript = $t::StapThread::GCScript; 28 | our $StapScript = $t::StapThread::StapScript; 29 | 30 | #worker_connections(1014); 31 | #master_on(); 32 | #workers(2); 33 | #log_level('warn'); 34 | 35 | repeat_each(2); 36 | 37 | plan tests => repeat_each() * (blocks() * 3); 38 | 39 | #no_diff(); 40 | no_long_string(); 41 | run_tests(); 42 | 43 | __DATA__ 44 | 45 | === TEST 1: pending response header data 46 | --- config 47 | server_tokens off; 48 | postpone_output 1; 49 | location = /t { 50 | content_by_lua ' 51 | ngx.send_headers() 52 | ngx.req.read_body() 53 | local sock, err = ngx.req.socket(true) 54 | if not sock then 55 | ngx.log(ngx.ERR, "server: failed to get raw req socket: ", err) 56 | return 57 | end 58 | '; 59 | } 60 | 61 | --- raw_request eval 62 | "GET /t HTTP/1.1\r 63 | Host: localhost\r 64 | Upgrade: mysocket\r 65 | Connection: close\r 66 | \r 67 | " 68 | --- stap2 69 | F(ngx_http_header_filter) { 70 | println("header filter") 71 | } 72 | F(ngx_http_lua_req_socket) { 73 | println("lua req socket") 74 | } 75 | --- response_body 76 | --- error_log 77 | server: failed to get raw req socket: pending data to write 78 | 79 | 80 | 81 | === TEST 2: send timeout 82 | --- config 83 | server_tokens off; 84 | postpone_output 1; 85 | location = /t { 86 | content_by_lua ' 87 | ngx.send_headers() 88 | ngx.req.read_body() 89 | ngx.flush(true) 90 | local sock, err = ngx.req.socket(true) 91 | if not sock then 92 | ngx.log(ngx.ERR, "server: failed to get raw req socket: ", err) 93 | return 94 | end 95 | sock:settimeout(100) 96 | local ok, err = sock:send("hello, world!") 97 | if not ok then 98 | ngx.log(ngx.ERR, "server: failed to send: ", err) 99 | end 100 | ngx.exit(444) 101 | '; 102 | } 103 | 104 | --- raw_request eval 105 | "GET /t HTTP/1.1\r 106 | Host: localhost\r 107 | Upgrade: mysocket\r 108 | Connection: close\r 109 | \r 110 | " 111 | --- ignore_response 112 | --- error_log 113 | lua tcp socket write timed out 114 | server: failed to send: timeout 115 | --- no_error_log 116 | [alert] 117 | 118 | -------------------------------------------------------------------------------- /t/118-use-default-type.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket::Lua; 4 | 5 | repeat_each(2); 6 | 7 | plan tests => repeat_each() * (blocks() * 4); 8 | 9 | our $HtmlDir = html_dir; 10 | 11 | $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; 12 | $ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8'; 13 | 14 | #log_level 'warn'; 15 | log_level 'debug'; 16 | 17 | #no_long_string(); 18 | #no_diff(); 19 | run_tests(); 20 | 21 | __DATA__ 22 | 23 | === TEST 1: lua_use_default_type default on 24 | --- config 25 | location /lua { 26 | default_type text/plain; 27 | content_by_lua ' 28 | ngx.say("hello") 29 | '; 30 | } 31 | --- request 32 | GET /lua 33 | --- response_body 34 | hello 35 | --- response_headers 36 | Content-Type: text/plain 37 | --- no_error_log 38 | [error] 39 | 40 | 41 | 42 | === TEST 2: lua_use_default_type explicitly on 43 | --- config 44 | lua_use_default_type on; 45 | location /lua { 46 | default_type text/plain; 47 | content_by_lua ' 48 | ngx.say("hello") 49 | '; 50 | } 51 | --- request 52 | GET /lua 53 | --- response_body 54 | hello 55 | --- response_headers 56 | Content-Type: text/plain 57 | --- no_error_log 58 | [error] 59 | 60 | 61 | 62 | === TEST 3: lua_use_default_type off 63 | --- config 64 | lua_use_default_type off; 65 | location /lua { 66 | default_type text/plain; 67 | content_by_lua ' 68 | ngx.say("hello") 69 | '; 70 | } 71 | --- request 72 | GET /lua 73 | --- response_body 74 | hello 75 | --- response_headers 76 | !Content-Type 77 | --- no_error_log 78 | [error] 79 | 80 | 81 | 82 | === TEST 4: overriding lua_use_default_type off 83 | --- config 84 | lua_use_default_type off; 85 | location /lua { 86 | lua_use_default_type on; 87 | default_type text/plain; 88 | content_by_lua ' 89 | ngx.say("hello") 90 | '; 91 | } 92 | --- request 93 | GET /lua 94 | --- response_body 95 | hello 96 | --- response_headers 97 | Content-Type: text/plain 98 | --- no_error_log 99 | [error] 100 | 101 | 102 | 103 | === TEST 5: overriding lua_use_default_type on 104 | --- config 105 | lua_use_default_type on; 106 | location /lua { 107 | lua_use_default_type off; 108 | default_type text/plain; 109 | content_by_lua ' 110 | ngx.say("hello") 111 | '; 112 | } 113 | --- request 114 | GET /lua 115 | --- response_body 116 | hello 117 | --- response_headers 118 | !Content-Type 119 | --- no_error_log 120 | [error] 121 | 122 | 123 | 124 | === TEST 6: lua_use_default_type on does not set content type on 304 125 | --- config 126 | lua_use_default_type on; 127 | location /lua { 128 | default_type text/plain; 129 | content_by_lua ' 130 | ngx.status = ngx.HTTP_NOT_MODIFIED 131 | '; 132 | } 133 | --- request 134 | GET /lua 135 | --- response_body 136 | --- response_headers 137 | !Content-Type 138 | --- no_error_log 139 | [error] 140 | --- error_code: 304 141 | -------------------------------------------------------------------------------- /t/024-access/auth.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | use Test::Nginx::Socket::Lua; 3 | 4 | #worker_connections(1014); 5 | #master_process_enabled(1); 6 | #log_level('warn'); 7 | #no_nginx_manager(); 8 | 9 | #repeat_each(1); 10 | repeat_each(2); 11 | 12 | plan tests => repeat_each() * (blocks() * 2 + 1); 13 | 14 | #no_diff(); 15 | no_long_string(); 16 | run_tests(); 17 | 18 | __DATA__ 19 | 20 | === TEST 1: basic test passing 21 | --- config 22 | location /lua { 23 | lua_need_request_body on; 24 | client_max_body_size 100k; 25 | client_body_buffer_size 100k; 26 | 27 | access_by_lua ' 28 | -- check the client IP addr is in our black list 29 | if ngx.var.remote_addr == "132.5.72.3" then 30 | ngx.exit(ngx.HTTP_FORBIDDEN) 31 | end 32 | 33 | -- check if the request body contains bad words 34 | if ngx.var.request_body and string.match(ngx.var.request_body, "fuck") then 35 | return ngx.redirect("/terms_of_use.html") 36 | end 37 | 38 | -- tests passed 39 | '; 40 | 41 | echo Logged in; 42 | } 43 | --- request 44 | GET /lua 45 | --- response_body 46 | Logged in 47 | 48 | 49 | 50 | === TEST 2: bad words in request body 51 | --- config 52 | location /lua { 53 | lua_need_request_body on; 54 | client_max_body_size 100k; 55 | client_body_buffer_size 100k; 56 | 57 | access_by_lua ' 58 | -- check the client IP addr is in our black list 59 | if ngx.var.remote_addr == "132.5.72.3" then 60 | ngx.exit(ngx.HTTP_FORBIDDEN) 61 | end 62 | 63 | -- check if the request body contains bad words 64 | if ngx.var.request_body and string.match(ngx.var.request_body, "fuck") then 65 | return ngx.redirect("/terms_of_use.html") 66 | end 67 | 68 | -- tests passed 69 | '; 70 | 71 | echo Logged in; 72 | } 73 | --- request 74 | POST /lua 75 | He fucks himself! 76 | --- response_body_like: 302 Found 77 | --- response_headers_like 78 | Location: /terms_of_use\.html 79 | --- error_code: 302 80 | 81 | 82 | 83 | === TEST 3: client IP 84 | --- config 85 | location /lua { 86 | lua_need_request_body on; 87 | client_max_body_size 100k; 88 | client_body_buffer_size 100k; 89 | 90 | access_by_lua ' 91 | -- check the client IP addr is in our black list 92 | if ngx.var.remote_addr == "127.0.0.1" then 93 | ngx.exit(ngx.HTTP_FORBIDDEN) 94 | end 95 | 96 | -- check if the request body contains bad words 97 | if ngx.var.request_body and string.match(ngx.var.request_body, "fuck") then 98 | return ngx.redirect("/terms_of_use.html") 99 | end 100 | 101 | -- tests passed 102 | '; 103 | 104 | echo Logged in; 105 | } 106 | --- request 107 | GET /lua 108 | --- response_body_like: 403 Forbidden 109 | --- error_code: 403 110 | 111 | -------------------------------------------------------------------------------- /t/003-errors.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket::Lua; 4 | 5 | repeat_each(1); 6 | 7 | plan tests => blocks() * repeat_each() * 2; 8 | 9 | #$ENV{LUA_PATH} = $ENV{HOME} . '/work/JSON4Lua-0.9.30/json/?.lua'; 10 | 11 | no_long_string(); 12 | 13 | run_tests(); 14 | 15 | __DATA__ 16 | 17 | === TEST 1: syntax error in lua code chunk 18 | --- config 19 | location /lua { 20 | set_by_lua $res "local a 21 | a = a+; 22 | return a"; 23 | echo $res; 24 | } 25 | --- request 26 | GET /lua 27 | --- error_code: 500 28 | --- response_body_like: 500 Internal Server Error 29 | 30 | 31 | 32 | === TEST 2: syntax error in lua file 33 | --- config 34 | location /lua { 35 | set_by_lua_file $res 'html/test.lua'; 36 | echo $res; 37 | } 38 | --- user_files 39 | >>> test.lua 40 | local a 41 | a = 3 +; 42 | return a 43 | --- request 44 | GET /lua 45 | --- error_code: 500 46 | --- response_body_like: 500 Internal Server Error 47 | 48 | 49 | 50 | === TEST 3: syntax error in lua file (from Guang Feng) 51 | --- config 52 | location /lua { 53 | set $res '[{"a":32},{"b":64}]'; 54 | #set $res '[{"friend_userid":1750146},{"friend_userid":1750150},{"friend_userid":1750153},{"friend_userid":1750166},{"friend_userid":1750181},{"friend_userid":1750186},{"friend_userid":1750195},{"friend_userid":1750232}]'; 55 | set_by_lua_file $list 'html/test.lua' $res; 56 | #set_by_lua_file $list 'html/feed.lua' $res; 57 | echo $list; 58 | } 59 | --- user_files 60 | >>> test.lua 61 | -- local j = require('json') 62 | local p = ngx.arg[1] 63 | return p 64 | >>> feed.lua 65 | local s = require("json") 66 | local function explode(d,p) 67 | local t, ll 68 | t={} 69 | ll=0 70 | if(#p == 1) then return p end 71 | while true do 72 | l=string.find(p,d,ll+1,true) 73 | if l~=nil then 74 | table.insert(t, string.sub(p,ll,l-1)) 75 | ll=l+1 76 | else 77 | table.insert(t, string.sub(p,ll)) 78 | break 79 | end 80 | end 81 | return t 82 | end 83 | 84 | local a = explode(',', string.sub(ngx.arg[1], 2, -1)) 85 | local x = {} 86 | for i,v in ipairs(a) do table.insert(x,s.decode(v).friend_userid) end 87 | return table.concat(x,',') 88 | --- request 89 | GET /lua 90 | --- response_body 91 | [{"a":32},{"b":64}] 92 | 93 | 94 | 95 | === TEST 4: 500 in subrequest 96 | --- config 97 | location /main { 98 | content_by_lua ' 99 | local res = ngx.location.capture("/err") 100 | ngx.say(res.status); 101 | '; 102 | } 103 | location /err { 104 | return 500; 105 | } 106 | --- request 107 | GET /main 108 | --- response_body 109 | 500 110 | 111 | 112 | 113 | === TEST 5: drizzle_pass 500 in subrequest 114 | --- config 115 | location /main { 116 | content_by_lua ' 117 | local res = ngx.location.capture("/err") 118 | ngx.say(res.status); 119 | '; 120 | } 121 | location /err { 122 | set $back 'blah-blah'; 123 | drizzle_pass $back; 124 | } 125 | --- request 126 | GET /main 127 | --- response_body 128 | 500 129 | 130 | -------------------------------------------------------------------------------- /t/112-req-header-conn.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket::Lua; 4 | 5 | #worker_connections(1014); 6 | #master_process_enabled(1); 7 | #log_level('warn'); 8 | 9 | repeat_each(2); 10 | 11 | plan tests => repeat_each() * (4 * blocks()); 12 | 13 | #no_diff(); 14 | no_long_string(); 15 | 16 | run_tests(); 17 | 18 | __DATA__ 19 | 20 | === TEST 1: clear the Connection req header 21 | --- config 22 | location /req-header { 23 | rewrite_by_lua ' 24 | ngx.req.set_header("Connection", nil); 25 | '; 26 | 27 | echo "connection: $http_connection"; 28 | } 29 | --- request 30 | GET /req-header 31 | 32 | --- stap 33 | F(ngx_http_lua_rewrite_by_chunk) { 34 | printf("rewrite: conn type: %d\n", $r->headers_in->connection_type) 35 | } 36 | 37 | 38 | F(ngx_http_core_content_phase) { 39 | printf("content: conn type: %d\n", $r->headers_in->connection_type) 40 | } 41 | 42 | --- stap_out 43 | rewrite: conn type: 1 44 | content: conn type: 0 45 | 46 | --- response_body 47 | connection: 48 | --- no_error_log 49 | [error] 50 | 51 | 52 | 53 | === TEST 2: set custom Connection req header (close) 54 | --- config 55 | location /req-header { 56 | rewrite_by_lua ' 57 | ngx.req.set_header("Connection", "CLOSE"); 58 | '; 59 | 60 | echo "connection: $http_connection"; 61 | } 62 | --- request 63 | GET /req-header 64 | 65 | --- stap 66 | F(ngx_http_lua_rewrite_by_chunk) { 67 | printf("rewrite: conn type: %d\n", $r->headers_in->connection_type) 68 | } 69 | 70 | 71 | F(ngx_http_core_content_phase) { 72 | printf("content: conn type: %d\n", $r->headers_in->connection_type) 73 | } 74 | 75 | --- stap_out 76 | rewrite: conn type: 1 77 | content: conn type: 1 78 | 79 | --- response_body 80 | connection: CLOSE 81 | --- no_error_log 82 | [error] 83 | 84 | 85 | 86 | === TEST 3: set custom Connection req header (keep-alive) 87 | --- config 88 | location /req-header { 89 | rewrite_by_lua ' 90 | ngx.req.set_header("Connection", "keep-alive"); 91 | '; 92 | 93 | echo "connection: $http_connection"; 94 | } 95 | --- request 96 | GET /req-header 97 | 98 | --- stap 99 | F(ngx_http_lua_rewrite_by_chunk) { 100 | printf("rewrite: conn type: %d\n", $r->headers_in->connection_type) 101 | } 102 | 103 | 104 | F(ngx_http_core_content_phase) { 105 | printf("content: conn type: %d\n", $r->headers_in->connection_type) 106 | } 107 | 108 | --- stap_out 109 | rewrite: conn type: 1 110 | content: conn type: 2 111 | 112 | --- response_body 113 | connection: keep-alive 114 | --- no_error_log 115 | [error] 116 | 117 | 118 | 119 | === TEST 4: set custom Connection req header (bad) 120 | --- config 121 | location /req-header { 122 | rewrite_by_lua ' 123 | ngx.req.set_header("Connection", "bad"); 124 | '; 125 | 126 | echo "connection: $http_connection"; 127 | } 128 | --- request 129 | GET /req-header 130 | 131 | --- stap 132 | F(ngx_http_lua_rewrite_by_chunk) { 133 | printf("rewrite: conn type: %d\n", $r->headers_in->connection_type) 134 | } 135 | 136 | 137 | F(ngx_http_core_content_phase) { 138 | printf("content: conn type: %d\n", $r->headers_in->connection_type) 139 | } 140 | 141 | --- stap_out 142 | rewrite: conn type: 1 143 | content: conn type: 0 144 | 145 | --- response_body 146 | connection: bad 147 | --- no_error_log 148 | [error] 149 | 150 | -------------------------------------------------------------------------------- /t/083-bad-sock-self.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket::Lua; 4 | 5 | repeat_each(2); 6 | 7 | plan tests => repeat_each() * (blocks() * 3); 8 | 9 | our $HtmlDir = html_dir; 10 | 11 | #$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; 12 | 13 | no_long_string(); 14 | #no_diff(); 15 | #log_level 'warn'; 16 | 17 | run_tests(); 18 | 19 | __DATA__ 20 | 21 | === TEST 1: receive 22 | --- config 23 | location /t { 24 | content_by_lua ' 25 | local sock, err = ngx.req.socket() 26 | sock.receive("l") 27 | '; 28 | } 29 | --- request 30 | POST /t 31 | --- more_headers: Content-Length: 1024 32 | --- response_body_like: 500 Internal Server Error 33 | --- error_code: 500 34 | --- error_log 35 | bad argument #1 to 'receive' (table expected, got string) 36 | 37 | 38 | 39 | === TEST 2: receiveuntil 40 | --- config 41 | location /t { 42 | content_by_lua ' 43 | local sock, err = ngx.req.socket() 44 | sock.receiveuntil(32, "ab") 45 | '; 46 | } 47 | --- request 48 | POST /t 49 | --- more_headers: Content-Length: 1024 50 | --- response_body_like: 500 Internal Server Error 51 | --- error_code: 500 52 | --- error_log 53 | bad argument #1 to 'receiveuntil' (table expected, got number) 54 | 55 | 56 | 57 | === TEST 3: send (bad arg number) 58 | --- config 59 | location /t { 60 | content_by_lua ' 61 | local sock, err = ngx.socket.tcp() 62 | sock.send("hello") 63 | '; 64 | } 65 | --- request 66 | GET /t 67 | --- response_body_like: 500 Internal Server Error 68 | --- error_code: 500 69 | --- error_log 70 | expecting 2 arguments (including the object), but got 1 71 | 72 | 73 | 74 | === TEST 4: send (bad self) 75 | --- config 76 | location /t { 77 | content_by_lua ' 78 | local sock, err = ngx.socket.tcp() 79 | sock.send("hello", 32) 80 | '; 81 | } 82 | --- request 83 | GET /t 84 | --- response_body_like: 500 Internal Server Error 85 | --- error_code: 500 86 | --- error_log 87 | bad argument #1 to 'send' (table expected, got string) 88 | 89 | 90 | 91 | === TEST 5: getreusedtimes (bad self) 92 | --- config 93 | location /t { 94 | content_by_lua ' 95 | local sock, err = ngx.socket.tcp() 96 | sock.getreusedtimes(2) 97 | '; 98 | } 99 | --- request 100 | GET /t 101 | --- response_body_like: 500 Internal Server Error 102 | --- error_code: 500 103 | --- error_log 104 | bad argument #1 to 'getreusedtimes' (table expected, got number) 105 | 106 | 107 | 108 | === TEST 6: close (bad self) 109 | --- config 110 | location /t { 111 | content_by_lua ' 112 | local sock, err = ngx.socket.tcp() 113 | sock.close(2) 114 | '; 115 | } 116 | --- request 117 | GET /t 118 | --- response_body_like: 500 Internal Server Error 119 | --- error_code: 500 120 | --- error_log 121 | bad argument #1 to 'close' (table expected, got number) 122 | 123 | 124 | 125 | === TEST 7: setkeepalive (bad self) 126 | --- config 127 | location /t { 128 | content_by_lua ' 129 | local sock, err = ngx.socket.tcp() 130 | sock.setkeepalive(2) 131 | '; 132 | } 133 | --- request 134 | GET /t 135 | --- response_body_like: 500 Internal Server Error 136 | --- error_code: 500 137 | --- error_log 138 | bad argument #1 to 'setkeepalive' (table expected, got number) 139 | 140 | -------------------------------------------------------------------------------- /valgrind.suppress: -------------------------------------------------------------------------------- 1 | { 2 | 3 | Memcheck:Addr1 4 | fun:ngx_init_cycle 5 | fun:ngx_master_process_cycle 6 | fun:main 7 | } 8 | { 9 | 10 | Memcheck:Addr4 11 | fun:ngx_init_cycle 12 | fun:ngx_master_process_cycle 13 | fun:main 14 | } 15 | { 16 | 17 | Memcheck:Cond 18 | fun:ngx_vslprintf 19 | fun:ngx_snprintf 20 | fun:ngx_sock_ntop 21 | fun:ngx_event_accept 22 | fun:ngx_epoll_process_events 23 | fun:ngx_process_events_and_timers 24 | } 25 | { 26 | 27 | Memcheck:Cond 28 | fun:ngx_vslprintf 29 | fun:ngx_snprintf 30 | fun:ngx_sock_ntop 31 | fun:ngx_event_accept 32 | fun:ngx_epoll_process_events 33 | fun:ngx_process_events_and_timers 34 | } 35 | { 36 | 37 | Memcheck:Addr1 38 | fun:ngx_vslprintf 39 | fun:ngx_snprintf 40 | fun:ngx_sock_ntop 41 | fun:ngx_event_accept 42 | } 43 | { 44 | 45 | exp-sgcheck:SorG 46 | fun:ngx_http_lua_ndk_set_var_get 47 | } 48 | { 49 | 50 | exp-sgcheck:SorG 51 | fun:ngx_http_variables_init_vars 52 | fun:ngx_http_block 53 | } 54 | { 55 | 56 | exp-sgcheck:SorG 57 | fun:ngx_conf_parse 58 | } 59 | { 60 | 61 | exp-sgcheck:SorG 62 | fun:ngx_vslprintf 63 | fun:ngx_log_error_core 64 | } 65 | { 66 | 67 | Memcheck:Param 68 | epoll_ctl(event) 69 | fun:epoll_ctl 70 | } 71 | { 72 | 73 | Memcheck:Cond 74 | fun:ngx_conf_flush_files 75 | fun:ngx_single_process_cycle 76 | } 77 | { 78 | 79 | Memcheck:Cond 80 | fun:memcpy 81 | fun:ngx_vslprintf 82 | fun:ngx_log_error_core 83 | fun:ngx_http_charset_header_filter 84 | } 85 | { 86 | 87 | Memcheck:Param 88 | socketcall.setsockopt(optval) 89 | fun:setsockopt 90 | fun:drizzle_state_connect 91 | } 92 | { 93 | 94 | Memcheck:Cond 95 | fun:ngx_conf_flush_files 96 | fun:ngx_single_process_cycle 97 | fun:main 98 | } 99 | { 100 | 101 | Memcheck:Leak 102 | fun:malloc 103 | fun:ngx_alloc 104 | fun:ngx_event_process_init 105 | } 106 | { 107 | 108 | Memcheck:Param 109 | sendmsg(mmsg[0].msg_hdr) 110 | fun:sendmmsg 111 | fun:__libc_res_nsend 112 | } 113 | { 114 | 115 | Memcheck:Param 116 | sendmsg(msg.msg_iov[0]) 117 | fun:__sendmsg_nocancel 118 | fun:ngx_write_channel 119 | fun:ngx_pass_open_channel 120 | fun:ngx_start_cache_manager_processes 121 | } 122 | { 123 | 124 | Memcheck:Cond 125 | fun:ngx_init_cycle 126 | fun:ngx_master_process_cycle 127 | fun:main 128 | } 129 | { 130 | 131 | Memcheck:Cond 132 | fun:index 133 | fun:expand_dynamic_string_token 134 | fun:_dl_map_object 135 | fun:map_doit 136 | fun:_dl_catch_error 137 | fun:do_preload 138 | fun:dl_main 139 | fun:_dl_sysdep_start 140 | fun:_dl_start 141 | } 142 | { 143 | 144 | Memcheck:Param 145 | sendmsg(mmsg[0].msg_hdr) 146 | fun:sendmmsg 147 | fun:__libc_res_nsend 148 | fun:__libc_res_nquery 149 | fun:__libc_res_nquerydomain 150 | fun:__libc_res_nsearch 151 | } 152 | -------------------------------------------------------------------------------- /t/051-sub-jit.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | use Test::Nginx::Socket::Lua; 3 | 4 | #worker_connections(1014); 5 | #master_on(); 6 | #workers(2); 7 | #log_level('warn'); 8 | 9 | repeat_each(2); 10 | 11 | plan tests => repeat_each() * (blocks() * 2 + 6); 12 | 13 | #no_diff(); 14 | no_long_string(); 15 | run_tests(); 16 | 17 | __DATA__ 18 | 19 | === TEST 1: matched with j 20 | --- config 21 | location /re { 22 | content_by_lua ' 23 | local s, n = ngx.re.sub("hello, 1234 5678", "([0-9]+)", "world", "j") 24 | if n then 25 | ngx.say(s, ": ", n) 26 | else 27 | ngx.say(s) 28 | end 29 | '; 30 | } 31 | --- request 32 | GET /re 33 | --- response_body 34 | hello, world 5678: 1 35 | --- error_log 36 | pcre JIT compiling result: 1 37 | 38 | 39 | 40 | === TEST 2: not matched with j 41 | --- config 42 | location /re { 43 | content_by_lua ' 44 | local s, n = ngx.re.sub("hello, world", "[0-9]+", "hiya", "j") 45 | if n then 46 | ngx.say(s, ": ", n) 47 | else 48 | ngx.say(s) 49 | end 50 | '; 51 | } 52 | --- request 53 | GET /re 54 | --- response_body 55 | hello, world: 0 56 | --- error_log 57 | pcre JIT compiling result: 1 58 | 59 | 60 | 61 | === TEST 3: matched with jo 62 | --- config 63 | location /re { 64 | content_by_lua ' 65 | local s, n = ngx.re.sub("hello, 1234 5678", "([0-9]+)", "world", "jo") 66 | if n then 67 | ngx.say(s, ": ", n) 68 | else 69 | ngx.say(s) 70 | end 71 | '; 72 | } 73 | --- request 74 | GET /re 75 | --- response_body 76 | hello, world 5678: 1 77 | 78 | --- grep_error_log eval 79 | qr/pcre JIT compiling result: \d+/ 80 | 81 | --- grep_error_log_out eval 82 | ["pcre JIT compiling result: 1\n", ""] 83 | 84 | 85 | 86 | === TEST 4: not matched with jo 87 | --- config 88 | location /re { 89 | content_by_lua ' 90 | local s, n = ngx.re.sub("hello, world", "[0-9]+", "hiya", "jo") 91 | if n then 92 | ngx.say(s, ": ", n) 93 | else 94 | ngx.say(s) 95 | end 96 | '; 97 | } 98 | --- request 99 | GET /re 100 | --- response_body 101 | hello, world: 0 102 | 103 | --- grep_error_log eval 104 | qr/pcre JIT compiling result: \d+/ 105 | 106 | --- grep_error_log_out eval 107 | ["pcre JIT compiling result: 1\n", ""] 108 | 109 | 110 | 111 | === TEST 5: bad pattern 112 | --- config 113 | location /re { 114 | content_by_lua ' 115 | local s, n, err = ngx.re.sub("hello\\nworld", "(abc", "world", "j") 116 | if s then 117 | ngx.say(s, ": ", n) 118 | else 119 | ngx.say("error: ", err) 120 | end 121 | '; 122 | } 123 | --- request 124 | GET /re 125 | --- response_body 126 | error: pcre_compile() failed: missing ) in "(abc" 127 | --- no_error_log 128 | [error] 129 | 130 | 131 | 132 | === TEST 6: bad pattern + o 133 | --- config 134 | location /re { 135 | content_by_lua ' 136 | local s, n, err = ngx.re.sub( "hello\\nworld", "(abc", "world", "jo") 137 | if s then 138 | ngx.say(s, ": ", n) 139 | else 140 | ngx.say("error: ", err) 141 | end 142 | '; 143 | } 144 | --- request 145 | GET /re 146 | --- response_body 147 | error: pcre_compile() failed: missing ) in "(abc" 148 | --- no_error_log 149 | [error] 150 | 151 | -------------------------------------------------------------------------------- /t/053-gsub-jit.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | use Test::Nginx::Socket::Lua; 3 | 4 | #worker_connections(1014); 5 | #master_on(); 6 | #workers(2); 7 | #log_level('warn'); 8 | 9 | repeat_each(2); 10 | 11 | plan tests => repeat_each() * (blocks() * 2 + 6); 12 | 13 | #no_diff(); 14 | no_long_string(); 15 | run_tests(); 16 | 17 | __DATA__ 18 | 19 | === TEST 1: matched with j 20 | --- config 21 | location /re { 22 | content_by_lua ' 23 | local s, n = ngx.re.gsub("hello, 1234 5678", "([0-9]+)", "world", "j") 24 | if n then 25 | ngx.say(s, ": ", n) 26 | else 27 | ngx.say(s) 28 | end 29 | '; 30 | } 31 | --- request 32 | GET /re 33 | --- response_body 34 | hello, world world: 2 35 | --- error_log 36 | pcre JIT compiling result: 1 37 | 38 | 39 | 40 | === TEST 2: not matched with j 41 | --- config 42 | location /re { 43 | content_by_lua ' 44 | local s, n = ngx.re.gsub("hello, world", "[0-9]+", "hiya", "j") 45 | if n then 46 | ngx.say(s, ": ", n) 47 | else 48 | ngx.say(s) 49 | end 50 | '; 51 | } 52 | --- request 53 | GET /re 54 | --- response_body 55 | hello, world: 0 56 | --- error_log 57 | pcre JIT compiling result: 1 58 | 59 | 60 | 61 | === TEST 3: matched with jo 62 | --- config 63 | location /re { 64 | content_by_lua ' 65 | local s, n = ngx.re.gsub("hello, 1234 5678", "([0-9]+)", "world", "jo") 66 | if n then 67 | ngx.say(s, ": ", n) 68 | else 69 | ngx.say(s) 70 | end 71 | '; 72 | } 73 | --- request 74 | GET /re 75 | --- response_body 76 | hello, world world: 2 77 | 78 | --- grep_error_log eval 79 | qr/pcre JIT compiling result: \d+/ 80 | 81 | --- grep_error_log_out eval 82 | ["pcre JIT compiling result: 1\n", ""] 83 | 84 | 85 | 86 | === TEST 4: not matched with jo 87 | --- config 88 | location /re { 89 | content_by_lua ' 90 | local s, n = ngx.re.gsub("hello, world", "[0-9]+", "hiya", "jo") 91 | if n then 92 | ngx.say(s, ": ", n) 93 | else 94 | ngx.say(s) 95 | end 96 | '; 97 | } 98 | --- request 99 | GET /re 100 | --- response_body 101 | hello, world: 0 102 | 103 | --- grep_error_log eval 104 | qr/pcre JIT compiling result: \d+/ 105 | 106 | --- grep_error_log_out eval 107 | ["pcre JIT compiling result: 1\n", ""] 108 | 109 | 110 | 111 | === TEST 5: bad pattern 112 | --- config 113 | location /re { 114 | content_by_lua ' 115 | local s, n, err = ngx.re.gsub("hello\\nworld", "(abc", "world", "j") 116 | if s then 117 | ngx.say(s, ": ", n) 118 | else 119 | ngx.say("error: ", err) 120 | end 121 | '; 122 | } 123 | --- request 124 | GET /re 125 | --- response_body 126 | error: pcre_compile() failed: missing ) in "(abc" 127 | --- no_error_log 128 | [error] 129 | 130 | 131 | 132 | === TEST 6: bad pattern + o 133 | --- config 134 | location /re { 135 | content_by_lua ' 136 | local s, n, err = ngx.re.gsub("hello\\nworld", "(abc", "world", "jo") 137 | if s then 138 | ngx.say(s, ": ", n) 139 | else 140 | ngx.say("error: ", err) 141 | end 142 | '; 143 | } 144 | --- request 145 | GET /re 146 | --- response_body 147 | error: pcre_compile() failed: missing ) in "(abc" 148 | --- no_error_log 149 | [error] 150 | 151 | -------------------------------------------------------------------------------- /src/ngx_http_lua_probe.h: -------------------------------------------------------------------------------- 1 | /* 2 | * automatically generated from the file dtrace/ngx_lua_provider.d by the 3 | * gen-dtrace-probe-header tool in the nginx-devel-utils project: 4 | * https://github.com/agentzh/nginx-devel-utils 5 | */ 6 | 7 | #ifndef _NGX_HTTP_LUA_PROBE_H_INCLUDED_ 8 | #define _NGX_HTTP_LUA_PROBE_H_INCLUDED_ 9 | 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | 16 | #if defined(NGX_DTRACE) && NGX_DTRACE 17 | 18 | #include 19 | 20 | #define ngx_http_lua_probe_info(s) \ 21 | NGINX_LUA_HTTP_LUA_INFO(s) 22 | 23 | #define ngx_http_lua_probe_register_preload_package(L, pkg) \ 24 | NGINX_LUA_HTTP_LUA_REGISTER_PRELOAD_PACKAGE(L, pkg) 25 | 26 | #define ngx_http_lua_probe_req_socket_consume_preread(r, data, len) \ 27 | NGINX_LUA_HTTP_LUA_REQ_SOCKET_CONSUME_PREREAD(r, data, len) 28 | 29 | #define ngx_http_lua_probe_user_coroutine_create(r, parent, child) \ 30 | NGINX_LUA_HTTP_LUA_USER_COROUTINE_CREATE(r, parent, child) 31 | 32 | #define ngx_http_lua_probe_user_coroutine_resume(r, parent, child) \ 33 | NGINX_LUA_HTTP_LUA_USER_COROUTINE_RESUME(r, parent, child) 34 | 35 | #define ngx_http_lua_probe_user_coroutine_yield(r, parent, child) \ 36 | NGINX_LUA_HTTP_LUA_USER_COROUTINE_YIELD(r, parent, child) 37 | 38 | #define ngx_http_lua_probe_thread_yield(r, L) \ 39 | NGINX_LUA_HTTP_LUA_THREAD_YIELD(r, L) 40 | 41 | #define ngx_http_lua_probe_socket_tcp_send_start(r, u, data, len) \ 42 | NGINX_LUA_HTTP_LUA_SOCKET_TCP_SEND_START(r, u, data, len) 43 | 44 | #define ngx_http_lua_probe_socket_tcp_receive_done(r, u, data, len) \ 45 | NGINX_LUA_HTTP_LUA_SOCKET_TCP_RECEIVE_DONE(r, u, data, len) 46 | 47 | #define ngx_http_lua_probe_socket_tcp_setkeepalive_buf_unread(r, u, data, len)\ 48 | NGINX_LUA_HTTP_LUA_SOCKET_TCP_SETKEEPALIVE_BUF_UNREAD(r, u, data, len) 49 | 50 | #define ngx_http_lua_probe_user_thread_spawn(r, creator, newthread) \ 51 | NGINX_LUA_HTTP_LUA_USER_THREAD_SPAWN(r, creator, newthread) 52 | 53 | #define ngx_http_lua_probe_thread_delete(r, thread, ctx) \ 54 | NGINX_LUA_HTTP_LUA_THREAD_DELETE(r, thread, ctx) 55 | 56 | #define ngx_http_lua_probe_run_posted_thread(r, thread, status) \ 57 | NGINX_LUA_HTTP_LUA_RUN_POSTED_THREAD(r, thread, status) 58 | 59 | #define ngx_http_lua_probe_coroutine_done(r, co, success) \ 60 | NGINX_LUA_HTTP_LUA_COROUTINE_DONE(r, co, success) 61 | 62 | #define ngx_http_lua_probe_user_thread_wait(parent, child) \ 63 | NGINX_LUA_HTTP_LUA_USER_THREAD_WAIT(parent, child) 64 | 65 | #else /* !(NGX_DTRACE) */ 66 | 67 | #define ngx_http_lua_probe_info(s) 68 | #define ngx_http_lua_probe_register_preload_package(L, pkg) 69 | #define ngx_http_lua_probe_req_socket_consume_preread(r, data, len) 70 | #define ngx_http_lua_probe_user_coroutine_create(r, parent, child) 71 | #define ngx_http_lua_probe_user_coroutine_resume(r, parent, child) 72 | #define ngx_http_lua_probe_user_coroutine_yield(r, parent, child) 73 | #define ngx_http_lua_probe_thread_yield(r, L) 74 | #define ngx_http_lua_probe_socket_tcp_send_start(r, u, data, len) 75 | #define ngx_http_lua_probe_socket_tcp_receive_done(r, u, data, len) 76 | #define ngx_http_lua_probe_socket_tcp_setkeepalive_buf_unread(r, u, data, len) 77 | #define ngx_http_lua_probe_user_thread_spawn(r, creator, newthread) 78 | #define ngx_http_lua_probe_thread_delete(r, thread, ctx) 79 | #define ngx_http_lua_probe_run_posted_thread(r, thread, status) 80 | #define ngx_http_lua_probe_coroutine_done(r, co, success) 81 | #define ngx_http_lua_probe_user_thread_wait(parent, child) 82 | 83 | #endif 84 | 85 | #endif /* _NGX_HTTP_LUA_PROBE_H_INCLUDED_ */ 86 | -------------------------------------------------------------------------------- /t/089-phase.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket::Lua; 4 | 5 | #worker_connections(1014); 6 | #master_process_enabled(1); 7 | log_level('warn'); 8 | 9 | repeat_each(2); 10 | 11 | plan tests => repeat_each() * (blocks() * 2 + 1); 12 | 13 | #no_diff(); 14 | #no_long_string(); 15 | run_tests(); 16 | 17 | __DATA__ 18 | 19 | === TEST 1: get_phase in init_by_lua 20 | --- http_config 21 | init_by_lua 'phase = ngx.get_phase()'; 22 | --- config 23 | location /lua { 24 | content_by_lua ' 25 | ngx.say(phase) 26 | '; 27 | } 28 | --- request 29 | GET /lua 30 | --- response_body 31 | init 32 | 33 | 34 | 35 | === TEST 2: get_phase in set_by_lua 36 | --- config 37 | set_by_lua $phase 'return ngx.get_phase()'; 38 | location /lua { 39 | content_by_lua ' 40 | ngx.say(ngx.var.phase) 41 | '; 42 | } 43 | --- request 44 | GET /lua 45 | --- response_body 46 | set 47 | 48 | 49 | 50 | === TEST 3: get_phase in rewrite_by_lua 51 | --- config 52 | location /lua { 53 | rewrite_by_lua ' 54 | ngx.say(ngx.get_phase()) 55 | ngx.exit(200) 56 | '; 57 | } 58 | --- request 59 | GET /lua 60 | --- response_body 61 | rewrite 62 | 63 | 64 | 65 | === TEST 4: get_phase in access_by_lua 66 | --- config 67 | location /lua { 68 | access_by_lua ' 69 | ngx.say(ngx.get_phase()) 70 | ngx.exit(200) 71 | '; 72 | } 73 | --- request 74 | GET /lua 75 | --- response_body 76 | access 77 | 78 | 79 | 80 | === TEST 5: get_phase in content_by_lua 81 | --- config 82 | location /lua { 83 | content_by_lua ' 84 | ngx.say(ngx.get_phase()) 85 | '; 86 | } 87 | --- request 88 | GET /lua 89 | --- response_body 90 | content 91 | 92 | 93 | 94 | === TEST 6: get_phase in header_filter_by_lua 95 | --- config 96 | location /lua { 97 | echo "OK"; 98 | header_filter_by_lua ' 99 | ngx.header.Phase = ngx.get_phase() 100 | '; 101 | } 102 | --- request 103 | GET /lua 104 | --- response_header 105 | Phase: header_filter 106 | 107 | 108 | 109 | === TEST 7: get_phase in body_filter_by_lua 110 | --- config 111 | location /lua { 112 | content_by_lua ' 113 | ngx.exit(200) 114 | '; 115 | body_filter_by_lua ' 116 | ngx.arg[1] = ngx.get_phase() 117 | '; 118 | } 119 | --- request 120 | GET /lua 121 | --- response_body chop 122 | body_filter 123 | 124 | 125 | 126 | === TEST 8: get_phase in log_by_lua 127 | --- config 128 | location /lua { 129 | echo "OK"; 130 | log_by_lua ' 131 | ngx.log(ngx.ERR, ngx.get_phase()) 132 | '; 133 | } 134 | --- request 135 | GET /lua 136 | --- error_log 137 | log 138 | 139 | 140 | 141 | === TEST 9: get_phase in ngx.timer callback 142 | --- config 143 | location /lua { 144 | echo "OK"; 145 | log_by_lua ' 146 | local function f() 147 | ngx.log(ngx.WARN, "current phase: ", ngx.get_phase()) 148 | end 149 | local ok, err = ngx.timer.at(0, f) 150 | if not ok then 151 | ngx.log(ngx.ERR, "failed to add timer: ", err) 152 | end 153 | '; 154 | } 155 | --- request 156 | GET /lua 157 | --- no_error_log 158 | [error] 159 | --- error_log 160 | current phase: timer 161 | 162 | 163 | 164 | === TEST 10: get_phase in init_worker_by_lua 165 | --- http_config 166 | init_worker_by_lua 'phase = ngx.get_phase()'; 167 | --- config 168 | location /lua { 169 | content_by_lua ' 170 | ngx.say(phase) 171 | '; 172 | } 173 | --- request 174 | GET /lua 175 | --- response_body 176 | init_worker 177 | --- no_error_log 178 | [error] 179 | 180 | -------------------------------------------------------------------------------- /t/006-escape.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket::Lua; 4 | 5 | repeat_each(2); 6 | #repeat_each(1); 7 | 8 | plan tests => repeat_each() * (blocks() * 2 + 1); 9 | 10 | no_long_string(); 11 | 12 | run_tests(); 13 | 14 | __DATA__ 15 | 16 | === TEST 1: escape uri in set_by_lua 17 | --- config 18 | location /escape { 19 | set_by_lua $res "return ngx.escape_uri('a 你')"; 20 | echo $res; 21 | } 22 | --- request 23 | GET /escape 24 | --- response_body 25 | a%20%E4%BD%A0 26 | 27 | 28 | 29 | === TEST 2: unescape uri in set_by_lua 30 | --- config 31 | location /unescape { 32 | set_by_lua $res "return ngx.unescape_uri('a%20%e4%bd%a0')"; 33 | echo $res; 34 | } 35 | --- request 36 | GET /unescape 37 | --- response_body 38 | a 你 39 | 40 | 41 | 42 | === TEST 3: escape uri in content_by_lua 43 | --- config 44 | location /escape { 45 | content_by_lua "ngx.say(ngx.escape_uri('a 你'))"; 46 | } 47 | --- request 48 | GET /escape 49 | --- response_body 50 | a%20%E4%BD%A0 51 | 52 | 53 | 54 | === TEST 4: unescape uri in content_by_lua 55 | --- config 56 | location /unescape { 57 | content_by_lua "ngx.say(ngx.unescape_uri('a%20%e4%bd%a0'))"; 58 | } 59 | --- request 60 | GET /unescape 61 | --- response_body 62 | a 你 63 | 64 | 65 | 66 | === TEST 5: escape uri in set_by_lua 67 | --- config 68 | location /escape { 69 | set_by_lua $res "return ngx.escape_uri('a+b')"; 70 | echo $res; 71 | } 72 | --- request 73 | GET /escape 74 | --- response_body 75 | a%2Bb 76 | 77 | 78 | 79 | === TEST 6: escape uri in set_by_lua 80 | --- config 81 | location /escape { 82 | set_by_lua $res "return ngx.escape_uri('\"a/b={}:<>;&[]\\\\^')"; 83 | echo $res; 84 | } 85 | --- request 86 | GET /escape 87 | --- response_body 88 | %22a%2Fb%3D%7B%7D%3A%3C%3E%3B%26%5B%5D%5C%5E 89 | 90 | 91 | 92 | === TEST 7: escape uri in set_by_lua 93 | --- config 94 | location /escape { 95 | echo hello; 96 | header_filter_by_lua ' 97 | ngx.header.baz = ngx.escape_uri(" ") 98 | '; 99 | } 100 | --- request 101 | GET /escape 102 | --- response_headers 103 | baz: %20 104 | --- response_body 105 | hello 106 | 107 | 108 | 109 | === TEST 8: escape a string that cannot be escaped 110 | --- config 111 | location /escape { 112 | set_by_lua $res "return ngx.escape_uri('abc')"; 113 | echo $res; 114 | } 115 | --- request 116 | GET /escape 117 | --- response_body 118 | abc 119 | 120 | 121 | 122 | === TEST 9: escape an empty string that cannot be escaped 123 | --- config 124 | location /escape { 125 | set_by_lua $res "return ngx.escape_uri('')"; 126 | echo $res; 127 | } 128 | --- request 129 | GET /escape 130 | --- response_body eval: "\n" 131 | 132 | 133 | 134 | === TEST 10: escape nil 135 | --- config 136 | location /escape { 137 | set_by_lua $res "return ngx.escape_uri(nil)"; 138 | echo "[$res]"; 139 | } 140 | --- request 141 | GET /escape 142 | --- response_body 143 | [] 144 | 145 | 146 | 147 | === TEST 11: escape numbers 148 | --- config 149 | location /escape { 150 | set_by_lua $res "return ngx.escape_uri(32)"; 151 | echo "[$res]"; 152 | } 153 | --- request 154 | GET /escape 155 | --- response_body 156 | [32] 157 | 158 | 159 | 160 | === TEST 12: unescape nil 161 | --- config 162 | location = /t { 163 | set_by_lua $res "return ngx.unescape_uri(nil)"; 164 | echo "[$res]"; 165 | } 166 | --- request 167 | GET /t 168 | --- response_body 169 | [] 170 | 171 | 172 | 173 | === TEST 13: unescape numbers 174 | --- config 175 | location = /t { 176 | set_by_lua $res "return ngx.unescape_uri(32)"; 177 | echo "[$res]"; 178 | } 179 | --- request 180 | GET /t 181 | --- response_body 182 | [32] 183 | 184 | -------------------------------------------------------------------------------- /t/059-unix-socket.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket::Lua; 4 | 5 | repeat_each(2); 6 | 7 | plan tests => repeat_each() * (blocks() * 2 + 1); 8 | 9 | $ENV{TEST_NGINX_HTML_DIR} ||= html_dir(); 10 | 11 | no_long_string(); 12 | #no_shuffle(); 13 | 14 | run_tests(); 15 | 16 | __DATA__ 17 | 18 | === TEST 1: connection refused (unix domain socket) 19 | --- config 20 | location /test { 21 | content_by_lua ' 22 | local sock = ngx.socket.tcp() 23 | local ok, err = sock:connect("unix:/tmp/nosuchfile.sock") 24 | ngx.say("connect: ", ok, " ", err) 25 | 26 | local bytes 27 | bytes, err = sock:send("hello") 28 | ngx.say("send: ", bytes, " ", err) 29 | 30 | local line 31 | line, err = sock:receive() 32 | ngx.say("receive: ", line, " ", err) 33 | 34 | ok, err = sock:close() 35 | ngx.say("close: ", ok, " ", err) 36 | '; 37 | } 38 | --- request 39 | GET /test 40 | --- response_body 41 | connect: nil no such file or directory 42 | send: nil closed 43 | receive: nil closed 44 | close: nil closed 45 | --- error_log eval 46 | qr{\[crit\] .*? connect\(\) to unix:/tmp/nosuchfile\.sock failed} 47 | 48 | 49 | 50 | === TEST 2: invalid host argument 51 | --- config 52 | location /test { 53 | content_by_lua ' 54 | local sock = ngx.socket.tcp() 55 | local ok, err = sock:connect("/tmp/test-nginx.sock") 56 | if not ok then 57 | ngx.say("failed to connect: ", err) 58 | return 59 | end 60 | 61 | ngx.say("connected: ", ok) 62 | '; 63 | } 64 | --- request 65 | GET /test 66 | --- response_body 67 | failed to connect: failed to parse host name "/tmp/test-nginx.sock": invalid host 68 | 69 | 70 | 71 | === TEST 3: sanity 72 | --- http_config 73 | server { 74 | listen unix:$TEST_NGINX_HTML_DIR/nginx.sock; 75 | default_type 'text/plain'; 76 | 77 | server_tokens off; 78 | location /foo { 79 | content_by_lua 'ngx.say("foo")'; 80 | more_clear_headers Date; 81 | } 82 | } 83 | --- config 84 | location /test { 85 | content_by_lua ' 86 | local sock = ngx.socket.tcp() 87 | local ok, err = sock:connect("unix:$TEST_NGINX_HTML_DIR/nginx.sock") 88 | if not ok then 89 | ngx.say("failed to connect: ", err) 90 | return 91 | end 92 | 93 | ngx.say("connected: ", ok) 94 | 95 | local req = "GET /foo HTTP/1.0\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n" 96 | -- req = "OK" 97 | 98 | local bytes, err = sock:send(req) 99 | if not bytes then 100 | ngx.say("failed to send request: ", err) 101 | return 102 | end 103 | 104 | ngx.say("request sent: ", bytes) 105 | 106 | while true do 107 | print("calling receive") 108 | local line, err = sock:receive() 109 | if line then 110 | ngx.say("received: ", line) 111 | 112 | else 113 | ngx.say("failed to receive a line: ", err) 114 | break 115 | end 116 | end 117 | 118 | ok, err = sock:close() 119 | ngx.say("close: ", ok, " ", err) 120 | '; 121 | } 122 | --- request 123 | GET /test 124 | --- response_body 125 | connected: 1 126 | request sent: 57 127 | received: HTTP/1.1 200 OK 128 | received: Server: nginx 129 | received: Content-Type: text/plain 130 | received: Content-Length: 4 131 | received: Connection: close 132 | received: 133 | received: foo 134 | failed to receive a line: closed 135 | close: 1 nil 136 | 137 | -------------------------------------------------------------------------------- /t/018-ndk.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket::Lua; 4 | 5 | repeat_each(2); 6 | 7 | plan tests => repeat_each() * (blocks() * 2 + 4); 8 | 9 | #no_diff(); 10 | #no_long_string(); 11 | 12 | run_tests(); 13 | 14 | __DATA__ 15 | 16 | === TEST 1: sanity 17 | --- config 18 | location /read { 19 | content_by_lua ' 20 | local s = ndk.set_var.set_escape_uri(" :") 21 | local r = ndk.set_var.set_unescape_uri("a%20b") 22 | ngx.say(s) 23 | ngx.say(r) 24 | '; 25 | } 26 | --- request 27 | GET /read 28 | --- response_body 29 | %20%3A 30 | a b 31 | 32 | 33 | 34 | === TEST 2: directive not found 35 | --- config 36 | location /read { 37 | content_by_lua ' 38 | local s = ndk.set_var.set_escape_uri_blah_blah(" :") 39 | ngx.say(s) 40 | '; 41 | } 42 | --- request 43 | GET /read 44 | --- response_body_like: 500 Internal Server Error 45 | --- error_code: 500 46 | 47 | 48 | 49 | === TEST 3: directive not found 50 | --- config 51 | location /read { 52 | content_by_lua ' 53 | local s = ndk.set_var.content_by_lua(" :") 54 | ngx.say(s) 55 | '; 56 | } 57 | --- request 58 | GET /read 59 | --- response_body_like: 500 Internal Server Error 60 | --- error_code: 500 61 | 62 | 63 | 64 | === TEST 4: directive not found 65 | --- config 66 | location /read { 67 | header_filter_by_lua ' 68 | ngx.header.Foo = ndk.set_var.set_escape_uri(" %") 69 | '; 70 | echo hi; 71 | } 72 | --- request 73 | GET /read 74 | --- response_headers 75 | Foo: %20%25 76 | --- response_body 77 | hi 78 | 79 | 80 | 81 | === TEST 5: bug: ndk.set_var not initialize ngx_http_variable_value_t variable properly 82 | --- config 83 | location /luaset { 84 | content_by_lua " 85 | 86 | local version = '2011.10.13+0000' 87 | local e_version = ndk.set_var.set_encode_base32(version) 88 | local s_version= ndk.set_var.set_quote_sql_str(version) 89 | ngx.say(e_version) 90 | ngx.say(s_version) 91 | "; 92 | } 93 | --- request 94 | GET /luaset 95 | --- response_body 96 | 68o32c9e64o2sc9j5co30c1g 97 | '2011.10.13+0000' 98 | 99 | 100 | 101 | === TEST 6: set_by_lua 102 | --- config 103 | location /read { 104 | set_by_lua $r ' 105 | return ndk.set_var.set_unescape_uri("a%20b") 106 | '; 107 | echo $r; 108 | } 109 | --- request 110 | GET /read 111 | --- response_body 112 | a b 113 | 114 | 115 | 116 | === TEST 7: header_filter_by_lua 117 | --- config 118 | location /read { 119 | set $foo ''; 120 | content_by_lua ' 121 | ngx.send_headers() 122 | ngx.say(ngx.var.foo) 123 | '; 124 | header_filter_by_lua ' 125 | ngx.var.foo = ndk.set_var.set_unescape_uri("a%20b") 126 | '; 127 | } 128 | --- request 129 | GET /read 130 | --- response_body 131 | a b 132 | 133 | 134 | 135 | === TEST 8: log_by_lua 136 | --- config 137 | location /read { 138 | echo ok; 139 | log_by_lua ' 140 | local foo = ndk.set_var.set_unescape_uri("a%20b") 141 | ngx.log(ngx.WARN, "foo = ", foo) 142 | '; 143 | } 144 | --- request 145 | GET /read 146 | --- response_body 147 | ok 148 | --- wait: 0.1 149 | --- error_log 150 | foo = a b 151 | 152 | 153 | 154 | === TEST 9: ngx.timer.* 155 | --- config 156 | location /read { 157 | echo ok; 158 | log_by_lua ' 159 | ngx.timer.at(0, function () 160 | local foo = ndk.set_var.set_unescape_uri("a%20b") 161 | ngx.log(ngx.WARN, "foo = ", foo) 162 | end) 163 | '; 164 | } 165 | --- request 166 | GET /read 167 | --- response_body 168 | ok 169 | --- wait: 0.1 170 | --- error_log 171 | foo = a b 172 | --- no_error_log 173 | [error] 174 | 175 | -------------------------------------------------------------------------------- /t/022-redirect.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket::Lua; 4 | 5 | #worker_connections(1014); 6 | #master_process_enabled(1); 7 | #log_level('warn'); 8 | 9 | repeat_each(2); 10 | #repeat_each(1); 11 | 12 | plan tests => repeat_each() * (blocks() * 3 + 1); 13 | 14 | #no_diff(); 15 | #no_long_string(); 16 | 17 | run_tests(); 18 | 19 | __DATA__ 20 | 21 | === TEST 1: default 302 22 | --- config 23 | location /read { 24 | content_by_lua ' 25 | ngx.redirect("http://agentzh.org/foo"); 26 | ngx.say("hi") 27 | '; 28 | } 29 | --- request 30 | GET /read 31 | --- response_headers 32 | Location: http://agentzh.org/foo 33 | --- response_body_like: 302 Found 34 | --- error_code: 302 35 | 36 | 37 | 38 | === TEST 2: explicit 302 39 | --- config 40 | location /read { 41 | content_by_lua ' 42 | ngx.redirect("http://agentzh.org/foo", ngx.HTTP_MOVED_TEMPORARILY); 43 | ngx.say("hi") 44 | '; 45 | } 46 | --- request 47 | GET /read 48 | --- response_headers 49 | Location: http://agentzh.org/foo 50 | --- response_body_like: 302 Found 51 | --- error_code: 302 52 | 53 | 54 | 55 | === TEST 3: explicit 301 56 | --- config 57 | location /read { 58 | content_by_lua ' 59 | ngx.redirect("http://agentzh.org/foo", ngx.HTTP_MOVED_PERMANENTLY); 60 | ngx.say("hi") 61 | '; 62 | } 63 | --- request 64 | GET /read 65 | --- response_headers 66 | Location: http://agentzh.org/foo 67 | --- response_body_like: 301 Moved Permanently 68 | --- error_code: 301 69 | 70 | 71 | 72 | === TEST 4: bad rc 73 | --- config 74 | location /read { 75 | content_by_lua ' 76 | ngx.redirect("http://agentzh.org/foo", 404); 77 | ngx.say("hi") 78 | '; 79 | } 80 | --- request 81 | GET /read 82 | --- response_headers 83 | !Location 84 | --- response_body_like: 500 Internal Server Error 85 | --- error_code: 500 86 | 87 | 88 | 89 | === TEST 5: no args 90 | --- config 91 | location /read { 92 | content_by_lua ' 93 | ngx.redirect() 94 | ngx.say("hi") 95 | '; 96 | } 97 | --- request 98 | GET /read 99 | --- response_headers 100 | !Location 101 | --- response_body_like: 500 Internal Server Error 102 | --- error_code: 500 103 | 104 | 105 | 106 | === TEST 6: relative uri 107 | --- config 108 | location /echo { 109 | echo hello, world; 110 | } 111 | location /proxy { 112 | proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/echo; 113 | } 114 | location /read { 115 | content_by_lua ' 116 | ngx.location.capture("/proxy") 117 | ngx.redirect("/echo") 118 | ngx.say("hi") 119 | '; 120 | } 121 | --- request 122 | GET /read 123 | --- raw_response_headers_like: Location: /echo\r\n 124 | --- response_body_like: 302 Found 125 | --- error_code: 302 126 | 127 | 128 | 129 | === TEST 7: default 302 (with uri args) 130 | --- config 131 | location /read { 132 | content_by_lua ' 133 | ngx.redirect("http://agentzh.org/foo?bar=3"); 134 | ngx.say("hi") 135 | '; 136 | } 137 | --- request 138 | GET /read 139 | --- response_headers 140 | Location: http://agentzh.org/foo?bar=3 141 | --- response_body_like: 302 Found 142 | --- error_code: 302 143 | 144 | 145 | 146 | === TEST 8: location.capture + ngx.redirect 147 | --- config 148 | location /echo { 149 | echo hello, world; 150 | } 151 | location /proxy { 152 | proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT/echo; 153 | } 154 | location /read { 155 | content_by_lua ' 156 | ngx.location.capture("/proxy") 157 | ngx.location.capture("/proxy") 158 | ngx.redirect("/echo") 159 | ngx.exit(403) 160 | '; 161 | } 162 | --- pipelined_requests eval 163 | ["GET /read/1", "GET /read/2"] 164 | --- error_code eval 165 | [302, 302] 166 | --- response_body eval 167 | [qr/302 Found/, qr/302 Found/] 168 | 169 | -------------------------------------------------------------------------------- /t/026-mysql.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | 3 | use Test::Nginx::Socket::Lua; 4 | 5 | repeat_each(2); 6 | 7 | plan tests => blocks() * repeat_each() * 3; 8 | 9 | #$ENV{LUA_PATH} = $ENV{HOME} . '/work/JSON4Lua-0.9.30/json/?.lua'; 10 | $ENV{TEST_NGINX_MYSQL_PORT} ||= 3306; 11 | 12 | no_long_string(); 13 | 14 | run_tests(); 15 | 16 | __DATA__ 17 | 18 | === TEST 1: when mysql query timed out, kill that query by Lua 19 | --- http_config 20 | upstream backend { 21 | drizzle_server 127.0.0.1:$TEST_NGINX_MYSQL_PORT protocol=mysql 22 | dbname=ngx_test user=ngx_test password=ngx_test; 23 | drizzle_keepalive max=300 mode=single overflow=ignore; 24 | } 25 | --- config 26 | location = /mysql { 27 | #internal; 28 | drizzle_send_query_timeout 100ms; 29 | #drizzle_send_query_timeout 1s; 30 | drizzle_query $echo_request_body; 31 | drizzle_pass backend; 32 | 33 | #error_page 504 /ret/504; 34 | rds_json on; 35 | more_set_headers -s 504 "X-Mysql-Tid: $drizzle_thread_id"; 36 | } 37 | 38 | location /lua { 39 | content_by_lua ' 40 | local sql = "select sleep(5)" 41 | local res = ngx.location.capture("/mysql", 42 | { method = ngx.HTTP_POST, body = sql }) 43 | 44 | ngx.say("status = " .. res.status) 45 | 46 | local tid = res.header["X-Mysql-Tid"] 47 | if tid == nil then 48 | ngx.say("thread id = nil") 49 | return 50 | end 51 | 52 | tid = tonumber(tid) 53 | ngx.say("thread id = " .. tid) 54 | 55 | res = ngx.location.capture("/mysql", 56 | { method = ngx.HTTP_POST, 57 | body = "kill query " .. tid }) 58 | 59 | ngx.say("kill status = " .. res.status) 60 | ngx.say("kill body = " .. res.body) 61 | '; 62 | } 63 | --- request 64 | GET /lua 65 | --- response_body_like 66 | ^status = 504 67 | thread id = \d+ 68 | kill status = 200 69 | kill body = {"errcode":0}$ 70 | --- error_log eval 71 | qr{upstream timed out \(\d+: Connection timed out\) while sending query to drizzle upstream} 72 | 73 | 74 | 75 | === TEST 2: no error pages 76 | --- http_config 77 | upstream backend { 78 | drizzle_server 127.0.0.1:$TEST_NGINX_MYSQL_PORT protocol=mysql 79 | dbname=ngx_test user=ngx_test password=ngx_test; 80 | drizzle_keepalive max=300 mode=single overflow=ignore; 81 | } 82 | --- config 83 | location @err { echo Hi; } 84 | error_page 504 = @err; 85 | location = /mysql { 86 | #internal; 87 | drizzle_send_query_timeout 100ms; 88 | #drizzle_send_query_timeout 1s; 89 | drizzle_query $echo_request_body; 90 | drizzle_pass backend; 91 | 92 | no_error_pages; 93 | 94 | rds_json on; 95 | more_set_headers -s 504 "X-Mysql-Tid: $drizzle_thread_id"; 96 | } 97 | 98 | location /lua { 99 | content_by_lua ' 100 | local sql = "select sleep(3)" 101 | local res = ngx.location.capture("/mysql", 102 | { method = ngx.HTTP_POST, body = sql }) 103 | 104 | ngx.say("status = " .. res.status) 105 | 106 | local tid = res.header["X-Mysql-Tid"] 107 | if tid == nil then 108 | ngx.say("thread id = nil") 109 | return 110 | end 111 | 112 | tid = tonumber(tid) 113 | ngx.say("thread id = " .. tid) 114 | 115 | res = ngx.location.capture("/mysql", 116 | { method = ngx.HTTP_POST, 117 | body = "kill query " .. tid }) 118 | 119 | ngx.say("kill status = " .. res.status) 120 | ngx.say("kill body = " .. res.body) 121 | '; 122 | } 123 | --- request 124 | GET /lua 125 | --- response_body_like 126 | ^status = 504 127 | thread id = \d+ 128 | kill status = 200 129 | kill body = {"errcode":0}$ 130 | --- SKIP 131 | 132 | -------------------------------------------------------------------------------- /t/data/fake-module/ngx_http_fake_module.c: -------------------------------------------------------------------------------- 1 | /* Copyright (C) ZHANG Heng (chiyouhen) 2 | * 3 | * This fake module was used to reproduce a bug in ngx_lua's 4 | * init_worker_by_lua implementation. 5 | */ 6 | 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | typedef struct { 15 | ngx_int_t a; 16 | } ngx_http_fake_srv_conf_t; 17 | 18 | 19 | typedef struct { 20 | ngx_int_t a; 21 | } ngx_http_fake_loc_conf_t; 22 | 23 | 24 | static void *ngx_http_fake_create_srv_conf(ngx_conf_t *cf); 25 | static char *ngx_http_fake_merge_srv_conf(ngx_conf_t *cf, void *prev, void *conf); 26 | static void *ngx_http_fake_create_loc_conf(ngx_conf_t *cf); 27 | static char *ngx_http_fake_merge_loc_conf(ngx_conf_t *cf, void *prev, void *conf); 28 | 29 | 30 | /* flow identify module configure struct */ 31 | static ngx_http_module_t ngx_http_fake_module_ctx = { 32 | NULL, /* preconfiguration */ 33 | NULL, /* postconfiguration */ 34 | 35 | NULL, /* create main configuration */ 36 | NULL, /* init main configuration */ 37 | 38 | ngx_http_fake_create_srv_conf, /* create server configuration */ 39 | ngx_http_fake_merge_srv_conf, /* merge server configuration */ 40 | 41 | ngx_http_fake_create_loc_conf, /* create location configuration */ 42 | ngx_http_fake_merge_loc_conf /* merge location configuration */ 43 | }; 44 | 45 | /* flow identify module struct */ 46 | ngx_module_t ngx_http_fake_module = { 47 | NGX_MODULE_V1, 48 | &ngx_http_fake_module_ctx, /* module context */ 49 | NULL, /* module directives */ 50 | NGX_HTTP_MODULE, /* module type */ 51 | NULL, /* init master */ 52 | NULL, /* init module */ 53 | NULL, /* init process */ 54 | NULL, /* init thread */ 55 | NULL, /* exit thread */ 56 | NULL, /* exit process */ 57 | NULL, /* exit master */ 58 | NGX_MODULE_V1_PADDING 59 | }; 60 | 61 | 62 | /* create server configure */ 63 | static void *ngx_http_fake_create_srv_conf(ngx_conf_t *cf) 64 | { 65 | ngx_http_fake_srv_conf_t *fscf; 66 | 67 | fscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fake_srv_conf_t)); 68 | if (fscf == NULL) { 69 | return NULL; 70 | } 71 | 72 | return fscf; 73 | } 74 | 75 | 76 | /* merge server configure */ 77 | static char *ngx_http_fake_merge_srv_conf(ngx_conf_t *cf, void *prev, void *conf) 78 | { 79 | ngx_http_fake_srv_conf_t *fscf; 80 | 81 | fscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_fake_module); 82 | if (fscf == NULL) { 83 | ngx_conf_log_error(NGX_LOG_ALERT, cf, 0, 84 | "get module srv conf failed in merge srv conf"); 85 | return NGX_CONF_ERROR; 86 | } 87 | 88 | ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, "merge srv conf ok"); 89 | return NGX_CONF_OK; 90 | } 91 | 92 | 93 | /* create location configure */ 94 | static void *ngx_http_fake_create_loc_conf(ngx_conf_t *cf) 95 | { 96 | ngx_http_fake_loc_conf_t *flcf; 97 | 98 | flcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fake_loc_conf_t)); 99 | if (flcf == NULL) { 100 | return NULL; 101 | } 102 | 103 | return flcf; 104 | } 105 | 106 | 107 | /* merge location configure */ 108 | static char *ngx_http_fake_merge_loc_conf(ngx_conf_t *cf, void *prev, void *conf) 109 | { 110 | ngx_http_fake_loc_conf_t *flcf; 111 | 112 | flcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_fake_module); 113 | if (flcf == NULL) { 114 | ngx_conf_log_error(NGX_LOG_ALERT, cf, 0, 115 | "get module loc conf failed in merge loc conf"); 116 | return NGX_CONF_ERROR; 117 | } 118 | 119 | ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, "merge loc conf ok"); 120 | return NGX_CONF_OK; 121 | } 122 | -------------------------------------------------------------------------------- /t/048-match-dfa.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | use Test::Nginx::Socket::Lua; 3 | 4 | #worker_connections(1014); 5 | #master_on(); 6 | #workers(2); 7 | #log_level('warn'); 8 | 9 | repeat_each(2); 10 | 11 | plan tests => repeat_each() * (blocks() * 2 + 4); 12 | 13 | #no_diff(); 14 | no_long_string(); 15 | run_tests(); 16 | 17 | __DATA__ 18 | 19 | === TEST 1: matched with d 20 | --- config 21 | location /re { 22 | content_by_lua ' 23 | m = ngx.re.match("hello", "(he|hell)", "d") 24 | if m then 25 | ngx.say(m[0]) 26 | else 27 | ngx.say("not matched!") 28 | end 29 | '; 30 | } 31 | --- request 32 | GET /re 33 | --- response_body 34 | hell 35 | 36 | 37 | 38 | === TEST 2: matched with d + j 39 | --- config 40 | location /re { 41 | content_by_lua ' 42 | m = ngx.re.match("hello", "(he|hell)", "jd") 43 | if m then 44 | ngx.say(m[0]) 45 | else 46 | ngx.say("not matched!") 47 | end 48 | '; 49 | } 50 | --- request 51 | GET /re 52 | --- response_body 53 | hell 54 | 55 | 56 | 57 | === TEST 3: not matched with j 58 | --- config 59 | location /re { 60 | content_by_lua ' 61 | m = ngx.re.match("world", "(he|hell)", "d") 62 | if m then 63 | ngx.say(m[0]) 64 | else 65 | ngx.say("not matched!") 66 | end 67 | '; 68 | } 69 | --- request 70 | GET /re 71 | --- response_body 72 | not matched! 73 | 74 | 75 | 76 | === TEST 4: matched with do 77 | --- config 78 | location /re { 79 | content_by_lua ' 80 | m = ngx.re.match("hello", "he|hell", "do") 81 | if m then 82 | ngx.say(m[0]) 83 | ngx.say(m[1]) 84 | ngx.say(m[2]) 85 | else 86 | ngx.say("not matched!") 87 | end 88 | '; 89 | } 90 | --- request 91 | GET /re 92 | --- response_body 93 | hell 94 | nil 95 | nil 96 | 97 | 98 | 99 | === TEST 5: not matched with do 100 | --- config 101 | location /re { 102 | content_by_lua ' 103 | m = ngx.re.match("world", "([0-9]+)", "do") 104 | if m then 105 | ngx.say(m[0]) 106 | else 107 | ngx.say("not matched!") 108 | end 109 | '; 110 | } 111 | --- request 112 | GET /re 113 | --- response_body 114 | not matched! 115 | 116 | 117 | 118 | === TEST 6: UTF-8 mode without UTF-8 sequence checks 119 | --- config 120 | location /re { 121 | content_by_lua ' 122 | local m = ngx.re.match("你好", ".", "Ud") 123 | if m then 124 | ngx.say(m[0]) 125 | else 126 | ngx.say("not matched!") 127 | end 128 | '; 129 | } 130 | --- stap 131 | probe process("$LIBPCRE_PATH").function("pcre_compile") { 132 | printf("compile opts: %x\n", $options) 133 | } 134 | 135 | probe process("$LIBPCRE_PATH").function("pcre_dfa_exec") { 136 | printf("exec opts: %x\n", $options) 137 | } 138 | 139 | --- stap_out 140 | compile opts: 800 141 | exec opts: 2000 142 | 143 | --- request 144 | GET /re 145 | --- response_body 146 | 你 147 | --- no_error_log 148 | [error] 149 | 150 | 151 | 152 | === TEST 7: UTF-8 mode with UTF-8 sequence checks 153 | --- config 154 | location /re { 155 | content_by_lua ' 156 | local m = ngx.re.match("你好", ".", "ud") 157 | if m then 158 | ngx.say(m[0]) 159 | else 160 | ngx.say("not matched!") 161 | end 162 | '; 163 | } 164 | --- stap 165 | probe process("$LIBPCRE_PATH").function("pcre_compile") { 166 | printf("compile opts: %x\n", $options) 167 | } 168 | 169 | probe process("$LIBPCRE_PATH").function("pcre_dfa_exec") { 170 | printf("exec opts: %x\n", $options) 171 | } 172 | 173 | --- stap_out 174 | compile opts: 800 175 | exec opts: 0 176 | 177 | --- request 178 | GET /re 179 | --- response_body 180 | 你 181 | --- no_error_log 182 | [error] 183 | 184 | -------------------------------------------------------------------------------- /Changes: -------------------------------------------------------------------------------- 1 | 0.2.0 - 5 July 2011 2 | * now we support ngx.var[1], ngx.var[2], and etc to refer to the nginx regex capturing variables \$1, \$2, and etc in Lua. this resolved github issue #43. thanks Tobia Conforto for reporting it. 3 | 4 | * now we use the same value overriding mechanism as ngx_rewrite's set command for ngx.var.VAR = new_value. Assigning values to special variables like $limit_rate and $args should now work; also writing to built-in variables that are not changeable (like $arg_PARAMETER) will result in a 500 error page, as expected, now. thanks Richard Kearsley for reporting it. 5 | 6 | * fixed the lua_code_cache off warning when the lua_code_cache is explicitly on. thanks Feng Xingguo. 7 | 8 | * applied the patch from cyberty to add ngx.http_time() function to expose the nginx core function ngx_http_time to the Lua land. 9 | 10 | * fixed an issue on i386: we now use off_t consistently. mixing it with size_t on 32-bit systems can cause Bad Things. this fixed github issue #42. thanks moodydeath. 11 | 12 | * fixed an issue on i386: fixed a formatter mismatch issue in ngx_http_echo_adjust_subrequest. thanks Wang Bin. This caused incorrect subrequest Content-Length header when a body is specified. 13 | 14 | * now in the subrequest capturing processor, we worked around an issue in ngx_http_static_module that when it issues 301 redirect for directory access w/o a trailing slash, it does not inject r->headers_out.location into the r->headers_out.headers list. thanks moodydeath for reporting it in the discussion of github issue #41. 15 | 16 | * fixed a bug in ngx.location.capture() and ngx.location.capture_multi() that we could not capture locations with internal redirections in them. thanks moodydeath for reporting it in github issue #41. 17 | 18 | * fixed redundant last chunk issue for ngx.exec() invocation at rewrite and access phases: we should quit the current core_run_phases cycle; this also fixed github issue #40: 2 Subrequest calls when using access_by_lua, ngx.exec and echo_location. 19 | 20 | * fixed ngx.exit(status) where status >= 200 and status < 300 for access_by_lua* and rewrite_by_lua*: it should quit the whole request altegother and skip all those subsequent phase handlers (if any). thanks moodydeath for reporting it. 21 | 22 | * fixed github issue #39: setting differnt response headers in Lua with common prefix might interfere with each other. thanks moodydeath. 23 | 24 | * fixed GitHub issue #38: request headers did not forward to subrequests when the "method" or "body" option is explicitly specified by a non-nil value for ngx.location.capture(). thanks Richard Kearsley. 25 | 26 | * fixed a bug in output header set; we should always set the header->hash to 1. thanks moodydeath for reporting it. 27 | 28 | * fixed spots that trigger the "variable set but not used" warning issued by gcc 4.6.0. 29 | 30 | * now we turn the ngx.req.header table into an ngx.req.get_headers() function; we also added ngx.req.set_header(name, value) and ngx.req.clear_header(name). thanks moodydeath. 31 | 32 | * now we make ngx_devel_kit (NDK) optional. thanks Kirill A. Korinskiy. 33 | 34 | * removed a duplicate definition of the ngx_str_set macro caught by ctags; also fixed a warning thrown by gcc -O3 on Mac OS X 10.6. 35 | 36 | * added patch to use PCRE related Lua extensions in ngx_lua (chaoslawful) 37 | 38 | * now we change the way we process HTTP 1.0 requests by automatically buffering all the user outputs generated by ngx.print()/ngx.say() calls, which is much more natural than the old broken way. 39 | 40 | * fixed the "ngx.exec() after ngx.location.capture() hanging" bug for rewrite_by_lua* and access_by_lua* as well. thanks Wendal Chen. 41 | 42 | * applied a patch from moodydeath to introduce the "ngx.is_subrequest" attribute. 43 | 44 | * now we encourage use of the client_body_in_single_buffer directive instead of big client_body_buffer_size when lua_need_request_body is turned on. 45 | 46 | * fixed the config script and added extra linking options needed by LuaJIT in 64-bit Mac OS X. 47 | 48 | * fixed the zero size alert caused by ngx.print("") in Lua. 49 | 50 | * now we always allocate r->request_body for subrequests when the method option is specified for ngx.location.capture*. this prevents accidental inheritance of parent request's request body when client_body_buffer_size < client_max_body_size. 51 | 52 | -------------------------------------------------------------------------------- /t/024-access/request_body.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | use Test::Nginx::Socket::Lua; 3 | 4 | #worker_connections(1014); 5 | #master_process_enabled(1); 6 | log_level('debug'); # to ensure any log-level can be outputed 7 | 8 | repeat_each(2); 9 | 10 | plan tests => repeat_each() * (blocks() * 2 + 2); 11 | 12 | #no_diff(); 13 | #no_long_string(); 14 | run_tests(); 15 | 16 | __DATA__ 17 | 18 | === TEST 1: test reading request body 19 | --- config 20 | location /echo_body { 21 | lua_need_request_body on; 22 | access_by_lua ' 23 | ngx.print(ngx.var.request_body or "nil") 24 | '; 25 | content_by_lua 'ngx.exit(ngx.OK)'; 26 | } 27 | --- request eval 28 | "POST /echo_body 29 | hello\x00\x01\x02 30 | world\x03\x04\xff" 31 | --- response_body eval 32 | "hello\x00\x01\x02 33 | world\x03\x04\xff" 34 | 35 | 36 | 37 | === TEST 2: test not reading request body 38 | --- config 39 | location /echo_body { 40 | lua_need_request_body off; 41 | access_by_lua ' 42 | ngx.print(ngx.var.request_body or "nil") 43 | '; 44 | content_by_lua 'ngx.exit(ngx.OK)'; 45 | } 46 | --- request eval 47 | "POST /echo_body 48 | hello\x00\x01\x02 49 | world\x03\x04\xff" 50 | --- response_body eval 51 | "nil" 52 | 53 | 54 | 55 | === TEST 3: test default setting (not reading request body) 56 | --- config 57 | location /echo_body { 58 | access_by_lua ' 59 | ngx.print(ngx.var.request_body or "nil") 60 | '; 61 | content_by_lua 'ngx.exit(ngx.OK)'; 62 | } 63 | --- request eval 64 | "POST /echo_body 65 | hello\x00\x01\x02 66 | world\x03\x04\xff" 67 | --- response_body eval 68 | "nil" 69 | 70 | 71 | 72 | === TEST 4: test main conf 73 | --- http_config 74 | lua_need_request_body on; 75 | --- config 76 | location /echo_body { 77 | access_by_lua ' 78 | ngx.print(ngx.var.request_body or "nil") 79 | '; 80 | content_by_lua 'ngx.exit(ngx.OK)'; 81 | } 82 | --- request eval 83 | "POST /echo_body 84 | hello\x00\x01\x02 85 | world\x03\x04\xff" 86 | --- response_body eval 87 | "hello\x00\x01\x02 88 | world\x03\x04\xff" 89 | 90 | 91 | 92 | === TEST 5: test server conf 93 | --- config 94 | lua_need_request_body on; 95 | 96 | location /echo_body { 97 | access_by_lua ' 98 | ngx.print(ngx.var.request_body or "nil") 99 | '; 100 | content_by_lua 'ngx.exit(ngx.OK)'; 101 | } 102 | --- request eval 103 | "POST /echo_body 104 | hello\x00\x01\x02 105 | world\x03\x04\xff" 106 | --- response_body eval 107 | "hello\x00\x01\x02 108 | world\x03\x04\xff" 109 | 110 | 111 | 112 | === TEST 6: test override main conf 113 | --- http_config 114 | lua_need_request_body on; 115 | --- config 116 | location /echo_body { 117 | lua_need_request_body off; 118 | access_by_lua ' 119 | ngx.print(ngx.var.request_body or "nil") 120 | '; 121 | content_by_lua 'ngx.exit(ngx.OK)'; 122 | } 123 | --- request eval 124 | "POST /echo_body 125 | hello\x00\x01\x02 126 | world\x03\x04\xff" 127 | --- response_body eval 128 | "nil" 129 | 130 | 131 | 132 | === TEST 7: test override server conf 133 | --- config 134 | lua_need_request_body on; 135 | 136 | location /echo_body { 137 | lua_need_request_body off; 138 | access_by_lua ' 139 | ngx.print(ngx.var.request_body or "nil") 140 | '; 141 | content_by_lua 'ngx.exit(ngx.OK)'; 142 | } 143 | --- request eval 144 | "POST /echo_body 145 | hello\x00\x01\x02 146 | world\x03\x04\xff" 147 | --- response_body eval 148 | "nil" 149 | 150 | 151 | 152 | === TEST 8: Expect: 100-Continue 153 | --- config 154 | location /echo_body { 155 | lua_need_request_body on; 156 | access_by_lua ' 157 | ngx.print(ngx.var.request_body or "nil") 158 | ngx.exit(200) 159 | '; 160 | } 161 | --- request 162 | POST /echo_body 163 | hello world 164 | --- more_headers 165 | Expect: 100-Continue 166 | --- ignore_response 167 | --- no_error_log 168 | [error] 169 | [alert] 170 | http finalize request: 500, "/echo_body?" a:1, c:2 171 | http finalize request: 500, "/echo_body?" a:1, c:0 172 | --- log_level: debug 173 | 174 | -------------------------------------------------------------------------------- /t/023-rewrite/request_body.t: -------------------------------------------------------------------------------- 1 | # vim:set ft= ts=4 sw=4 et fdm=marker: 2 | use Test::Nginx::Socket::Lua; 3 | 4 | #worker_connections(1014); 5 | #master_process_enabled(1); 6 | log_level('debug'); # to ensure any log-level can be outputed 7 | 8 | repeat_each(2); 9 | 10 | plan tests => repeat_each() * (blocks() * 2 + 2); 11 | 12 | #no_diff(); 13 | #no_long_string(); 14 | run_tests(); 15 | 16 | __DATA__ 17 | 18 | === TEST 1: test reading request body 19 | --- config 20 | location /echo_body { 21 | lua_need_request_body on; 22 | rewrite_by_lua ' 23 | ngx.print(ngx.var.request_body or "nil") 24 | '; 25 | content_by_lua 'ngx.exit(ngx.OK)'; 26 | } 27 | --- request eval 28 | "POST /echo_body 29 | hello\x00\x01\x02 30 | world\x03\x04\xff" 31 | --- response_body eval 32 | "hello\x00\x01\x02 33 | world\x03\x04\xff" 34 | 35 | 36 | 37 | === TEST 2: test not reading request body 38 | --- config 39 | location /echo_body { 40 | lua_need_request_body off; 41 | rewrite_by_lua ' 42 | ngx.print(ngx.var.request_body or "nil") 43 | '; 44 | content_by_lua 'ngx.exit(ngx.OK)'; 45 | } 46 | --- request eval 47 | "POST /echo_body 48 | hello\x00\x01\x02 49 | world\x03\x04\xff" 50 | --- response_body eval 51 | "nil" 52 | 53 | 54 | 55 | === TEST 3: test default setting (not reading request body) 56 | --- config 57 | location /echo_body { 58 | rewrite_by_lua ' 59 | ngx.print(ngx.var.request_body or "nil") 60 | '; 61 | content_by_lua 'ngx.exit(ngx.OK)'; 62 | } 63 | --- request eval 64 | "POST /echo_body 65 | hello\x00\x01\x02 66 | world\x03\x04\xff" 67 | --- response_body eval 68 | "nil" 69 | 70 | 71 | 72 | === TEST 4: test main conf 73 | --- http_config 74 | lua_need_request_body on; 75 | --- config 76 | location /echo_body { 77 | rewrite_by_lua ' 78 | ngx.print(ngx.var.request_body or "nil") 79 | '; 80 | content_by_lua 'ngx.exit(ngx.OK)'; 81 | } 82 | --- request eval 83 | "POST /echo_body 84 | hello\x00\x01\x02 85 | world\x03\x04\xff" 86 | --- response_body eval 87 | "hello\x00\x01\x02 88 | world\x03\x04\xff" 89 | 90 | 91 | 92 | === TEST 5: test server conf 93 | --- config 94 | lua_need_request_body on; 95 | 96 | location /echo_body { 97 | rewrite_by_lua ' 98 | ngx.print(ngx.var.request_body or "nil") 99 | '; 100 | content_by_lua 'ngx.exit(ngx.OK)'; 101 | } 102 | --- request eval 103 | "POST /echo_body 104 | hello\x00\x01\x02 105 | world\x03\x04\xff" 106 | --- response_body eval 107 | "hello\x00\x01\x02 108 | world\x03\x04\xff" 109 | 110 | 111 | 112 | === TEST 6: test override main conf 113 | --- http_config 114 | lua_need_request_body on; 115 | --- config 116 | location /echo_body { 117 | lua_need_request_body off; 118 | rewrite_by_lua ' 119 | ngx.print(ngx.var.request_body or "nil") 120 | '; 121 | content_by_lua 'ngx.exit(ngx.OK)'; 122 | } 123 | --- request eval 124 | "POST /echo_body 125 | hello\x00\x01\x02 126 | world\x03\x04\xff" 127 | --- response_body eval 128 | "nil" 129 | 130 | 131 | 132 | === TEST 7: test override server conf 133 | --- config 134 | lua_need_request_body on; 135 | 136 | location /echo_body { 137 | lua_need_request_body off; 138 | rewrite_by_lua ' 139 | ngx.print(ngx.var.request_body or "nil") 140 | '; 141 | content_by_lua 'ngx.exit(ngx.OK)'; 142 | } 143 | --- request eval 144 | "POST /echo_body 145 | hello\x00\x01\x02 146 | world\x03\x04\xff" 147 | --- response_body eval 148 | "nil" 149 | 150 | 151 | 152 | === TEST 8: Expect: 100-Continue 153 | --- config 154 | location /echo_body { 155 | lua_need_request_body on; 156 | rewrite_by_lua ' 157 | ngx.print(ngx.var.request_body or "nil") 158 | ngx.exit(200) 159 | '; 160 | } 161 | --- request 162 | POST /echo_body 163 | hello world 164 | --- more_headers 165 | Expect: 100-Continue 166 | --- ignore_response 167 | --- no_error_log 168 | [error] 169 | [alert] 170 | http finalize request: 500, "/echo_body?" a:1, c:2 171 | http finalize request: 500, "/echo_body?" a:1, c:0 172 | --- log_level: debug 173 | 174 | --------------------------------------------------------------------------------