├── .gitattributes
├── .gitignore
├── .travis.yml
├── Makefile
├── README.md
├── dist.ini
├── lib
└── resty
│ └── ctxdump.lua
├── lua-resty-ctxdump-0.1-0.rockspec
├── t
├── 00-sanity.t
└── 01-bug.t
└── util
└── lua-releng
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.t linguist-language=Text
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | t/servroot/*
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: perl
2 | perl:
3 | - 5.10
4 | cache:
5 | - apt
6 | - ccache
7 | env:
8 | - V_OPENRESTY=1.9.15.1
9 | install:
10 | - cpanm -v --notest Test::Nginx
11 | before_script:
12 | - sudo apt-get update -q
13 | - sudo apt-get install libreadline-dev libncurses5-dev libpcre3-dev libssl-dev -y
14 | - sudo apt-get install make build-essential lua5.1 -y
15 | - wget https://openresty.org/download/openresty-$V_OPENRESTY.tar.gz
16 | - tar xzf openresty-$V_OPENRESTY.tar.gz
17 | - cd openresty-$V_OPENRESTY && ./configure && make && sudo make install && cd ..
18 | script:
19 | - make test
20 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | OPENRESTY_PREFIX=/usr/local/openresty
2 |
3 | PREFIX ?= /usr/local
4 | LUA_INCLUDE_DIR ?= $(PREFIX)/include
5 | LUA_LIB_DIR ?= $(PREFIX)/lib/lua/$(LUA_VERSION)
6 | INSTALL ?= install
7 |
8 | .PHONY: all test install
9 |
10 | all: ;
11 |
12 | install: all
13 | $(INSTALL) -d $(DESTDIR)/$(LUA_LIB_DIR)/resty/
14 | $(INSTALL) lib/resty/*.lua $(DESTDIR)/$(LUA_LIB_DIR)/resty/
15 |
16 | test: all
17 | sudo cp lib/resty/ctxdump.lua $(OPENRESTY_PREFIX)/lualib/resty
18 | PATH=$(OPENRESTY_PREFIX)/nginx/sbin:$$PATH prove -I../test-nginx/lib -r t/
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Name
2 | ====
3 |
4 | lua-resty-ctxdump - stash and apply the ngx.ctx, avoiding being destoried after Nginx internal redirect happens.
5 |
6 | 
7 |
8 | Table of Contents
9 | =================
10 |
11 | * [Name](#name)
12 | * [Status](#status)
13 | * [Synopsis](#synopsis)
14 | * [Methods](#methods)
15 | * [stash_ngx_ctx](#stash_ngx_ctx)
16 | * [apply_ngx_ctx](#apply_ngx_ctx)
17 | * [Author](#author)
18 | * [Copyright and License](#copyright-and-license)
19 | * [See Also](#see-also)
20 |
21 | Status
22 | ======
23 |
24 | Probably production ready in most cases, though not yet proven in the wild. Please check the issues list and let me know if you have any problems / questions.
25 |
26 | Synopsis
27 | ========
28 |
29 | ```lua
30 |
31 | location /t1 {
32 | set $ctx_ref "";
33 | content_by_lua_block {
34 | local ctxdump = require "resty.ctxdump"
35 | ngx.ctx = {
36 | Date = "Wed May 3 15:18:04 CST 2017",
37 | Site = "unknown"
38 | }
39 | ngx.var.ctx_ref = ctxdump.stash_ngx_ctx()
40 | ngx.exec("/t2")
41 | }
42 | }
43 |
44 | location /t2 {
45 | internal;
46 | content_by_lua_block {
47 | local ctxdump = require "resty.ctxdump"
48 | ngx.ctx = ctxdump.apply_ngx_ctx(ngx.var.ctx_ref)
49 | ngx.say("Date: " .. ngx.ctx["Date"] .. " Site: " .. ngx.ctx["Site"])
50 | }
51 | }
52 |
53 | ```
54 |
55 | Methods
56 | =======
57 |
58 | stash_ngx_ctx
59 | -------------
60 |
61 | **syntax:** *ref = stash_ngx_ctx()*
62 | **phase:** *init_worker_by_lua\*, set_by_lua\*, rewrite_by_lua\*, access_by_lua\*,
63 | content_by_lua\*, header_filter_by_lua\*, body_filter_by_lua\*, log_by_lua\*,
64 | ngx.timer.\*, balancer_by_lua\*
65 |
66 | Reference the `ngx.ctx`, returns an anchor(a new reference maintained by lua-resty-ctxdump).
67 |
68 | Note: `stash_ngx_ctx` and `apply_ngx_ctx` must be called in pairs, otherwise memory leak will happen! See [apply_ngx_ctx](#apply_ngx_ctx).
69 |
70 | apply_ngx_ctx
71 | -------------
72 |
73 | **syntax:** *old_ngx_ctx = apply_ngx_ctx(ref)*
74 | **phase:** *init_worker_by_lua\*, set_by_lua\*, rewrite_by_lua\*, access_by_lua\*,
75 | content_by_lua\*, header_filter_by_lua\*, body_filter_by_lua\*, log_by_lua\*,
76 | ngx.timer.\*, balancer_by_lua\*
77 |
78 | fetch the old `ngx.ctx` with the anchor returns from `stash_ngx_ctx `. After that, the anchor will be out of work.
79 |
80 | Note: `stash_ngx_ctx` and `apply_ngx_ctx ` must be called in pairs, otherwise memory leak will happen! See [stash_ngx_ctx](#stash_ngx_ctx).
81 |
82 |
83 | Author
84 | ======
85 |
86 | Alex Zhang(张超) tokers@apache.org, @api7.ai.
87 |
88 |
89 | Copyright and License
90 | =====================
91 |
92 | The bundle itself is licensed under the 2-clause BSD license.
93 |
94 | Copyright (c) 2017-2021, Alex Zhang.
95 |
96 | This module is licensed under the terms of the BSD license.
97 |
98 | Redistribution and use in source and binary forms, with or without
99 | modification, are permitted provided that the following conditions are
100 | met:
101 |
102 | * Redistributions of source code must retain the above copyright notice, this
103 | list of conditions and the following disclaimer.
104 | * Redistributions in binary form must reproduce the above copyright notice, this
105 | list of conditions and the following disclaimer in the documentation and/or
106 | other materials provided with the distribution.
107 |
108 |
109 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
110 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
111 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
112 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
113 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
114 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
115 |
116 | See Also
117 | ========
118 |
119 | * upyun-resty: https://github.com/upyun/upyun-resty
120 |
--------------------------------------------------------------------------------
/dist.ini:
--------------------------------------------------------------------------------
1 | name = lua-resty-ctxdump
2 | abstract = Stash and apply the old ngx.ctx for avoiding being destoried after Nginx internal redirect happens.
3 | version = 0.03
4 | author = Alex Zhang(张超) zchao1995@gmail.com, UPYUN Inc.
5 | is_original = yes
6 | license = 2bsd
7 | lib_dir = lib
8 | repo_link = https://github.com/tokers/lua-resty-ctxdump
9 |
--------------------------------------------------------------------------------
/lib/resty/ctxdump.lua:
--------------------------------------------------------------------------------
1 | -- Copyright (C) UPYUN, Inc.
2 | -- Copyright (C) Alex Zhang
3 |
4 | local tonumber = tonumber
5 | local _M = { _VERSION = "0.03" }
6 | local memo = {}
7 | local FREE_LIST_REF = 0
8 |
9 |
10 | local function ref_in_table(tb, key)
11 | if key == nil then
12 | return -1
13 | end
14 |
15 | local ref = tb[FREE_LIST_REF]
16 | if ref and ref ~= FREE_LIST_REF then
17 | tb[FREE_LIST_REF] = tb[ref]
18 | else
19 | ref = #tb + 1
20 | end
21 |
22 | tb[ref] = key
23 |
24 | return ref
25 | end
26 |
27 |
28 | function _M.stash_ngx_ctx()
29 | local ctx_ref = ref_in_table(memo, ngx.ctx)
30 | return ctx_ref
31 | end
32 |
33 |
34 | function _M.apply_ngx_ctx(ref)
35 | ref = tonumber(ref)
36 | if not ref or ref <= FREE_LIST_REF then
37 | return nil, "bad ref value"
38 | end
39 |
40 | local old_ngx_ctx = memo[ref]
41 |
42 | -- dereference
43 | memo[ref] = memo[FREE_LIST_REF]
44 | memo[FREE_LIST_REF] = ref
45 |
46 | return old_ngx_ctx
47 | end
48 |
49 |
50 | return _M
51 |
--------------------------------------------------------------------------------
/lua-resty-ctxdump-0.1-0.rockspec:
--------------------------------------------------------------------------------
1 | package = "lua-resty-ctxdump"
2 | version = "0.1-0"
3 | source = {
4 | url = "git://github.com/tokers/lua-resty-ctxdump",
5 | tag = "v0.1"
6 | }
7 |
8 | description = {
9 | summary = "Stash and apply the ngx.ctx, avoiding being destoried after Nginx internal redirect happens",
10 | homepage = "https://github.com/tokers/lua-resty-ctxdump",
11 | license = "2-clause BSD license",
12 | maintainer = "Chao Zhang "
13 | }
14 |
15 | build = {
16 | type = "builtin",
17 | modules = {
18 | ["resty.ctxdump"] = "lib/resty/ctxdump.lua"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/t/00-sanity.t:
--------------------------------------------------------------------------------
1 | use lib 'lib';
2 | use Test::Nginx::Socket 'no_plan';
3 |
4 | repeat_each(2);
5 | run_tests();
6 |
7 | __DATA__
8 |
9 | === TEST 1: stash and apply the old ngx.ctx
10 |
11 | --- config
12 |
13 | location = /t1 {
14 | set $ctx_ref "";
15 | content_by_lua_block {
16 | local ctxdump = require "resty.ctxdump"
17 | ngx.ctx = {
18 | today = "wednesday",
19 | launch = "steak",
20 | drink = "wine",
21 | }
22 |
23 | ngx.var.ctx_ref = ctxdump.stash_ngx_ctx()
24 | ngx.exec("/t2")
25 | }
26 | }
27 |
28 | location = /t2 {
29 | content_by_lua_block {
30 | local ctxdump = require "resty.ctxdump"
31 | ngx.ctx = ctxdump.apply_ngx_ctx(ngx.var.ctx_ref)
32 | ngx.var.ctx_ref = ""
33 | ngx.say("today ", ngx.ctx["today"], " launch ", ngx.ctx["launch"],
34 | " drink ", ngx.ctx["drink"])
35 | }
36 | }
37 |
38 | --- request
39 | GET /t1
40 |
41 | --- error_code: 200
42 |
43 | --- response_body
44 | today wednesday launch steak drink wine
45 |
--------------------------------------------------------------------------------
/t/01-bug.t:
--------------------------------------------------------------------------------
1 | use lib 'lib';
2 | use Test::Nginx::Socket 'no_plan';
3 |
4 | repeat_each(2);
5 | run_tests();
6 |
7 | __DATA__
8 |
9 | === TEST 1: memo will be swell.
10 |
11 | --- config
12 |
13 | location = /t1 {
14 | set $ctx_ref "";
15 | content_by_lua_block {
16 | local ctxdump = require "resty.ctxdump"
17 | ngx.ctx = {
18 | today = "wednesday",
19 | launch = "steak",
20 | drink = "wine",
21 | }
22 |
23 | ngx.var.ctx_ref = ctxdump.stash_ngx_ctx()
24 | ngx.exec("/t2")
25 | }
26 | }
27 |
28 | location = /t2 {
29 | content_by_lua_block {
30 | local ctxdump = require "resty.ctxdump"
31 | ngx.ctx = ctxdump.apply_ngx_ctx(ngx.var.ctx_ref)
32 | ngx.say("ref is ", ngx.var.ctx_ref)
33 | ngx.var.ctx_ref = ""
34 | }
35 | }
36 |
37 | --- request
38 | GET /t1
39 |
40 | --- error_code: 200
41 |
42 | --- response_body
43 | ref is 1
44 |
45 | --- request
46 | GET /t1
47 |
48 | --- error_code: 200
49 |
50 | --- response_body
51 | ref is 1
52 |
--------------------------------------------------------------------------------
/util/lua-releng:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env perl
2 |
3 | use strict;
4 | use warnings;
5 |
6 | sub file_contains ($$);
7 |
8 | my $version;
9 | for my $file (map glob, qw{ *.lua lib/*.lua lib/*/*.lua lib/*/*/*.lua lib/*/*/*/*.lua lib/*/*/*/*/*.lua }) {
10 | # Check the sanity of each .lua file
11 | open my $in, $file or
12 | die "ERROR: Can't open $file for reading: $!\n";
13 | my $found_ver;
14 | while (<$in>) {
15 | my ($ver, $skipping);
16 | if (/(?x) (?:_VERSION) \s* = .*? ([\d\.]*\d+) (.*? SKIP)?/) {
17 | my $orig_ver = $ver = $1;
18 | $found_ver = 1;
19 | # $skipping = $2;
20 | $ver =~ s{^(\d+)\.(\d{3})(\d{3})$}{join '.', int($1), int($2), int($3)}e;
21 | warn "$file: $orig_ver ($ver)\n";
22 | } elsif (/(?x) (?:_VERSION) \s* = \s* ([a-zA-Z_]\S*)/) {
23 | warn "$file: $1\n";
24 | $found_ver = 1;
25 | last;
26 | }
27 | if ($ver and $version and !$skipping) {
28 | if ($version ne $ver) {
29 | # die "$file: $ver != $version\n";
30 | }
31 | } elsif ($ver and !$version) {
32 | $version = $ver;
33 | }
34 | }
35 | if (!$found_ver) {
36 | warn "WARNING: No \"_VERSION\" or \"version\" field found in `$file`.\n";
37 | }
38 | close $in;
39 | print "Checking use of Lua global variables in file $file ...\n";
40 | my $output = `luac -p -l $file | grep ETGLOBAL | grep -vE 'require|type|tostring|error|ngx\$|ndk|jit|setmetatable|getmetatable|string|table|io|os|print|tonumber|math|pcall|xpcall|unpack|pairs|ipairs|assert|module|package|coroutine|[gs]etfenv|next|select|rawset|rawget|debug'`;
41 | if ($output) {
42 | print $output;
43 | exit 1;
44 | }
45 | #file_contains($file, "attempt to write to undeclared variable");
46 | system("grep -H -n -E --color '.{120}' $file");
47 | }
48 |
49 | sub file_contains ($$) {
50 | my ($file, $regex) = @_;
51 | open my $in, $file
52 | or die "Cannot open $file fo reading: $!\n";
53 | my $content = do { local $/; <$in> };
54 | close $in;
55 | #print "$content";
56 | return scalar ($content =~ /$regex/);
57 | }
58 |
59 | if (-d 't') {
60 | for my $file (map glob, qw{ t/*.t t/*/*.t t/*/*/*.t }) {
61 | system(qq{grep -H -n --color -E '\\--- ?(ONLY|LAST)' $file});
62 | }
63 | }
64 |
--------------------------------------------------------------------------------