├── .gitignore ├── README.md ├── lib └── resty │ └── master │ ├── http │ ├── core.lua │ └── request.lua │ └── stream │ ├── core.lua │ └── request.lua └── util └── lua-releng /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.a 3 | *.so 4 | *.out 5 | *.pyc 6 | *.dylib 7 | *.dSYM/ 8 | 9 | *.swp 10 | *.swo 11 | *.un~ 12 | *.DS_Store 13 | 14 | tags 15 | 16 | t/servroot 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | lua-resty-master 2 | ==== 3 | 4 | Development framework for OpenResty, inspired by NGINX. 5 | 6 | 7 | # License 8 | 9 | MIT 10 | -------------------------------------------------------------------------------- /lib/resty/master/http/core.lua: -------------------------------------------------------------------------------- 1 | -- Copyright (C) Jingli Chen (Wine93) 2 | -- Copyright (C) Jinzheng Zhang (tianchaijz) 3 | 4 | 5 | local _M = {} 6 | 7 | 8 | _M.INIT_WORKER = -1 9 | 10 | _M.REWRITE_PHASE = 1 11 | _M.ACCESS_PHASE = 2 12 | _M.CONTENT_PHASE = 3 13 | _M.HEADER_FILTER_PHASE = 4 14 | _M.BODY_FILTER_PHASE = 5 15 | _M.LOG_PHASE = 6 16 | 17 | 18 | return _M 19 | -------------------------------------------------------------------------------- /lib/resty/master/http/request.lua: -------------------------------------------------------------------------------- 1 | -- Copyright (C) Jingli Chen (Wine93) 2 | -- Copyright (C) Jinzheng Zhang (tianchaijz) 3 | 4 | 5 | local core = require "resty.master.http.core" 6 | 7 | 8 | local type = type 9 | local ipairs = ipairs 10 | local assert = assert 11 | local setmetatable = setmetatable 12 | 13 | 14 | local _M = {} 15 | local _mt = { __index = _M } 16 | local _handlers = {} 17 | local _inits = {} -- init worker hooks 18 | local _inits_loaded = {} 19 | 20 | 21 | _M.REWRITE_PHASE = core.REWRITE_PHASE 22 | _M.ACCESS_PHASE = core.ACCESS_PHASE 23 | _M.CONTENT_PHASE = core.CONTENT_PHASE 24 | _M.HEADER_FILTER_PHASE = core.HEADER_FILTER_PHASE 25 | _M.BODY_FILTER_PHASE = core.BODY_FILTER_PHASE 26 | _M.LOG_PHASE = core.LOG_PHASE 27 | 28 | 29 | local function is_tbl(obj) return type(obj) == "table" end 30 | 31 | 32 | local function load_module_phase(module, phase) 33 | local phase_ctx 34 | if is_tbl(module) then 35 | local export = module.export 36 | if is_tbl(export) and not export[phase] then 37 | return 38 | end 39 | 40 | local ctx = module.ctx 41 | if is_tbl(ctx) then 42 | phase_ctx = ctx[phase] or ctx 43 | end 44 | 45 | module = module[1] 46 | end 47 | local mod = assert(require(module), module) 48 | return module, mod[phase], phase_ctx or {} 49 | end 50 | 51 | 52 | local function phase_handler(modules, phase) 53 | local chain 54 | local index = {} 55 | for idx = #modules, 1, -1 do 56 | local module, ph, ctx = load_module_phase(modules[idx], phase) 57 | if ph then 58 | chain = { next = chain, handler = ph.handler, ctx = ctx } 59 | index[module] = chain 60 | end 61 | end 62 | return { chain = chain, index = index } 63 | end 64 | 65 | 66 | local function next_handler(self, phase, module) 67 | local ph = _handlers[self._type][phase] 68 | if not ph then 69 | return 70 | end 71 | 72 | local chain = ph.index[module].next 73 | if chain then 74 | return chain.handler(self, chain.ctx) 75 | end 76 | end 77 | 78 | 79 | local function run_phase(self) 80 | local ph = _handlers[self._type][self._phase] 81 | local chain = ph.chain 82 | if chain then 83 | chain.handler(self, chain.ctx) 84 | end 85 | end 86 | 87 | 88 | function _M.new(typ) 89 | local r = { _ctx = {}, _type = typ, _phase = 0 } 90 | return setmetatable(r, _mt) 91 | end 92 | 93 | 94 | function _M.register(typ, modules) 95 | local handler = {} 96 | for phase = _M.REWRITE_PHASE, _M.LOG_PHASE, 1 do 97 | handler[phase] = phase_handler(modules, phase) 98 | end 99 | _handlers[typ] = handler 100 | 101 | for _, mod in ipairs(modules) do 102 | local module, init, ctx = load_module_phase(mod, core.INIT_WORKER) 103 | if init and init.handler then 104 | if not ctx then 105 | if _inits_loaded[module] then 106 | ngx.log(ngx.ERR, module, 107 | " init multiple times without context") 108 | else 109 | _inits_loaded[module] = true 110 | end 111 | end 112 | 113 | _inits[#_inits + 1] = { init.handler, ctx } 114 | end 115 | end 116 | end 117 | 118 | 119 | function _M.init() 120 | local handler, ctx 121 | for _, init in ipairs(_inits) do 122 | handler, ctx = init[1], init[2] 123 | handler(ctx) 124 | end 125 | 126 | _inits = {} 127 | _inits_loaded = {} 128 | end 129 | 130 | 131 | function _M.get_type(self) 132 | return self._type 133 | end 134 | 135 | 136 | local function set_type(self, typ) 137 | self._type = typ 138 | end 139 | _M.set_type = set_type 140 | 141 | 142 | local function set_phase(self, phase) 143 | self._phase = phase 144 | end 145 | _M.set_phase = set_phase 146 | 147 | 148 | function _M.get_phase(self) 149 | return self._phase 150 | end 151 | 152 | 153 | function _M.get_module_ctx(self, module) 154 | return self._ctx[module] 155 | end 156 | 157 | 158 | function _M.set_module_ctx(self, module, ctx) 159 | self._ctx[module] = ctx 160 | end 161 | 162 | 163 | function _M.next_handler(self, module) 164 | return next_handler(self, self._phase, module) 165 | end 166 | 167 | 168 | -- content -> header filter -> content 169 | function _M.run(self, phase) 170 | local old_phase = self._phase 171 | set_phase(self, phase) 172 | run_phase(self) 173 | set_phase(self, old_phase) 174 | end 175 | 176 | 177 | function _M.exec(self, typ) 178 | local old_phase = self._phase 179 | set_type(self, typ) 180 | run_phase(self) 181 | set_phase(self, old_phase) 182 | end 183 | 184 | 185 | return _M 186 | -------------------------------------------------------------------------------- /lib/resty/master/stream/core.lua: -------------------------------------------------------------------------------- 1 | -- Copyright (C) Jingli Chen (Wine93) 2 | -- Copyright (C) Jinzheng Zhang (tianchaijz) 3 | 4 | 5 | local _M = {} 6 | 7 | 8 | _M.INIT_WORKER = -1 9 | 10 | _M.PREREAD_PHASE = 1 11 | _M.CONTENT_PHASE = 2 12 | _M.LOG_PHASE = 3 13 | 14 | 15 | return _M 16 | -------------------------------------------------------------------------------- /lib/resty/master/stream/request.lua: -------------------------------------------------------------------------------- 1 | -- Copyright (C) Jingli Chen (Wine93) 2 | -- Copyright (C) Jinzheng Zhang (tianchaijz) 3 | 4 | 5 | local core = require "resty.master.stream.core" 6 | 7 | local type = type 8 | local ipairs = ipairs 9 | local assert = assert 10 | local setmetatable = setmetatable 11 | 12 | 13 | local _M = {} 14 | local _mt = { __index = _M } 15 | local _handlers = {} 16 | local _inits = {} -- init worker hooks 17 | local _inits_loaded = {} 18 | 19 | 20 | _M.PREREAD_PHASE = core.PREREAD_PHASE 21 | _M.CONTENT_PHASE = core.CONTENT_PHASE 22 | _M.LOG_PHASE = core.LOG_PHASE 23 | 24 | 25 | local function is_tbl(obj) return type(obj) == "table" end 26 | 27 | 28 | local function load_module_phase(module, phase) 29 | local phase_ctx 30 | if is_tbl(module) then 31 | local export = module.export 32 | if is_tbl(export) and not export[phase] then 33 | return 34 | end 35 | 36 | local ctx = module.ctx 37 | if is_tbl(ctx) then 38 | phase_ctx = ctx[phase] or ctx 39 | end 40 | 41 | module = module[1] 42 | end 43 | local mod = assert(require(module), module) 44 | return module, mod[phase], phase_ctx or {} 45 | end 46 | 47 | 48 | local function phase_handler(modules, phase) 49 | local chain 50 | local index = {} 51 | for idx = #modules, 1, -1 do 52 | local module, ph, ctx = load_module_phase(modules[idx], phase) 53 | if ph then 54 | chain = { next = chain, handler = ph.handler, ctx = ctx } 55 | index[module] = chain 56 | end 57 | end 58 | return { chain = chain, index = index } 59 | end 60 | 61 | 62 | local function next_handler(self, phase, module) 63 | local ph = _handlers[self._type][phase] 64 | if not ph then 65 | return 66 | end 67 | 68 | local chain = ph.index[module].next 69 | if chain then 70 | return chain.handler(self, chain.ctx) 71 | end 72 | end 73 | 74 | 75 | local function run_phase(self) 76 | local ph = _handlers[self._type][self._phase] 77 | local chain = ph.chain 78 | if chain then 79 | chain.handler(self, chain.ctx) 80 | end 81 | end 82 | 83 | 84 | function _M.new(typ) 85 | local r = { _ctx = {}, _type = typ, _phase = 0 } 86 | return setmetatable(r, _mt) 87 | end 88 | 89 | 90 | function _M.register(typ, modules) 91 | local handler = {} 92 | for phase = _M.PREREAD_PHASE, _M.LOG_PHASE, 1 do 93 | handler[phase] = phase_handler(modules, phase) 94 | end 95 | _handlers[typ] = handler 96 | 97 | for _, mod in ipairs(modules) do 98 | local module, init, ctx = load_module_phase(mod, core.INIT_WORKER) 99 | if init and init.handler then 100 | if not ctx then 101 | if _inits_loaded[module] then 102 | ngx.log(ngx.ERR, module, 103 | " init multiple times without context") 104 | else 105 | _inits_loaded[module] = true 106 | end 107 | end 108 | 109 | _inits[#_inits + 1] = { init.handler, ctx } 110 | end 111 | end 112 | end 113 | 114 | 115 | function _M.init() 116 | local handler, ctx 117 | for _, init in ipairs(_inits) do 118 | handler, ctx = init[1], init[2] 119 | handler(ctx) 120 | end 121 | 122 | _inits = {} 123 | _inits_loaded = {} 124 | end 125 | 126 | 127 | function _M.get_type(self) 128 | return self._type 129 | end 130 | 131 | 132 | local function set_type(self, typ) 133 | self._type = typ 134 | end 135 | _M.set_type = set_type 136 | 137 | 138 | local function set_phase(self, phase) 139 | self._phase = phase 140 | end 141 | _M.set_phase = set_phase 142 | 143 | 144 | function _M.get_phase(self) 145 | return self._phase 146 | end 147 | 148 | 149 | function _M.get_module_ctx(self, module) 150 | return self._ctx[module] 151 | end 152 | 153 | 154 | function _M.set_module_ctx(self, module, ctx) 155 | self._ctx[module] = ctx 156 | end 157 | 158 | 159 | function _M.next_handler(self, module) 160 | return next_handler(self, self._phase, module) 161 | end 162 | 163 | 164 | function _M.run(self, phase) 165 | local old_phase = self._phase 166 | set_phase(self, phase) 167 | run_phase(self) 168 | set_phase(self, old_phase) 169 | end 170 | 171 | 172 | function _M.exec(self, typ) 173 | local old_phase = self._phase 174 | set_type(self, typ) 175 | run_phase(self) 176 | set_phase(self, old_phase) 177 | end 178 | 179 | 180 | return _M 181 | -------------------------------------------------------------------------------- /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 t/*.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 | 23 | } elsif (/(?x) (?:_VERSION) \s* = \s* ([a-zA-Z_]\S*)/) { 24 | warn "$file: $1\n"; 25 | $found_ver = 1; 26 | last; 27 | } 28 | 29 | if ($ver and $version and !$skipping) { 30 | if ($version ne $ver) { 31 | # die "$file: $ver != $version\n"; 32 | } 33 | } elsif ($ver and !$version) { 34 | $version = $ver; 35 | } 36 | } 37 | if (!$found_ver) { 38 | warn "WARNING: No \"_VERSION\" or \"version\" field found in `$file`.\n"; 39 | } 40 | close $in; 41 | 42 | print "Checking use of Lua global variables in file $file ...\n"; 43 | system("luac5.1 -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|collectgarbage'"); 44 | #file_contains($file, "attempt to write to undeclared variable"); 45 | system("grep -H -n -E --color '.{120}' $file"); 46 | } 47 | 48 | sub file_contains ($$) { 49 | my ($file, $regex) = @_; 50 | open my $in, $file 51 | or die "Cannot open $file fo reading: $!\n"; 52 | my $content = do { local $/; <$in> }; 53 | close $in; 54 | #print "$content"; 55 | return scalar ($content =~ /$regex/); 56 | } 57 | 58 | if (-d 't') { 59 | for my $file (map glob, qw{ t/*.t t/*/*.t t/*/*/*.t }) { 60 | system(qq{grep -H -n --color -E '\\--- ?(ONLY|LAST)' $file}); 61 | } 62 | } 63 | 64 | --------------------------------------------------------------------------------