├── README ├── config ├── example ├── nginx │ ├── boundary.lua │ ├── init.lua │ ├── kit.lua │ ├── lp.lua │ └── urlcode.lua ├── t1.lua ├── t2.lua ├── t3.lua └── test.lp └── src ├── ngx_http_lua_module.c ├── strtok_r.c └── strtok_r.h /README: -------------------------------------------------------------------------------- 1 | -- example: 2 | 3 | lua_file "/usr/local/nginx/conf/test.lua"; 4 | 5 | location ~/test { 6 | lua_file "/usr/local/nginx/conf/test.lua"; 7 | } 8 | -------------------------------------------------------------------------------- /config: -------------------------------------------------------------------------------- 1 | ngx_feature="lua library" 2 | ngx_feature_libs="-llua -lm" 3 | ngx_feature_name= 4 | ngx_feature_run=no 5 | ngx_feature_incs="#include " 6 | ngx_feature_path= 7 | ngx_feature_test="(void) luaL_newstate();" 8 | 9 | if [ -n "$LUAJIT_INC" -o -n "$LUAJIT_LIB" ]; then 10 | # explicit set lua lib path 11 | ngx_feature="LuaJIT library in $LUAJIT_LIB and $LUAJIT_INC (specified by the LUAJIT_LIB and LUAJIT_INC env)" 12 | ngx_feature_path="$LUAJIT_INC" 13 | if [ $NGX_RPATH = YES ]; then 14 | ngx_feature_libs="-R$LUAJIT_LIB -L$LUAJIT_LIB -lluajit-5.1 -lm" 15 | else 16 | ngx_feature_libs="-L$LUAJIT_LIB -lluajit-5.1 -lm" 17 | fi 18 | 19 | . auto/feature 20 | 21 | if [ $ngx_found = no ]; then 22 | cat << END 23 | $0: error: the ngx_lua addon requires the lua or luajit library and LUAJIT_LIB is defined as $LUAJIT_LIB and LUAJIT_INC $LUAJIT_INC, but we cannot find LuaJIT there. 24 | END 25 | exit 1 26 | fi 27 | 28 | case "$NGX_PLATFORM" in 29 | Darwin:*) 30 | case "$NGX_MACHINE" in 31 | amd64 | x86_64 | i386) 32 | echo "adding extra linking options needed by LuaJIT" 33 | ngx_feature_libs="$ngx_feature_libs -pagezero_size 10000 -image_base 100000000" 34 | ;; 35 | 36 | *) 37 | ;; 38 | esac 39 | ;; 40 | 41 | *) 42 | ;; 43 | esac 44 | else 45 | if [ -n "$LUA_INC" -o -n "$LUA_LIB" ]; then 46 | # explicit set lua lib path 47 | ngx_feature="lua library in $LUA_LIB and $LUA_INC (specified by the LUA_LIB and LUA_INC env)" 48 | ngx_feature_path="$LUA_INC" 49 | if [ $NGX_RPATH = YES ]; then 50 | ngx_feature_libs="-R$LUA_LIB -L$LUA_LIB -llua -lm" 51 | else 52 | ngx_feature_libs="-L$LUA_LIB -llua -lm" 53 | fi 54 | 55 | . auto/feature 56 | 57 | if [ $ngx_found = no ]; then 58 | cat << END 59 | $0: error: the ngx_lua addon requires the lua or luajit library and LUA_LIB is defined as $LUA_LIB and LUA_INC is $LUA_INC, but we cannot find standard Lua there. 60 | END 61 | exit 1 62 | fi 63 | else 64 | # auto-discovery 65 | ngx_feature="lua library" 66 | ngx_feature_libs="-llua -lm" 67 | . auto/feature 68 | 69 | if [ $ngx_found = no ]; then 70 | # OpenBSD 71 | ngx_feature="lua library in /usr/local/" 72 | ngx_feature_path="/usr/local/include" 73 | if [ $NGX_RPATH = YES ]; then 74 | ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -llua -lm" 75 | else 76 | ngx_feature_libs="-L/usr/local/lib -llua -lm" 77 | fi 78 | . auto/feature 79 | fi 80 | 81 | if [ $ngx_found = no ]; then 82 | # NetBSD 83 | ngx_feature="lua library in /usr/pkg/" 84 | ngx_feature_path="/usr/pkg/include/" 85 | if [ $NGX_RPATH = YES ]; then 86 | ngx_feature_libs="-R/usr/pkg/lib -L/usr/pkg/lib -lm -llua" 87 | else 88 | ngx_feature_libs="-L/usr/pkg/lib -lm -llua" 89 | fi 90 | . auto/feature 91 | fi 92 | 93 | if [ $ngx_found = no ]; then 94 | # MacPorts 95 | ngx_feature="lua library in /opt/local/" 96 | ngx_feature_path="/opt/local/include" 97 | if [ $NGX_RPATH = YES ]; then 98 | ngx_feature_libs="-R/opt/local/lib -L/opt/local/lib -lm -llua" 99 | else 100 | ngx_feature_libs="-L/opt/local/lib -lm -llua" 101 | fi 102 | . auto/feature 103 | fi 104 | 105 | if [ $ngx_found = no ]; then 106 | # FreeBSD 107 | ngx_feature="lua library in /usr/local/../lua51/" 108 | ngx_feature_path="/usr/local/include/lua51" 109 | if [ $NGX_RPATH = YES ]; then 110 | ngx_feature_libs="-R/usr/local/lib/lua51 -L/usr/local/lib/lua51 -llua -lm" 111 | else 112 | ngx_feature_libs="-L/usr/local/lib/lua51 -llua -lm" 113 | fi 114 | . auto/feature 115 | fi 116 | 117 | if [ $ngx_found = no ]; then 118 | # Debian 119 | ngx_feature="lua library in /usr/" 120 | ngx_feature_path="/usr/include/lua5.1" 121 | if [ $NGX_RPATH = YES ]; then 122 | ngx_feature_libs="-R/usr/lib -L/usr/lib -lm -llua5.1" 123 | else 124 | ngx_feature_libs="-L/usr/lib -lm -llua5.1" 125 | fi 126 | . auto/feature 127 | fi 128 | fi 129 | fi 130 | 131 | if [ $ngx_found = yes ]; then 132 | CORE_INCS="$CORE_INCS $ngx_feature_path" 133 | CORE_LIBS="$CORE_LIBS $ngx_feature_libs" 134 | else 135 | cat << END 136 | $0: error: the ngx_lua addon requires the lua library. 137 | END 138 | exit 1 139 | fi 140 | 141 | ngx_addon_name=ngx_http_lua_module 142 | HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES ngx_http_lua_module" 143 | NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/src/ngx_http_lua_module.c $ngx_addon_dir/src/strtok_r.c" 144 | NGX_ADDON_DEPS="$NGX_ADDON_DEPS $ngx_addon_dir/src/strtok_r.h" 145 | CFLAGS="$CFLAGS -DNDK_SET_VAR" 146 | 147 | ngx_feature="export symbols by default" 148 | ngx_feature_libs="-Wl,-E" 149 | ngx_feature_name= 150 | ngx_feature_run=no 151 | ngx_feature_incs="#include " 152 | ngx_feature_path= 153 | ngx_feature_test='printf("hello");' 154 | 155 | . auto/feature 156 | 157 | if [ $ngx_found = yes ]; then 158 | CORE_LIBS="-Wl,-E $CORE_LIBS" 159 | fi 160 | 161 | USE_MD5=YES 162 | 163 | 164 | -------------------------------------------------------------------------------- /example/nginx/boundary.lua: -------------------------------------------------------------------------------- 1 | -- Copyright (C) Alacner Zhang (alacner@gmail.com) 2 | 3 | module('nginx.boundary', package.seeall) 4 | 5 | require ("nginx.kit") 6 | 7 | function get(ct) 8 | if not ct then return false end 9 | local _,_,boundary = string.find (ct, "boundary%=(.-)$") 10 | if not boundary then return false end 11 | return "--"..boundary 12 | end 13 | 14 | -- 15 | -- Create a table containing the headers of a multipart/form-data field 16 | -- 17 | function split(...) 18 | local request_data, boundary = ... 19 | 20 | if not request_data then return false end; 21 | if not boundary then return false end; 22 | 23 | local files, posts = {}, {} 24 | 25 | local post_temp = nginx.kit.split(request_data, boundary) 26 | for i,pd in ipairs(post_temp) do 27 | 28 | local headers = {} 29 | local hdrdata, post_val = string.match(pd, "(.+)\r\n\r\n(.+)\r\n") 30 | --printl(hdrdata) 31 | 32 | if hdrdata then 33 | string.gsub (hdrdata, '([^%c%s:]+):%s+([^\n]+)', function(type,val) 34 | type = string.lower(type) 35 | headers[type] = val 36 | end) 37 | end 38 | 39 | local t = {} 40 | local hcd = headers["content-disposition"] 41 | if hcd then 42 | string.gsub(hcd, ';%s*([^%s=]+)="(.-)"', function(attr, val) 43 | t[attr] = val 44 | end) 45 | -- Filter POST or FILE 46 | if headers["content-type"] then 47 | -- name,type,size,tmp_name,error 48 | local file = {} 49 | file['type'] = headers["content-type"] 50 | file['name'] = t["filename"] 51 | file['data'] = post_val; 52 | file['size'] = string.len(post_val); 53 | 54 | files[t.name] = file 55 | else 56 | posts[t.name] = post_val 57 | end 58 | end 59 | end 60 | 61 | return posts, files 62 | end 63 | -------------------------------------------------------------------------------- /example/nginx/init.lua: -------------------------------------------------------------------------------- 1 | -- Copyright (C) Alacner Zhang (alacner@gmail.com) 2 | 3 | --module('nginx', package.seeall) 4 | 5 | print = ngx.print 6 | 7 | require("nginx.kit") 8 | require("nginx.boundary") 9 | require("nginx.urlcode") 10 | 11 | print_r = nginx.kit.print_r 12 | 13 | local ngx_post_request_data = ngx.post["request_data"] 14 | 15 | ngx.post = nil 16 | 17 | if ngx_post_request_data then 18 | local posts, files = {}, {}; 19 | local boundary = nginx.boundary.get(ngx.header["Content-Type"]) 20 | if boundary then 21 | posts, files = nginx.boundary.split(ngx_post_request_data, boundary) 22 | else 23 | nginx.urlcode.parsequery(ngx_post_request_data, posts) 24 | end 25 | ngx.post, ngx.files, posts, files = posts, files, nil, nil 26 | end 27 | -------------------------------------------------------------------------------- /example/nginx/kit.lua: -------------------------------------------------------------------------------- 1 | -- Copyright (C) Alacner Zhang (alacner@gmail.com) 2 | 3 | module('nginx.kit', package.seeall) 4 | 5 | function print_r(sth) 6 | if type(sth) ~= "table" then 7 | if type(sth) == "nil" then 8 | sth = "nil" 9 | end 10 | print(sth) 11 | return 12 | end 13 | 14 | local space, deep = string.rep(' ', 4), 0 15 | local function _dump(t) 16 | for k,v in pairs(t) do 17 | local key = tostring(k) 18 | 19 | if type(v) == "table" then 20 | deep = deep + 2 21 | print(string.format("%s[%s] => Table\r\n%s(\r\n", 22 | string.rep(space, deep - 1), 23 | key, 24 | string.rep(space, deep) 25 | ) 26 | ) --print. 27 | _dump(v) 28 | 29 | print(string.format("%s)\r\n",string.rep(space, deep))) 30 | deep = deep - 2 31 | else 32 | print(string.format("%s[%s] => %s\r\n", 33 | string.rep(space, deep + 1), 34 | key, 35 | tostring(v) 36 | ) 37 | ) --print. 38 | end 39 | end 40 | end 41 | 42 | print(string.format("Table\r\n(\r\n")) 43 | _dump(sth) 44 | print(string.format(")\r\n")) 45 | end 46 | 47 | 48 | function split(str, pat) 49 | local t = {} -- NOTE: use {n = 0} in Lua-5.0 50 | local fpat = "(.-)" .. pat 51 | local last_end = 1 52 | local s, e, cap = str:find(fpat, 1) 53 | while s do 54 | if s ~= 1 or cap ~= "" then 55 | table.insert(t,cap) 56 | end 57 | last_end = e+1 58 | s, e, cap = str:find(fpat, last_end) 59 | end 60 | if last_end <= #str then 61 | cap = str:sub(last_end) 62 | table.insert(t, cap) 63 | end 64 | return t 65 | end 66 | -------------------------------------------------------------------------------- /example/nginx/lp.lua: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------- 2 | -- Lua Pages Template Preprocessor. 3 | -- 4 | -- @release $Id: lp.lua,v 1.15 2008/12/11 17:40:24 mascarenhas Exp $ 5 | ---------------------------------------------------------------------------- 6 | 7 | local assert, error, getfenv, loadstring, setfenv = assert, error, getfenv, loadstring, setfenv 8 | 9 | ---------------------------------------------------------------------------- 10 | -- function to do output 11 | local outfunc = "ngx.print" 12 | --local outfunc = "print" 13 | --local outfunc = "io.write" 14 | -- accepts the old expression field: `$| |$' 15 | local compatmode = true 16 | 17 | -- 18 | -- Builds a piece of Lua code which outputs the (part of the) given string. 19 | -- @param s String. 20 | -- @param i Number with the initial position in the string. 21 | -- @param f Number with the final position in the string (default == -1). 22 | -- @return String with the correspondent Lua code which outputs the part of the string. 23 | -- 24 | local function out (s, i, f) 25 | s = string.sub(s, i, f or -1) 26 | if s == "" then return s end 27 | -- we could use `%q' here, but this way we have better control 28 | s = string.gsub(s, "([\\\n\'])", "\\%1") 29 | -- substitute '\r' by '\'+'r' and let `loadstring' reconstruct it 30 | s = string.gsub(s, "\r", "\\r") 31 | return string.format(" %s('%s'); ", outfunc, s) 32 | end 33 | 34 | 35 | ---------------------------------------------------------------------------- 36 | -- Translate the template to Lua code. 37 | -- @param s String to translate. 38 | -- @return String with translated code. 39 | ---------------------------------------------------------------------------- 40 | function translate (s) 41 | s = string.gsub(s, "^#![^\n]+\n", "") 42 | if compatmode then 43 | s = string.gsub(s, "$|(.-)|%$", "") 44 | s = string.gsub(s, "", "") 45 | end 46 | s = string.gsub(s, "<%?(.-)%?>", "") 47 | s = string.gsub(s, "<%%(.-)%%>", "") 48 | s = string.gsub(s, "<%?lua lua(.-)%?>", "") 49 | local res = {} 50 | local start = 1 -- start of untranslated part in `s' 51 | while true do 52 | local ip, fp, target, exp, code = string.find(s, "<%?(%w*)[ \t]*(=?)(.-)%?>", start) 53 | if not ip then break end 54 | table.insert(res, out(s, start, ip-1)) 55 | if target ~= "" and target ~= "lua" then 56 | -- not for Lua; pass whole instruction to the output 57 | table.insert(res, out(s, ip, fp)) 58 | else 59 | if exp == "=" then -- expression? 60 | table.insert(res, string.format(" %s(%s);", outfunc, code)) 61 | else -- command 62 | table.insert(res, string.format(" %s ", code)) 63 | end 64 | end 65 | start = fp + 1 66 | end 67 | table.insert(res, out(s, start)) 68 | return table.concat(res) 69 | end 70 | 71 | 72 | ---------------------------------------------------------------------------- 73 | -- Defines the name of the output function. 74 | -- @param f String with the name of the function which produces output. 75 | 76 | function setoutfunc (f) 77 | outfunc = f 78 | end 79 | 80 | ---------------------------------------------------------------------------- 81 | -- Turns on or off the compatibility with old CGILua 3.X behavior. 82 | -- @param c Boolean indicating if the compatibility mode should be used. 83 | 84 | function setcompatmode (c) 85 | compatmode = c 86 | end 87 | 88 | ---------------------------------------------------------------------------- 89 | -- Internal compilation cache. 90 | 91 | local cache = {} 92 | 93 | ---------------------------------------------------------------------------- 94 | -- Translates a template into a Lua function. 95 | -- Does NOT execute the resulting function. 96 | -- Uses a cache of templates. 97 | -- @param string String with the template to be translated. 98 | -- @param chunkname String with the name of the chunk, for debugging purposes. 99 | -- @return Function with the resulting translation. 100 | 101 | function compile (string, chunkname) 102 | local f, err = cache[string] 103 | if f then return f end 104 | f, err = loadstring (translate (string), chunkname) 105 | if not f then error (err, 3) end 106 | cache[string] = f 107 | return f 108 | end 109 | 110 | ---------------------------------------------------------------------------- 111 | -- Translates and executes a template in a given file. 112 | -- The translation creates a Lua function which will be executed in an 113 | -- optionally given environment. 114 | -- @param filename String with the name of the file containing the template. 115 | -- @param env Table with the environment to run the resulting function. 116 | local BOM = string.char(239) .. string.char(187) .. string.char(191) 117 | 118 | function include (filename, env) 119 | -- read the whole contents of the file 120 | local fh = assert (io.open (filename)) 121 | local src = fh:read("*a") 122 | fh:close() 123 | if src:sub(1,3) == BOM then src = src:sub(4) end 124 | -- translates the file into a function 125 | local prog = compile (src, '@'..filename) 126 | local _env 127 | if env then 128 | _env = getfenv (prog) 129 | setfenv (prog, env) 130 | end 131 | prog () 132 | end 133 | -------------------------------------------------------------------------------- /example/nginx/urlcode.lua: -------------------------------------------------------------------------------- 1 | ---------------------------------------------------------------------------- 2 | -- Utility functions for encoding/decoding of URLs. 3 | -- 4 | -- @release $Id: urlcode.lua,v 1.10 2008/01/21 16:11:32 carregal Exp $ 5 | ---------------------------------------------------------------------------- 6 | 7 | module('nginx.urlcode', package.seeall) 8 | 9 | ---------------------------------------------------------------------------- 10 | -- Decode an URL-encoded string (see RFC 2396) 11 | ---------------------------------------------------------------------------- 12 | function unescape (str) 13 | str = string.gsub (str, "+", " ") 14 | str = string.gsub (str, "%%(%x%x)", function(h) return string.char(tonumber(h,16)) end) 15 | str = string.gsub (str, "\r\n", "\n") 16 | return str 17 | end 18 | 19 | ---------------------------------------------------------------------------- 20 | -- URL-encode a string (see RFC 2396) 21 | ---------------------------------------------------------------------------- 22 | function escape (str) 23 | str = string.gsub (str, "\n", "\r\n") 24 | str = string.gsub (str, "([^0-9a-zA-Z ])", -- locale independent 25 | function (c) return string.format ("%%%02X", string.byte(c)) end) 26 | str = string.gsub (str, " ", "+") 27 | return str 28 | end 29 | 30 | ---------------------------------------------------------------------------- 31 | -- Insert a (name=value) pair into table [[args]] 32 | -- @param args Table to receive the result. 33 | -- @param name Key for the table. 34 | -- @param value Value for the key. 35 | -- Multi-valued names will be represented as tables with numerical indexes 36 | -- (in the order they came). 37 | ---------------------------------------------------------------------------- 38 | function insertfield (args, name, value) 39 | if not args[name] then 40 | args[name] = value 41 | else 42 | local t = type (args[name]) 43 | if t == "string" then 44 | args[name] = { 45 | args[name], 46 | value, 47 | } 48 | elseif t == "table" then 49 | table.insert (args[name], value) 50 | else 51 | error ("CGILua fatal error (invalid args table)!") 52 | end 53 | end 54 | end 55 | 56 | ---------------------------------------------------------------------------- 57 | -- Parse url-encoded request data 58 | -- (the query part of the script URL or url-encoded post data) 59 | -- 60 | -- Each decoded (name=value) pair is inserted into table [[args]] 61 | -- @param query String to be parsed. 62 | -- @param args Table where to store the pairs. 63 | ---------------------------------------------------------------------------- 64 | function parsequery (query, args) 65 | if type(query) == "string" then 66 | local insertfield, unescape = insertfield, unescape 67 | string.gsub (query, "([^&=]+)=([^&=]*)&?", 68 | function (key, val) 69 | insertfield (args, unescape(key), unescape(val)) 70 | end) 71 | end 72 | end 73 | 74 | ---------------------------------------------------------------------------- 75 | -- URL-encode the elements of a table creating a string to be used in a 76 | -- URL for passing data/parameters to another script 77 | -- @param args Table where to extract the pairs (name=value). 78 | -- @return String with the resulting encoding. 79 | ---------------------------------------------------------------------------- 80 | function encodetable (args) 81 | if args == nil or next(args) == nil then -- no args or empty args? 82 | return "" 83 | end 84 | local strp = "" 85 | for key, vals in pairs(args) do 86 | if type(vals) ~= "table" then 87 | vals = {vals} 88 | end 89 | for i,val in ipairs(vals) do 90 | strp = strp.."&"..escape(key).."="..escape(val) 91 | end 92 | end 93 | -- remove first & 94 | return string.sub(strp,2) 95 | end 96 | -------------------------------------------------------------------------------- /example/t1.lua: -------------------------------------------------------------------------------- 1 | -- Copyright (C) Alacner Zhang (alacner@gmail.com) 2 | 3 | require("nginx") 4 | 5 | print_r(ngx) 6 | ngx.eof() 7 | do return end 8 | 9 | require "lp" 10 | 11 | do return end 12 | 13 | 14 | 15 | 16 | --ngx.set_header('Content-Type', "image/png"); 17 | ngx.set_header('Content-Type', "text/html"); 18 | 19 | --local f = io.open('/root/repos/nginx_lua_module/example/t1.lua', 'rb') 20 | --local f = io.open('/root/test.jpg', 'rb') 21 | --local t = f:read("*a") 22 | --ngx.print(t) 23 | 24 | local f = io.open('/root/480x480.png', 'rb') 25 | --local t = f:read("*a") 26 | --log(a) 27 | --local t = f:read(8192) 28 | --ngx.print(t) 29 | --print_r(ngx) 30 | --ngx.flush() 31 | --ngx.print(t) 32 | --print_r(ngx) 33 | --ngx.flush() 34 | --ngx.print(t) 35 | --print_r(ngx) 36 | --local f = io.open('/root/test.jpg', 'rb') 37 | --local f = assert(io.open(arg[1], "rb")) 38 | f:close() 39 | --ngx.print(ngx.set_cookie) 40 | local t = os.time() 41 | ngx.set_cookie('love1', "me") -- name, value, expire, path, domain, secure 42 | --ngx.set_cookie('love2', "me", 100) -- name, value, expire, path, domain, secure 43 | --ngx.set_cookie('love3', '123456') -- name, value, expire, path, domain, secure 44 | --ngx.set_cookie('isopen', 'true', 1000, '/', '192.168.137.126') -- name, value, expire, path, domain, secure 45 | ngx.set_header('X-Memc-Flags', "11111111111111"); 46 | ngx.set_header('X-Memc-Flags', "2222222222222222222222222"); 47 | ngx.set_header('X-Memc-Flags', "f1111122222222333333334444445"); 48 | print_r(ngx) 49 | ngx.eof() 50 | do return end 51 | 52 | local http = require("socket.http") 53 | local r, e, h, l = http.request("http://www.6uu.com") 54 | print_r(h) 55 | print_r(l) 56 | print_r(m) 57 | ngx.eof() 58 | 59 | do return end 60 | 61 | 62 | local socket = require("socket") 63 | local tcp = socket.tcp() 64 | tcp:settimeout(1) 65 | local n,e,h = tcp:connect("www.google.com","80") 66 | print_r(n) 67 | --print_r(e) 68 | print_r(h) 69 | ngx.eof() 70 | 71 | do return end 72 | 73 | 74 | TIMEOUT = 1; 75 | local http = require("socket.http") 76 | local r, e, h = http.request("http://www.6uu.com") 77 | print_r(h) 78 | do return end 79 | --ngx.set_header('X-Memc-Flags', "f1111122222222333333334444445"); 80 | --ngx.set_header("Set-Cookie", 'love=xxx;'); 81 | ngx.print('exit?') 82 | 83 | --ngx.print(table.concat(p)) 84 | --[[ 85 | ]] 86 | ngx.print('hhhhhhhhhhh') 87 | ngx.print('
') 88 | ngx.print(ngx.random) 89 | ngx.print('
') 90 | ngx.print(ngx.server.QUERY_STRING) 91 | print(os.time()) 92 | local Flexihash = require "Flexihash" 93 | local flexihash = Flexihash.New() 94 | flexihash:addTarget('10.249.196.117|11211|0') 95 | flexihash:addTarget('10.249.196.118|11211|0') 96 | flexihash:addTarget('10.249.196.119|11211|0') 97 | flexihash:addTarget('10.249.196.120|11211|0') 98 | flexihash:addTarget('10.249.196.121|11211|0') 99 | flexihash:addTarget('10.249.196.122|11211|0') 100 | flexihash:addTarget('10.249.196.123|11211|0') 101 | flexihash:addTarget('10.249.196.123|11211|0') 102 | flexihash:addTarget('10.249.196.124|11211|0') 103 | print_r(flexihash:getAllTargets()) 104 | local memcache_key = os.time(); 105 | local config = flexihash:lookup(memcache_key) 106 | ngx.set_header('X-Memc-Flags', config); 107 | print(memcache_key, ' => ', config) 108 | print("\r\n memcached\r\n") 109 | 110 | --[=====[ 111 | require "Memcached" 112 | --local memc = Memcached.New('127.0.0.1', 11211) 113 | --memc:set('1234', 1234) 114 | --print(memc:get(1234)) 115 | --]=====] 116 | 117 | local socket = require("socket") 118 | local sc = socket.connect('127.0.0.1', 11211) 119 | sc:settimeout(1) 120 | --local sc = socket.connect('10.249.196.117', 11211) 121 | sc:send("get " .. config .. "\r\n") 122 | local answer = sc:receive() 123 | print(answer) 124 | 125 | print_r(ngx) 126 | print"------ end -----" 127 | -------------------------------------------------------------------------------- /example/t2.lua: -------------------------------------------------------------------------------- 1 | --Copyright (c) 2011-2015 Zhihua Zhang (alacner@gmail.com) 2 | ngx.set_header('Content-Type', "text/html"); 3 | local print = ngx.print 4 | print(os.time()) 5 | require "lp" 6 | include('test.lp') 7 | ngx.eof() 8 | -------------------------------------------------------------------------------- /example/t3.lua: -------------------------------------------------------------------------------- 1 | --Copyright (c) 2011-2015 Zhihua Zhang (alacner@gmail.com) 2 | --ngx.set_header('Location', "http://www.google.com"); 3 | --ngx.set_cookie('love', '123456') -- name, value, expire, path, domain, secure 4 | --ngx.set_cookie('aa', 'ssssss') -- name, value, expire, path, domain, secure 5 | print = ngx.print 6 | local kit = require("kit") 7 | local print_r = kit.print_r 8 | 9 | --ngx.set_header('Content-Type', "image/png"); 10 | ngx.set_header('Content-Type', "text/html"); 11 | 12 | --local f = io.open('/root/repos/nginx_lua_module/example/t1.lua', 'rb') 13 | --local f = io.open('/root/test.jpg', 'rb') 14 | --local t = f:read("*a") 15 | --ngx.print(t) 16 | 17 | local f = io.open('/root/480x480.png', 'rb') 18 | --local t = f:read("*a") 19 | --log(a) 20 | --local t = f:read(8192) 21 | --ngx.print(t) 22 | --print_r(ngx) 23 | --ngx.flush() 24 | --ngx.print(t) 25 | --print_r(ngx) 26 | --ngx.flush() 27 | --ngx.print(t) 28 | --print_r(ngx) 29 | --local f = io.open('/root/test.jpg', 'rb') 30 | --local f = assert(io.open(arg[1], "rb")) 31 | f:close() 32 | --ngx.print(ngx.set_cookie) 33 | local t = os.time() 34 | ngx.set_cookie('love1', "me") -- name, value, expire, path, domain, secure 35 | --ngx.set_cookie('love2', "me", 100) -- name, value, expire, path, domain, secure 36 | --ngx.set_cookie('love3', '123456') -- name, value, expire, path, domain, secure 37 | --ngx.set_cookie('isopen', 'true', 1000, '/', '192.168.137.126') -- name, value, expire, path, domain, secure 38 | ngx.set_header('X-Memc-Flags', "11111111111111"); 39 | ngx.set_header('X-Memc-Flags', "2222222222222222222222222"); 40 | ngx.set_header('X-Memc-Flags', "f1111122222222333333334444445"); 41 | print_r(ngx) 42 | ngx.eof() 43 | do return end 44 | 45 | local http = require("socket.http") 46 | local r, e, h, l = http.request("http://www.6uu.com") 47 | print_r(h) 48 | print_r(l) 49 | print_r(m) 50 | ngx.eof() 51 | 52 | do return end 53 | 54 | 55 | local socket = require("socket") 56 | local tcp = socket.tcp() 57 | tcp:settimeout(1) 58 | local n,e,h = tcp:connect("www.google.com","80") 59 | print_r(n) 60 | --print_r(e) 61 | print_r(h) 62 | ngx.eof() 63 | 64 | do return end 65 | 66 | 67 | TIMEOUT = 1; 68 | local http = require("socket.http") 69 | local r, e, h = http.request("http://www.6uu.com") 70 | print_r(h) 71 | do return end 72 | --ngx.set_header('X-Memc-Flags', "f1111122222222333333334444445"); 73 | --ngx.set_header("Set-Cookie", 'love=xxx;'); 74 | ngx.print('exit?') 75 | 76 | --ngx.print(table.concat(p)) 77 | --[[ 78 | ]] 79 | ngx.print('hhhhhhhhhhh') 80 | ngx.print('
') 81 | ngx.print(ngx.random) 82 | ngx.print('
') 83 | ngx.print(ngx.server.QUERY_STRING) 84 | print(os.time()) 85 | local Flexihash = require "Flexihash" 86 | local flexihash = Flexihash.New() 87 | flexihash:addTarget('10.249.196.117|11211|0') 88 | flexihash:addTarget('10.249.196.118|11211|0') 89 | flexihash:addTarget('10.249.196.119|11211|0') 90 | flexihash:addTarget('10.249.196.120|11211|0') 91 | flexihash:addTarget('10.249.196.121|11211|0') 92 | flexihash:addTarget('10.249.196.122|11211|0') 93 | flexihash:addTarget('10.249.196.123|11211|0') 94 | flexihash:addTarget('10.249.196.123|11211|0') 95 | flexihash:addTarget('10.249.196.124|11211|0') 96 | print_r(flexihash:getAllTargets()) 97 | local memcache_key = os.time(); 98 | local config = flexihash:lookup(memcache_key) 99 | ngx.set_header('X-Memc-Flags', config); 100 | print(memcache_key, ' => ', config) 101 | print("\r\n memcached\r\n") 102 | 103 | --[=====[ 104 | require "Memcached" 105 | --local memc = Memcached.New('127.0.0.1', 11211) 106 | --memc:set('1234', 1234) 107 | --print(memc:get(1234)) 108 | --]=====] 109 | 110 | local socket = require("socket") 111 | local sc = socket.connect('127.0.0.1', 11211) 112 | sc:settimeout(1) 113 | --local sc = socket.connect('10.249.196.117', 11211) 114 | sc:send("get " .. config .. "\r\n") 115 | local answer = sc:receive() 116 | print(answer) 117 | 118 | print_r(ngx) 119 | print"------ end -----" 120 | -------------------------------------------------------------------------------- /example/test.lp: -------------------------------------------------------------------------------- 1 | =================
") 3 | ?> 4 | 5 | 6 | Login 7 | 8 | 9 | 10 | 13 |
14 | 15 | 16 |

User logged in

17 | Logout 18 | 19 |

20 |
21 | User name:
22 | Password:
23 | file1:
24 | file2:
25 |
26 | 27 | 28 |
29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/ngx_http_lua_module.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Alacner Zhang (alacner@gmail.com) 4 | */ 5 | 6 | 7 | #include "strtok_r.h" 8 | #define lua_strtok_r(a, b, c) strtok_r((a), (b), (c)) 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "lua.h" 16 | #include "lauxlib.h" 17 | #include "lualib.h" 18 | 19 | #define safe_emalloc(nmemb, size, offset) malloc((nmemb) * (size) + (offset)) 20 | 21 | 22 | typedef struct { 23 | lua_State *lua; /* lua state handle */ 24 | } ngx_http_lua_main_conf_t; 25 | 26 | typedef struct { 27 | ngx_http_complex_value_t file_src; 28 | } ngx_http_lua_loc_conf_t; 29 | 30 | typedef struct { 31 | ngx_chain_t *out; /* buffered response body chains */ 32 | unsigned eof:1; /* last_buf has been sent ? */ 33 | } ngx_http_lua_ctx_t; 34 | 35 | extern ngx_module_t ngx_http_lua_module; 36 | static ngx_http_output_header_filter_pt ngx_http_next_header_filter; 37 | static ngx_http_output_body_filter_pt ngx_http_next_body_filter; 38 | 39 | #define LUA_NGX_REQUEST "_ngx.request" /* nginx request pointer */ 40 | #define LUA_NGX_OUT_BUFFER "_ngx.out_buffer" /* nginx request pointer */ 41 | 42 | 43 | static ngx_int_t ngx_http_lua_init(ngx_conf_t *cf); 44 | static void * ngx_http_lua_create_main_conf(ngx_conf_t *cf); 45 | static char * ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf); 46 | static void * ngx_http_lua_create_loc_conf(ngx_conf_t *cf); 47 | 48 | static ngx_int_t ngx_http_lua_init_worker(ngx_cycle_t *cycle); 49 | static void ngx_http_lua_exit(ngx_cycle_t *cycle); 50 | 51 | static ngx_int_t ngx_http_lua_send_chain_link(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, ngx_chain_t *in); 52 | static ngx_int_t ngx_http_lua_header_filter(ngx_http_request_t *r); 53 | static ngx_int_t ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in); 54 | 55 | static ngx_int_t ngx_set_http_out_header(ngx_http_request_t *r, char *key, char *value); 56 | 57 | static lua_State* ngx_http_lua_create_interpreter(ngx_conf_t *cf, ngx_http_lua_main_conf_t *lmcf); 58 | static char * ngx_http_lua_init_interpreter(ngx_conf_t *cf, ngx_http_lua_main_conf_t *lmcf); 59 | 60 | static char *ngx_http_lua_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); 61 | static ngx_int_t ngx_http_lua_file_handler(ngx_http_request_t *r); 62 | static void ngx_http_lua_file_request_handler(ngx_http_request_t *r); 63 | 64 | static u_char * ngx_http_lua_script_filename(ngx_pool_t *pool, u_char *src, size_t len); 65 | 66 | static int luaC_ngx_print(lua_State *L); 67 | static int luaF_ngx_print (lua_State *L); 68 | static int luaF_ngx_set_header (lua_State *L); 69 | static int luaF_ngx_set_cookie (lua_State *L); 70 | static int luaF_ngx_flush(lua_State *L); 71 | static int luaF_ngx_eof(lua_State *L); 72 | static int luaM_ngx_get_header (lua_State *L); 73 | static int luaM_ngx_get (lua_State *L); 74 | static int luaM_ngx_post (lua_State *L); 75 | static int luaM_ngx_get_cookie (lua_State *L); 76 | 77 | 78 | static ngx_command_t ngx_http_lua_commands[] = { 79 | { 80 | ngx_string("lua_file"), 81 | NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 82 | ngx_http_lua_file, 83 | NGX_HTTP_LOC_CONF_OFFSET, 84 | offsetof(ngx_http_lua_loc_conf_t, file_src), 85 | NULL 86 | }, 87 | 88 | ngx_null_command 89 | }; 90 | 91 | 92 | static ngx_http_module_t ngx_http_lua_module_ctx = { 93 | NULL, /* preconfiguration */ 94 | ngx_http_lua_init, /* postconfiguration */ 95 | 96 | ngx_http_lua_create_main_conf, /* create main configuration */ 97 | ngx_http_lua_init_main_conf, /* init main configuration */ 98 | 99 | NULL, /* create server configuration */ 100 | NULL, /* merge server configuration */ 101 | 102 | ngx_http_lua_create_loc_conf, /* create location configuration */ 103 | NULL /* merge location configuration */ 104 | }; 105 | 106 | 107 | ngx_module_t ngx_http_lua_module = { 108 | NGX_MODULE_V1, 109 | &ngx_http_lua_module_ctx, /* module context */ 110 | ngx_http_lua_commands, /* module directives */ 111 | NGX_HTTP_MODULE, /* module type */ 112 | NULL, /* init master */ 113 | NULL, /* init module */ 114 | ngx_http_lua_init_worker, /* init process */ 115 | NULL, /* init thread */ 116 | NULL, /* exit thread */ 117 | ngx_http_lua_exit, /* exit process */ 118 | NULL, /* exit master */ 119 | NGX_MODULE_V1_PADDING 120 | }; 121 | 122 | 123 | static ngx_int_t 124 | ngx_http_lua_send_chain_link(ngx_http_request_t *r, ngx_http_lua_ctx_t *ctx, 125 | ngx_chain_t *in) 126 | { 127 | ngx_int_t rc; 128 | ngx_chain_t *cl; 129 | ngx_chain_t **ll; 130 | 131 | if (ctx->eof) { 132 | ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, 133 | "ctx->eof already set"); 134 | return NGX_OK; 135 | } 136 | 137 | if (in == NULL) { 138 | ctx->eof = 1; 139 | 140 | ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, 141 | "send special buf"); 142 | if (r->headers_out.status == 0) { 143 | r->headers_out.status = NGX_HTTP_OK; 144 | } 145 | 146 | ngx_http_send_header(r); 147 | 148 | if (ctx->out) { 149 | rc = ngx_http_output_filter(r, ctx->out); 150 | 151 | if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { 152 | return rc; 153 | } 154 | 155 | ctx->out = NULL; 156 | } 157 | 158 | rc = ngx_http_send_special(r, NGX_HTTP_LAST); 159 | if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { 160 | return rc; 161 | } 162 | 163 | return NGX_OK; 164 | } 165 | 166 | /* buffer all the output bufs */ 167 | for (cl = ctx->out, ll = &ctx->out; cl; cl = cl->next) { 168 | ll = &cl->next; 169 | } 170 | 171 | *ll = in; 172 | 173 | return NGX_OK; 174 | } 175 | 176 | 177 | static int 178 | luaF_ngx_print(lua_State *L) 179 | { 180 | ngx_http_request_t *r; 181 | ngx_http_lua_ctx_t *ctx; 182 | const char *p; 183 | size_t len; 184 | size_t size; 185 | ngx_buf_t *b; 186 | ngx_chain_t *cl; 187 | ngx_int_t rc; 188 | int i; 189 | int nargs; 190 | 191 | lua_getglobal(L, LUA_NGX_REQUEST); 192 | r = lua_touserdata(L, -1); 193 | lua_pop(L, 1); 194 | 195 | if (r == NULL) { 196 | return luaL_error(L, "no request object found"); 197 | } 198 | 199 | ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); 200 | 201 | if (ctx == NULL) { 202 | return luaL_error(L, "no request ctx found"); 203 | } 204 | 205 | if (ctx->eof) { 206 | return luaL_error(L, "seen eof already"); 207 | } 208 | 209 | nargs = lua_gettop(L); 210 | size = 0; 211 | 212 | for (i = 1; i <= nargs; i++) { 213 | luaL_checkstring(L, i); 214 | lua_tolstring(L, i, &len); 215 | size += len; 216 | } 217 | 218 | if (size == 0) { 219 | /* do nothing for empty strings */ 220 | return 0; 221 | } 222 | 223 | b = ngx_create_temp_buf(r->pool, size); 224 | if (b == NULL) { 225 | return luaL_error(L, "out of memory"); 226 | } 227 | 228 | for (i = 1; i <= nargs; i++) { 229 | p = lua_tolstring(L, i, &len); 230 | b->last = ngx_copy(b->last, (u_char *) p, len); 231 | } 232 | 233 | cl = ngx_alloc_chain_link(r->pool); 234 | if (cl == NULL) { 235 | return luaL_error(L, "out of memory"); 236 | } 237 | 238 | cl->next = NULL; 239 | cl->buf = b; 240 | 241 | rc = ngx_http_lua_send_chain_link(r, ctx, cl); 242 | 243 | if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { 244 | return luaL_error(L, "failed to send data through the output filters"); 245 | } 246 | 247 | return 0; 248 | } 249 | 250 | 251 | static int 252 | luaF_ngx_set_header (lua_State *L) 253 | { 254 | const char *key = luaL_optstring(L, 1, NULL); 255 | const char *value = luaL_optstring(L, 2, NULL); 256 | 257 | ngx_http_request_t *r; 258 | 259 | lua_getglobal(L, LUA_NGX_REQUEST); 260 | r = lua_touserdata(L, -1); 261 | lua_pop(L, 1); 262 | 263 | if (r == NULL) { 264 | return luaL_error(L, "no request object found"); 265 | } 266 | 267 | if (ngx_set_http_out_header(r, (char *)key, (char *)value) == NGX_OK) { 268 | lua_pushboolean(L, 1); 269 | } else { 270 | lua_pushboolean(L, 0); 271 | } 272 | 273 | return 1; 274 | } 275 | 276 | 277 | static int 278 | luaM_ngx_get_cookie (lua_State *L) 279 | { 280 | ngx_http_request_t *r; 281 | 282 | lua_getglobal(L, LUA_NGX_REQUEST); 283 | r = lua_touserdata(L, -1); 284 | lua_pop(L, 1); 285 | 286 | if (r == NULL) { 287 | return luaL_error(L, "no request object found"); 288 | } 289 | 290 | lua_newtable(L); 291 | 292 | ngx_int_t i, n; 293 | ngx_table_elt_t **cookies; 294 | u_char *p, *cookie; 295 | ssize_t size; 296 | 297 | n = r->headers_in.cookies.nelts; 298 | if (n == 0) { 299 | return 1; 300 | } 301 | 302 | cookies = r->headers_in.cookies.elts; 303 | 304 | char *strtok_buf, *variable, *k, *v; 305 | 306 | if (n == 1) { 307 | variable = lua_strtok_r((char *)(*cookies)->value.data, ";", &strtok_buf); 308 | 309 | while (variable) { 310 | k = lua_strtok_r(variable, "=", &v); 311 | lua_pushstring(L, v); 312 | lua_setfield(L, -2, k); 313 | variable = lua_strtok_r(NULL, ";", &strtok_buf); 314 | } 315 | return 1; 316 | } 317 | 318 | size = - (ssize_t) (sizeof("; ") - 1); 319 | 320 | for (i = 0; i < n; i++) { 321 | size += cookies[i]->value.len + sizeof("; ") - 1; 322 | } 323 | 324 | cookie = ngx_pnalloc(r->pool, size); 325 | if (cookie == NULL) { 326 | return 1; 327 | } 328 | 329 | p = cookie; 330 | 331 | for (i = 0; /* void */ ; i++) { 332 | p = ngx_copy(p, cookies[i]->value.data, cookies[i]->value.len); 333 | 334 | if (i == n - 1) { 335 | break; 336 | } 337 | 338 | *p++ = ';'; *p++ = ' '; 339 | } 340 | 341 | variable = lua_strtok_r((char *)cookie, ";", &strtok_buf); 342 | 343 | while (variable) { 344 | k = lua_strtok_r(variable, "=", &v); 345 | lua_pushstring(L, v); 346 | lua_setfield(L, -2, k); 347 | variable = lua_strtok_r(NULL, ";", &strtok_buf); 348 | } 349 | 350 | return 1; 351 | } 352 | 353 | 354 | static int 355 | luaM_ngx_get_header (lua_State *L) 356 | { 357 | ngx_http_request_t *r; 358 | 359 | lua_getglobal(L, LUA_NGX_REQUEST); 360 | r = lua_touserdata(L, -1); 361 | lua_pop(L, 1); 362 | 363 | if (r == NULL) { 364 | return luaL_error(L, "no request object found"); 365 | } 366 | 367 | lua_newtable(L); 368 | 369 | ngx_list_part_t *part; 370 | ngx_table_elt_t *header; 371 | ngx_uint_t i; 372 | 373 | part = &r->headers_in.headers.part; 374 | header = part->elts; 375 | 376 | for (i = 0; /* void */ ; i++) { 377 | 378 | if (i >= part->nelts) { 379 | if (part->next == NULL) { 380 | break; 381 | } 382 | 383 | part = part->next; 384 | header = part->elts; 385 | i = 0; 386 | } 387 | 388 | lua_pushlstring(L, (const char *)header[i].value.data, header[i].value.len); 389 | lua_setfield(L, -2, (const char *)header[i].key.data); 390 | } 391 | 392 | return 1; 393 | } 394 | 395 | 396 | static int 397 | luaM_ngx_get (lua_State *L) 398 | { 399 | ngx_http_request_t *r; 400 | 401 | lua_getglobal(L, LUA_NGX_REQUEST); 402 | r = lua_touserdata(L, -1); 403 | lua_pop(L, 1); 404 | 405 | if (r == NULL) { 406 | return luaL_error(L, "no request object found"); 407 | } 408 | 409 | lua_newtable(L); 410 | 411 | u_char *variables; 412 | variables = ngx_pnalloc(r->pool, r->args.len+1); 413 | ngx_cpystrn(variables, r->args.data, r->args.len+1); 414 | 415 | char *strtok_buf, *variable, *k, *v; 416 | variable = lua_strtok_r((char *)variables, "&", &strtok_buf); 417 | 418 | while (variable) { 419 | k = lua_strtok_r(variable, "=", &v); 420 | lua_pushstring(L, v); 421 | lua_setfield(L, -2, k); 422 | variable = lua_strtok_r(NULL, "&", &strtok_buf); 423 | } 424 | 425 | return 1; 426 | } 427 | 428 | 429 | static int 430 | luaM_ngx_post (lua_State *L) 431 | { 432 | ngx_http_request_t *r; 433 | ngx_file_t file; 434 | size_t size; 435 | u_char *body; 436 | ssize_t n; 437 | 438 | lua_getglobal(L, LUA_NGX_REQUEST); 439 | r = lua_touserdata(L, -1); 440 | lua_pop(L, 1); 441 | 442 | if (r == NULL) { 443 | return luaL_error(L, "no request object found"); 444 | } 445 | 446 | lua_newtable(L); 447 | 448 | if (r->request_body == NULL || r->request_body->temp_file == NULL) { 449 | return 1; 450 | } 451 | 452 | file = r->request_body->temp_file->file; 453 | 454 | if (ngx_file_info(file.name.data, &file.info) == NGX_FILE_ERROR) { 455 | return luaL_error(L, "ngx_file_info failed"); 456 | } 457 | 458 | size = (size_t) ngx_file_size(&file.info); 459 | 460 | body = ngx_pcalloc(r->pool, size); 461 | if (body == NULL) { 462 | return luaL_error(L, "palloc body out of memory"); 463 | } 464 | 465 | n = ngx_read_file(&file, body, size, 0); 466 | 467 | if (n == NGX_ERROR) { 468 | ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, 469 | ngx_read_file_n " \"%s\" failed", file.name.data); 470 | return luaL_error(L, "readfile failed"); 471 | } 472 | 473 | lua_pushlstring(L, (const char *)body, size); 474 | lua_setfield(L, -2, "_request_data_"); 475 | 476 | return 1; 477 | } 478 | 479 | 480 | static int 481 | luaF_ngx_set_cookie (lua_State *L) 482 | { 483 | ngx_http_request_t *r; 484 | ngx_table_elt_t *set_cookie; 485 | 486 | lua_getglobal(L, LUA_NGX_REQUEST); 487 | r = lua_touserdata(L, -1); 488 | lua_pop(L, 1); 489 | 490 | 491 | set_cookie = ngx_list_push(&r->headers_out.headers); 492 | if (set_cookie == NULL) { 493 | return luaL_error(L, "out of memory"); 494 | } 495 | 496 | 497 | //Set-Cookie: _ca=heheheh; expires=Thu, 01-Jan-1970 00:04:10 GMT; path=/; domain=domain; secure 498 | size_t name_len = 0, value_len = 0, path_len = 0, domain_len = 0; 499 | 500 | const char *name = luaL_optlstring(L, 1, NULL, &name_len); 501 | const char *value = luaL_optlstring(L, 2, NULL, &value_len); 502 | int expire = luaL_optnumber(L, 3, 0); 503 | const char *path = luaL_optlstring(L, 4, NULL, &path_len); 504 | const char *domain = luaL_optlstring(L, 5, NULL, &domain_len); 505 | int secure = lua_toboolean(L, 6); 506 | int http_only = lua_toboolean(L, 7); 507 | 508 | int cnt = 0; 509 | lua_pushfstring(L, "%s=%s", name, value); 510 | cnt++; 511 | 512 | if (expire) { 513 | u_char *p; 514 | static u_char expires[] = "; expires=Thu, 31-Dec-37 23:55:55 GMT"; 515 | 516 | p = ngx_pnalloc(r->pool, sizeof(expires) - 1); 517 | p = ngx_cpymem(p, expires, sizeof("; expires=") - 1); 518 | 519 | ngx_http_cookie_time(p, ngx_time() + expire); 520 | lua_pushfstring(L, "; expires=%s", p); 521 | cnt++; 522 | } 523 | 524 | if (path != NULL) { 525 | lua_pushfstring(L, "; path=%s", path); 526 | cnt++; 527 | } 528 | 529 | if (domain != NULL) { 530 | lua_pushfstring(L, "; domain=%s", domain); 531 | cnt++; 532 | } 533 | 534 | if (secure) { 535 | lua_pushfstring(L, "; secure"); 536 | cnt++; 537 | } 538 | 539 | if (http_only) { 540 | lua_pushfstring(L, "; HttpOnly"); 541 | cnt++; 542 | } 543 | 544 | lua_concat(L, cnt); 545 | 546 | size_t len = 0; 547 | const char * cookie = lua_tolstring(L, -1, &len); 548 | 549 | lua_pop(L, 1); 550 | 551 | set_cookie->hash = 1; 552 | ngx_str_set(&set_cookie->key, "Set-Cookie"); 553 | set_cookie->value.len = len; 554 | set_cookie->value.data = (u_char *) cookie; 555 | 556 | ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, 557 | "set cookie: \"%V\"", &set_cookie->value); 558 | 559 | lua_pushboolean(L, 1); 560 | return 1; 561 | } 562 | 563 | 564 | static int 565 | luaC_ngx_print(lua_State *L) 566 | { 567 | ngx_http_request_t *r; 568 | 569 | lua_getglobal(L, LUA_NGX_REQUEST); 570 | r = lua_touserdata(L, -1); 571 | lua_pop(L, 1); 572 | 573 | if (r && r->connection && r->connection->log) { 574 | ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, 575 | "lua print: %s", luaL_optstring(L, -1, "(null)")); 576 | } 577 | return 0; 578 | } 579 | 580 | 581 | static void * 582 | ngx_http_lua_create_main_conf(ngx_conf_t *cf) 583 | { 584 | ngx_http_lua_main_conf_t *lmcf; 585 | 586 | lmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_lua_main_conf_t)); 587 | if (lmcf == NULL) { 588 | return NULL; 589 | } 590 | 591 | return lmcf; 592 | } 593 | 594 | 595 | static char * 596 | ngx_http_lua_init_main_conf(ngx_conf_t *cf, void *conf) 597 | { 598 | ngx_http_lua_main_conf_t *lmcf = conf; 599 | 600 | if (lmcf->lua == NULL) { 601 | if (ngx_http_lua_init_interpreter(cf, lmcf) != NGX_CONF_OK) { 602 | return NGX_CONF_ERROR; 603 | } 604 | } 605 | 606 | return NGX_CONF_OK; 607 | } 608 | 609 | 610 | static void * 611 | ngx_http_lua_create_loc_conf(ngx_conf_t *cf) 612 | { 613 | ngx_http_lua_loc_conf_t *conf; 614 | conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_lua_loc_conf_t)); 615 | if (conf == NULL) { 616 | return NGX_CONF_ERROR; 617 | } 618 | return conf; 619 | } 620 | 621 | 622 | static ngx_int_t ngx_set_http_out_header(ngx_http_request_t *r, char *key, char *value) 623 | { 624 | int len; 625 | 626 | if (strcasecmp("Content-Type", key) == 0) { /* if key: content-type */ 627 | len = ngx_strlen(value); 628 | r->headers_out.content_type_len = len; 629 | r->headers_out.content_type.len = len; 630 | r->headers_out.content_type.data = (u_char *)value; 631 | r->headers_out.content_type_lowcase = NULL; 632 | return NGX_OK; 633 | } 634 | 635 | ngx_table_elt_t *head_type; 636 | head_type = (ngx_table_elt_t *)ngx_list_push(&r->headers_out.headers); 637 | if (head_type != NULL) { 638 | head_type->hash = 1; 639 | head_type->key.len = ngx_strlen(key); 640 | head_type->key.data = (u_char *)key; 641 | head_type->value.len = ngx_strlen(value); 642 | head_type->value.data = (u_char *)value; 643 | 644 | ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, 645 | "set out header: %s: %s", key, value); 646 | } 647 | 648 | return NGX_OK; 649 | } 650 | 651 | 652 | static ngx_int_t 653 | ngx_http_lua_file_handler(ngx_http_request_t *r) 654 | { 655 | ngx_int_t rc; 656 | 657 | if (r->method == NGX_HTTP_POST) { 658 | 659 | r->request_body_in_file_only = 1; 660 | r->request_body_in_persistent_file = 1; 661 | r->request_body_in_clean_file = 1; 662 | r->request_body_file_group_access = 1; 663 | r->request_body_file_log_level = 0; 664 | 665 | ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "post:%V", &r->uri); 666 | rc = ngx_http_read_client_request_body(r, ngx_http_lua_file_request_handler); 667 | 668 | if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { 669 | return rc; 670 | } 671 | 672 | return NGX_DONE; 673 | } 674 | 675 | ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "get:%V", &r->uri); 676 | 677 | ngx_http_lua_file_request_handler(r); 678 | return NGX_OK; 679 | } 680 | 681 | static void 682 | ngx_http_lua_file_request_handler(ngx_http_request_t *r) 683 | { 684 | lua_State *L; 685 | ngx_http_lua_ctx_t *ctx; 686 | ngx_http_lua_main_conf_t *lmcf; 687 | ngx_http_lua_loc_conf_t *llcf; 688 | ngx_str_t file_src; 689 | u_char *script_filename; 690 | 691 | llcf = ngx_http_get_module_loc_conf(r, ngx_http_lua_module); 692 | 693 | if (ngx_http_complex_value(r, &llcf->file_src, &file_src) != NGX_OK) { 694 | ngx_http_finalize_request(r, NGX_ERROR); 695 | return; 696 | } 697 | script_filename = ngx_http_lua_script_filename(r->pool, file_src.data, file_src.len); 698 | 699 | if (script_filename == NULL) { 700 | ngx_http_finalize_request(r, NGX_ERROR); 701 | return; 702 | } 703 | 704 | ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); 705 | 706 | if (ctx == NULL) { 707 | ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_lua_ctx_t)); 708 | if (ctx == NULL) { 709 | ngx_http_finalize_request(r, NGX_ERROR); 710 | return; 711 | } 712 | 713 | ngx_http_set_ctx(r, ctx, ngx_http_lua_module); 714 | } 715 | 716 | lmcf = ngx_http_get_module_main_conf(r, ngx_http_lua_module); 717 | L = lmcf->lua; 718 | 719 | ngx_set_http_out_header(r, "X-Powered-By", LUA_RELEASE); 720 | 721 | /* push ngx_http_request_t to lua */ 722 | lua_pushlightuserdata(L, r); 723 | lua_setglobal(L, LUA_NGX_REQUEST); 724 | 725 | ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "lua_newtable()"); 726 | 727 | lua_newtable(L); /* ngx */ 728 | 729 | lua_pushnumber(L, ngx_random()); 730 | lua_setfield(L, -2, "random"); 731 | 732 | lua_pushcfunction(L, luaF_ngx_print); 733 | lua_setfield(L, -2, "print"); 734 | 735 | lua_pushcfunction(L, luaF_ngx_set_header); 736 | lua_setfield(L, -2, "set_header"); 737 | 738 | lua_pushcfunction(L, luaF_ngx_flush); 739 | lua_setfield(L, -2, "flush"); 740 | 741 | lua_pushcfunction(L, luaF_ngx_eof); 742 | lua_setfield(L, -2, "eof"); 743 | 744 | luaM_ngx_get_cookie(L); 745 | lua_setfield(L, -2, "cookie"); 746 | 747 | luaM_ngx_get_header(L); 748 | lua_setfield(L, -2, "header"); 749 | 750 | lua_pushcfunction(L, luaF_ngx_set_cookie); 751 | lua_setfield(L, -2, "set_cookie"); 752 | 753 | luaM_ngx_get(L); 754 | lua_setfield(L, -2, "get"); 755 | 756 | luaM_ngx_post(L); 757 | lua_setfield(L, -2, "post"); 758 | 759 | /* {{{ ngx.server */ 760 | lua_newtable(L); 761 | 762 | lua_pushstring(L, (const char *)script_filename); 763 | lua_setfield(L, -2, "SCRIPT_FILENAME"); 764 | 765 | lua_pushlstring(L, (const char *)r->uri.data, r->uri.len); 766 | lua_setfield(L, -2, "REQUEST_URI"); 767 | 768 | lua_pushlstring(L, (const char *)r->args.data, r->args.len); 769 | lua_setfield(L, -2, "QUERY_STRING"); 770 | 771 | lua_pushnumber(L, (int)time((time_t*)NULL)); 772 | lua_setfield(L, -2, "REQUEST_TIME"); 773 | 774 | lua_pushlstring(L, (const char *)r->http_protocol.data, r->http_protocol.len); 775 | lua_setfield(L, -2, "SERVER_PROTOCOL"); 776 | 777 | lua_pushlstring(L, (const char *)r->method_name.data, r->method_name.len); 778 | lua_setfield(L, -2, "REQUEST_METHOD"); 779 | 780 | if (r->headers_in.connection) { 781 | lua_pushlstring(L, (const char *)r->headers_in.connection->value.data, r->headers_in.connection->value.len); 782 | lua_setfield(L, -2, "HTTP_CONNECTION"); 783 | } 784 | 785 | lua_pushlstring(L, (const char *)r->headers_in.host->value.data, r->headers_in.host->value.len); 786 | lua_setfield(L, -2, "HTTP_HOST"); 787 | 788 | lua_pushlstring(L, (const char *)r->headers_in.user_agent->value.data, r->headers_in.user_agent->value.len); 789 | lua_setfield(L, -2, "HTTP_USER_AGENT"); 790 | 791 | if (r->headers_in.referer) { 792 | lua_pushlstring(L, (const char *)r->headers_in.referer->value.data, r->headers_in.referer->value.len); 793 | lua_setfield(L, -2, "HTTP_REFERER"); 794 | } 795 | 796 | #if (NGX_HTTP_PROXY || NGX_HTTP_REALIP || NGX_HTTP_GEO) 797 | if (r->headers_in.x_forwarded_for) { 798 | lua_pushlstring(L, (const char *)r->headers_in.x_forwarded_for->value.data, r->headers_in.x_forwarded_for->value.len); 799 | lua_setfield(L, -2, "X_FORWARDED_FOR"); 800 | } 801 | #endif 802 | 803 | #if (NGX_HTTP_REALIP) 804 | if (r->headers_in.x_real_ip) { 805 | lua_pushlstring(L, (const char *)r->headers_in.x_real_ip->value.data, r->headers_in.x_real_ip->value.len); 806 | lua_setfield(L, -2, "X_REAL_IP"); 807 | } 808 | #endif 809 | 810 | lua_setfield(L, -2, "server"); 811 | /* }}} */ 812 | 813 | lua_setglobal(L, "ngx"); 814 | 815 | // execute lua code 816 | if (luaL_dofile(L, (const char *)script_filename) != 0) { 817 | ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 818 | "runtime error: %s", lua_tostring(L, -1)); 819 | lua_pop(L, 1); 820 | ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); 821 | return; 822 | } 823 | 824 | return; 825 | } 826 | 827 | 828 | static char * 829 | ngx_http_lua_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 830 | { 831 | //ngx_http_lua_loc_conf_t *llcf = conf; 832 | ngx_http_core_loc_conf_t *clcf; 833 | ngx_http_lua_main_conf_t *lmcf; 834 | 835 | lmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_lua_module); 836 | 837 | if (lmcf->lua == NULL) { 838 | if (ngx_http_lua_init_interpreter(cf, lmcf) != NGX_CONF_OK) { 839 | return NGX_CONF_ERROR; 840 | } 841 | } 842 | 843 | clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); 844 | 845 | clcf->handler = ngx_http_lua_file_handler; 846 | ngx_conf_set_str_slot(cf, cmd, conf); 847 | 848 | return NGX_CONF_OK; 849 | } 850 | 851 | 852 | static lua_State* 853 | ngx_http_lua_create_interpreter(ngx_conf_t *cf, ngx_http_lua_main_conf_t *lmcf) 854 | { 855 | lua_State *L; 856 | 857 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, "create lua interpreter"); 858 | 859 | if (ngx_set_environment(cf->cycle, NULL) == NULL) { 860 | return NULL; 861 | } 862 | 863 | L = luaL_newstate(); 864 | if (L == NULL) { 865 | ngx_log_error(NGX_LOG_ALERT, cf->log, 0, "luaL_newstate() failed"); 866 | return NULL; 867 | } 868 | 869 | lua_gc(L, LUA_GCSTOP, 0); 870 | luaL_openlibs(L); 871 | lua_gc(L, LUA_GCRESTART, 0); 872 | 873 | lua_pushcfunction(L, luaC_ngx_print); 874 | lua_setglobal(L, "print"); 875 | 876 | return L; 877 | } 878 | 879 | 880 | static char * 881 | ngx_http_lua_init_interpreter(ngx_conf_t *cf, ngx_http_lua_main_conf_t *lmcf) 882 | { 883 | lmcf->lua = ngx_http_lua_create_interpreter(cf, lmcf); 884 | 885 | if (lmcf->lua == NULL) { 886 | return NGX_CONF_ERROR; 887 | } 888 | 889 | return NGX_CONF_OK; 890 | } 891 | 892 | 893 | static ngx_int_t 894 | ngx_http_lua_init_worker(ngx_cycle_t *cycle) 895 | { 896 | ngx_http_lua_main_conf_t *lmcf; 897 | 898 | lmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_lua_module); 899 | 900 | if (lmcf) { 901 | } 902 | 903 | return NGX_OK; 904 | } 905 | 906 | 907 | static void 908 | ngx_http_lua_exit(ngx_cycle_t *cycle) 909 | { 910 | ngx_http_lua_main_conf_t *lmcf; 911 | 912 | lmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_lua_module); 913 | if (lmcf->lua) { 914 | lua_close(lmcf->lua); 915 | } 916 | } 917 | 918 | 919 | static ngx_int_t 920 | ngx_http_lua_header_filter(ngx_http_request_t *r) 921 | { 922 | //ngx_http_lua_ctx_t *ctx; 923 | 924 | //ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); 925 | 926 | return ngx_http_next_header_filter(r); 927 | } 928 | 929 | 930 | static ngx_int_t 931 | ngx_http_lua_body_filter(ngx_http_request_t *r, ngx_chain_t *in) 932 | { 933 | ngx_http_lua_ctx_t *ctx; 934 | ngx_chain_t *cl; 935 | 936 | ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); 937 | 938 | if (ctx == NULL || ctx->eof) { 939 | return ngx_http_next_body_filter(r, in); 940 | } 941 | 942 | ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 943 | "http lua filter"); 944 | 945 | for (cl = in; cl; cl = cl->next) { 946 | cl->buf->pos = cl->buf->last; 947 | cl->buf->file_pos = cl->buf->file_last; 948 | } 949 | 950 | if (r == r->connection->data && r->postponed) { 951 | /* notify the downstream postpone filter to flush the postponed 952 | * outputs of the current request */ 953 | return ngx_http_next_body_filter(r, NULL); 954 | } 955 | 956 | return NGX_OK; 957 | } 958 | 959 | 960 | static ngx_int_t 961 | ngx_http_lua_init(ngx_conf_t *cf) 962 | { 963 | ngx_http_next_header_filter = ngx_http_top_header_filter; 964 | ngx_http_top_header_filter = ngx_http_lua_header_filter; 965 | 966 | ngx_http_next_body_filter = ngx_http_top_body_filter; 967 | ngx_http_top_body_filter = ngx_http_lua_body_filter; 968 | 969 | return NGX_OK; 970 | } 971 | 972 | 973 | static u_char * 974 | ngx_http_lua_script_filename(ngx_pool_t *pool, u_char *src, size_t len) 975 | { 976 | u_char *p, *dst; 977 | 978 | if (len == 0) { 979 | return NULL; 980 | } 981 | 982 | if (src[0] == '/') { 983 | /* being an absolute path already */ 984 | dst = ngx_palloc(pool, len + 1); 985 | if (dst == NULL) { 986 | return NULL; 987 | } 988 | 989 | p = ngx_copy(dst, src, len); 990 | 991 | *p = '\0'; 992 | 993 | return dst; 994 | } 995 | 996 | dst = ngx_palloc(pool, ngx_cycle->prefix.len + len + 1); 997 | if (dst == NULL) { 998 | return NULL; 999 | } 1000 | 1001 | p = ngx_copy(dst, ngx_cycle->prefix.data, ngx_cycle->prefix.len); 1002 | p = ngx_copy(p, src, len); 1003 | 1004 | *p = '\0'; 1005 | 1006 | return dst; 1007 | } 1008 | 1009 | 1010 | /** 1011 | * Force flush out response content 1012 | * */ 1013 | static int 1014 | luaF_ngx_flush(lua_State *L) 1015 | { 1016 | ngx_http_request_t *r; 1017 | ngx_http_lua_ctx_t *ctx; 1018 | ngx_buf_t *buf; 1019 | ngx_chain_t *cl; 1020 | ngx_int_t rc; 1021 | 1022 | lua_getglobal(L, LUA_NGX_REQUEST); 1023 | r = lua_touserdata(L, -1); 1024 | lua_pop(L, 1); 1025 | 1026 | if (r == NULL) { 1027 | return luaL_error(L, "no request object found"); 1028 | } 1029 | 1030 | ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); 1031 | if (ctx == NULL) { 1032 | return luaL_error(L, "no request ctx found"); 1033 | } 1034 | 1035 | if (ctx->eof) { 1036 | return luaL_error(L, "already seen eof"); 1037 | } 1038 | 1039 | buf = ngx_calloc_buf(r->pool); 1040 | if (buf == NULL) { 1041 | return luaL_error(L, "memory allocation error"); 1042 | } 1043 | 1044 | buf->flush = 1; 1045 | 1046 | cl = ngx_alloc_chain_link(r->pool); 1047 | if (cl == NULL) { 1048 | return luaL_error(L, "out of memory"); 1049 | } 1050 | 1051 | cl->next = NULL; 1052 | cl->buf = buf; 1053 | 1054 | rc = ngx_http_lua_send_chain_link(r, ctx, cl); 1055 | 1056 | if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { 1057 | return luaL_error(L, "failed to send chain link: %d", (int) rc); 1058 | } 1059 | 1060 | return 0; 1061 | } 1062 | 1063 | 1064 | /** 1065 | * Send last_buf, terminate output stream 1066 | * */ 1067 | static int 1068 | luaF_ngx_eof(lua_State *L) 1069 | { 1070 | ngx_http_request_t *r; 1071 | ngx_http_lua_ctx_t *ctx; 1072 | ngx_int_t rc; 1073 | 1074 | lua_getglobal(L, LUA_NGX_REQUEST); 1075 | r = lua_touserdata(L, -1); 1076 | lua_pop(L, 1); 1077 | 1078 | if (r == NULL) { 1079 | return luaL_error(L, "no request object found"); 1080 | } 1081 | 1082 | ctx = ngx_http_get_module_ctx(r, ngx_http_lua_module); 1083 | 1084 | rc = ngx_http_lua_send_chain_link(r, ctx, NULL/*indicate last_buf*/); 1085 | 1086 | if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { 1087 | return luaL_error(L, "failed to send eof buf"); 1088 | } 1089 | 1090 | return 0; 1091 | } 1092 | -------------------------------------------------------------------------------- /src/strtok_r.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1998 Softweyr LLC. All rights reserved. 3 | * 4 | * strtok_r, from Berkeley strtok 5 | * Oct 13, 1998 by Wes Peters 6 | * 7 | * Copyright (c) 1988, 1993 8 | * The Regents of the University of California. All rights reserved. 9 | * 10 | * Redistribution and use in source and binary forms, with or without 11 | * modification, are permitted provided that the following conditions 12 | * are met: 13 | * 14 | * 1. Redistributions of source code must retain the above copyright 15 | * notices, this list of conditions and the following disclaimer. 16 | * 17 | * 2. Redistributions in binary form must reproduce the above copyright 18 | * notices, this list of conditions and the following disclaimer in the 19 | * documentation and/or other materials provided with the distribution. 20 | * 21 | * 3. All advertising materials mentioning features or use of this software 22 | * must display the following acknowledgement: 23 | * 24 | * This product includes software developed by Softweyr LLC, the 25 | * University of California, Berkeley, and its contributors. 26 | * 27 | * 4. Neither the name of the University nor the names of its contributors 28 | * may be used to endorse or promote products derived from this software 29 | * without specific prior written permission. 30 | * 31 | * THIS SOFTWARE IS PROVIDED BY SOFTWEYR LLC, THE REGENTS AND CONTRIBUTORS 32 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 34 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SOFTWEYR LLC, THE 35 | * REGENTS, OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 36 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 37 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 38 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 39 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 40 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 41 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 | */ 43 | 44 | #include 45 | 46 | char * 47 | strtok_r(char *s, const char *delim, char **last) 48 | { 49 | char *spanp; 50 | int c, sc; 51 | char *tok; 52 | 53 | if (s == NULL && (s = *last) == NULL) 54 | { 55 | return NULL; 56 | } 57 | 58 | /* 59 | * Skip (span) leading delimiters (s += strspn(s, delim), sort of). 60 | */ 61 | cont: 62 | c = *s++; 63 | for (spanp = (char *)delim; (sc = *spanp++) != 0; ) 64 | { 65 | if (c == sc) 66 | { 67 | goto cont; 68 | } 69 | } 70 | 71 | if (c == 0) /* no non-delimiter characters */ 72 | { 73 | *last = NULL; 74 | return NULL; 75 | } 76 | tok = s - 1; 77 | 78 | /* 79 | * Scan token (scan for delimiters: s += strcspn(s, delim), sort of). 80 | * Note that delim must have one NUL; we stop if we see that, too. 81 | */ 82 | for (;;) 83 | { 84 | c = *s++; 85 | spanp = (char *)delim; 86 | do 87 | { 88 | if ((sc = *spanp++) == c) 89 | { 90 | if (c == 0) 91 | { 92 | s = NULL; 93 | } 94 | else 95 | { 96 | char *w = s - 1; 97 | *w = '\0'; 98 | } 99 | *last = s; 100 | return tok; 101 | } 102 | } 103 | while (sc != 0); 104 | } 105 | /* NOTREACHED */ 106 | } 107 | -------------------------------------------------------------------------------- /src/strtok_r.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Copyright (C) Alacner Zhang (alacner@gmail.com) 4 | */ 5 | 6 | 7 | #ifndef STRTOK_R_H 8 | #define STRTOK_R_H 9 | 10 | char * strtok_r(char *s, const char *delim, char **last); 11 | 12 | #endif /* STRTOK_R_H */ 13 | --------------------------------------------------------------------------------