Commit b1495dba by Joneq

提交第一版

parents
No preview for this file type
config.lua
\ No newline at end of file
No preview for this file type
-- Copyright (C) Yichun Zhang (agentzh)
local base = require "resty.core.base"
base.allows_subsystem('http', 'stream')
local ffi = require "ffi"
local C = ffi.C
local ffi_str = ffi.string
local errmsg = base.get_errmsg_ptr()
local FFI_OK = base.FFI_OK
local FFI_ERROR = base.FFI_ERROR
local int_out = ffi.new("int[1]")
local get_request = base.get_request
local error = error
local type = type
local tonumber = tonumber
local max = math.max
local subsystem = ngx.config.subsystem
local ngx_lua_ffi_balancer_set_current_peer
local ngx_lua_ffi_balancer_set_more_tries
local ngx_lua_ffi_balancer_get_last_failure
local ngx_lua_ffi_balancer_set_timeouts -- used by both stream and http
if subsystem == 'http' then
ffi.cdef[[
int ngx_http_lua_ffi_balancer_set_current_peer(ngx_http_request_t *r,
const unsigned char *addr, size_t addr_len, int port, char **err);
int ngx_http_lua_ffi_balancer_set_more_tries(ngx_http_request_t *r,
int count, char **err);
int ngx_http_lua_ffi_balancer_get_last_failure(ngx_http_request_t *r,
int *status, char **err);
int ngx_http_lua_ffi_balancer_set_timeouts(ngx_http_request_t *r,
long connect_timeout, long send_timeout,
long read_timeout, char **err);
]]
ngx_lua_ffi_balancer_set_current_peer =
C.ngx_http_lua_ffi_balancer_set_current_peer
ngx_lua_ffi_balancer_set_more_tries =
C.ngx_http_lua_ffi_balancer_set_more_tries
ngx_lua_ffi_balancer_get_last_failure =
C.ngx_http_lua_ffi_balancer_get_last_failure
ngx_lua_ffi_balancer_set_timeouts =
C.ngx_http_lua_ffi_balancer_set_timeouts
elseif subsystem == 'stream' then
ffi.cdef[[
int ngx_stream_lua_ffi_balancer_set_current_peer(
ngx_stream_lua_request_t *r,
const unsigned char *addr, size_t addr_len, int port, char **err);
int ngx_stream_lua_ffi_balancer_set_more_tries(ngx_stream_lua_request_t *r,
int count, char **err);
int ngx_stream_lua_ffi_balancer_get_last_failure(
ngx_stream_lua_request_t *r, int *status, char **err);
int ngx_stream_lua_ffi_balancer_set_timeouts(ngx_stream_lua_request_t *r,
long connect_timeout, long timeout, char **err);
]]
ngx_lua_ffi_balancer_set_current_peer =
C.ngx_stream_lua_ffi_balancer_set_current_peer
ngx_lua_ffi_balancer_set_more_tries =
C.ngx_stream_lua_ffi_balancer_set_more_tries
ngx_lua_ffi_balancer_get_last_failure =
C.ngx_stream_lua_ffi_balancer_get_last_failure
local ngx_stream_lua_ffi_balancer_set_timeouts =
C.ngx_stream_lua_ffi_balancer_set_timeouts
ngx_lua_ffi_balancer_set_timeouts =
function(r, connect_timeout, send_timeout, read_timeout, err)
local timeout = max(send_timeout, read_timeout)
return ngx_stream_lua_ffi_balancer_set_timeouts(r, connect_timeout,
timeout, err)
end
else
error("unknown subsystem: " .. subsystem)
end
local peer_state_names = {
[1] = "keepalive",
[2] = "next",
[4] = "failed",
}
local _M = { version = base.version }
function _M.set_current_peer(addr, port)
local r = get_request()
if not r then
error("no request found")
end
if not port then
port = 0
elseif type(port) ~= "number" then
port = tonumber(port)
end
local rc = ngx_lua_ffi_balancer_set_current_peer(r, addr, #addr,
port, errmsg)
if rc == FFI_OK then
return true
end
return nil, ffi_str(errmsg[0])
end
function _M.set_more_tries(count)
local r = get_request()
if not r then
error("no request found")
end
local rc = ngx_lua_ffi_balancer_set_more_tries(r, count, errmsg)
if rc == FFI_OK then
if errmsg[0] == nil then
return true
end
return true, ffi_str(errmsg[0]) -- return the warning
end
return nil, ffi_str(errmsg[0])
end
function _M.get_last_failure()
local r = get_request()
if not r then
error("no request found")
end
local state = ngx_lua_ffi_balancer_get_last_failure(r, int_out, errmsg)
if state == 0 then
return nil
end
if state == FFI_ERROR then
return nil, nil, ffi_str(errmsg[0])
end
return peer_state_names[state] or "unknown", int_out[0]
end
function _M.set_timeouts(connect_timeout, send_timeout, read_timeout)
local r = get_request()
if not r then
error("no request found")
end
if not connect_timeout then
connect_timeout = 0
elseif type(connect_timeout) ~= "number" or connect_timeout <= 0 then
error("bad connect timeout", 2)
else
connect_timeout = connect_timeout * 1000
end
if not send_timeout then
send_timeout = 0
elseif type(send_timeout) ~= "number" or send_timeout <= 0 then
error("bad send timeout", 2)
else
send_timeout = send_timeout * 1000
end
if not read_timeout then
read_timeout = 0
elseif type(read_timeout) ~= "number" or read_timeout <= 0 then
error("bad read timeout", 2)
else
read_timeout = read_timeout * 1000
end
local rc
rc = ngx_lua_ffi_balancer_set_timeouts(r, connect_timeout,
send_timeout, read_timeout,
errmsg)
if rc == FFI_OK then
return true
end
return false, ffi_str(errmsg[0])
end
return _M
-- Copyright (C) by Yichun Zhang (agentzh)
-- Copyright (C) by OpenResty Inc.
local ffi = require("ffi")
local base = require("resty.core.base")
local ffi_str = ffi.string
local type = type
local C = ffi.C
local NGX_ERROR = ngx.ERROR
local _M = { version = base.version }
ffi.cdef[[
typedef intptr_t ngx_int_t;
void ngx_encode_base64url(ngx_str_t *dst, ngx_str_t *src);
ngx_int_t ngx_decode_base64url(ngx_str_t *dst, ngx_str_t *src);
]]
local get_string_buf = base.get_string_buf
local dst_str_t = ffi.new("ngx_str_t[1]")
local src_str_t = ffi.new("ngx_str_t[1]")
local function base64_encoded_length(len)
return ((len + 2) / 3) * 4
end
local function base64_decoded_length(len)
return ((len + 3) / 4) * 3
end
function _M.encode_base64url(s)
if type(s) ~= "string" then
return nil, "must provide a string"
end
local len = #s
local trans_len = base64_encoded_length(len)
local src = src_str_t[0]
local dst = dst_str_t[0]
src.data = s
src.len = len
dst.data = get_string_buf(trans_len)
dst.len = trans_len
C.ngx_encode_base64url(dst_str_t, src_str_t)
return ffi_str(dst.data, dst.len)
end
function _M.decode_base64url(s)
if type(s) ~= "string" then
return nil, "must provide a string"
end
local len = #s
local trans_len = base64_decoded_length(len)
local src = src_str_t[0]
local dst = dst_str_t[0]
src.data = s
src.len = len
dst.data = get_string_buf(trans_len)
dst.len = trans_len
local ret = C.ngx_decode_base64url(dst_str_t, src_str_t)
if ret == NGX_ERROR then
return nil, "invalid input"
end
return ffi_str(dst.data, dst.len)
end
return _M
Name
====
`ngx.base64` - urlsafe base64 encode/decode functions OpenResty/ngx\_lua.
Table of Contents
=================
* [Name](#name)
* [Status](#status)
* [Synopsis](#synopsis)
* [Methods](#methods)
* [encode\_base64url](#encode_base64url)
* [decode\_base64url](#decode_base64url)
* [Community](#community)
* [English Mailing List](#english-mailing-list)
* [Chinese Mailing List](#chinese-mailing-list)
* [Bugs and Patches](#bugs-and-patches)
* [Author](#author)
* [Copyright and License](#copyright-and-license)
* [See Also](#see-also)
Status
======
This Lua module is production ready.
Synopsis
========
```lua
local b64 = require("ngx.base64")
local res, err
res = b64.encode_base64url("foo")
res, err = b64.decode_base64url(res)
if not res then
-- invalid input
ngx.log(ngx.ERR, err)
end
assert(res == "foo")
```
[Back to TOC](#table-of-contents)
Methods
=======
encode\_base64url
-----------------
**syntax:** *encoded = base64.encode_base64url(input)*
**context:** *any*
Encode `input` using base64url rules. Returns the encoded string.
[Back to TOC](#table-of-contents)
decode\_base64url
-----------------
**syntax:** *decoded, err = base64.decode_base64url(input)*
**context:** *any*
Decode `input` using base64url rules. Returns the decoded string.
If the `input` is not a valid base64url encoded string, `decoded `will be `nil`
and `err` will be a string describing the error.
[Back to TOC](#table-of-contents)
Community
=========
[Back to TOC](#table-of-contents)
English Mailing List
--------------------
The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers.
[Back to TOC](#table-of-contents)
Chinese Mailing List
--------------------
The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers.
[Back to TOC](#table-of-contents)
Bugs and Patches
================
Please report bugs or submit patches by
1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues),
1. or posting to the [OpenResty community](#community).
[Back to TOC](#table-of-contents)
Author
======
Datong Sun &lt;datong@openresty.com&gt; (dndx), OpenResty Inc.
[Back to TOC](#table-of-contents)
Copyright and License
=====================
This module is licensed under the BSD license.
Copyright (C) 2017, by Yichun "agentzh" Zhang, OpenResty Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[Back to TOC](#table-of-contents)
See Also
========
* the [lua-resty-core](https://github.com/openresty/lua-resty-core) library.
* the ngx_lua module: https://github.com/openresty/lua-nginx-module
* OpenResty: https://openresty.org
[Back to TOC](#table-of-contents)
-- Copyright (C) Yichun Zhang (agentzh)
local base = require "resty.core.base"
base.allows_subsystem('http', 'stream')
local ffi = require 'ffi'
local ffi_string = ffi.string
local get_string_buf = base.get_string_buf
local get_size_ptr = base.get_size_ptr
local C = ffi.C
local new_tab = base.new_tab
local ffi_new = ffi.new
local charpp = ffi_new("char *[1]")
local intp = ffi.new("int[1]")
local num_value = ffi_new("double[1]")
local get_request = base.get_request
local tonumber = tonumber
local type = type
local error = error
local subsystem = ngx.config.subsystem
local ngx_lua_ffi_errlog_set_filter_level
local ngx_lua_ffi_errlog_get_msg
local ngx_lua_ffi_errlog_get_sys_filter_level
local ngx_lua_ffi_raw_log
local _M = { version = base.version }
if subsystem == 'http' then
ffi.cdef[[
int ngx_http_lua_ffi_errlog_set_filter_level(int level, unsigned char *err,
size_t *errlen);
int ngx_http_lua_ffi_errlog_get_msg(char **log, int *loglevel,
unsigned char *err, size_t *errlen, double *log_time);
int ngx_http_lua_ffi_errlog_get_sys_filter_level(ngx_http_request_t *r);
int ngx_http_lua_ffi_raw_log(ngx_http_request_t *r, int level,
const unsigned char *s, size_t s_len);
]]
ngx_lua_ffi_errlog_set_filter_level =
C.ngx_http_lua_ffi_errlog_set_filter_level
ngx_lua_ffi_errlog_get_msg = C.ngx_http_lua_ffi_errlog_get_msg
ngx_lua_ffi_errlog_get_sys_filter_level =
C.ngx_http_lua_ffi_errlog_get_sys_filter_level
ngx_lua_ffi_raw_log = C.ngx_http_lua_ffi_raw_log
elseif subsystem == 'stream' then
ffi.cdef[[
int ngx_stream_lua_ffi_errlog_set_filter_level(int level, unsigned char *err,
size_t *errlen);
int ngx_stream_lua_ffi_errlog_get_msg(char **log, int *loglevel,
unsigned char *err, size_t *errlen, double *log_time);
int ngx_stream_lua_ffi_errlog_get_sys_filter_level(ngx_stream_lua_request_t *r);
int ngx_stream_lua_ffi_raw_log(ngx_stream_lua_request_t *r, int level,
const unsigned char *s, size_t s_len);
]]
ngx_lua_ffi_errlog_set_filter_level =
C.ngx_stream_lua_ffi_errlog_set_filter_level
ngx_lua_ffi_errlog_get_msg = C.ngx_stream_lua_ffi_errlog_get_msg
ngx_lua_ffi_errlog_get_sys_filter_level =
C.ngx_stream_lua_ffi_errlog_get_sys_filter_level
ngx_lua_ffi_raw_log = C.ngx_stream_lua_ffi_raw_log
end
local ERR_BUF_SIZE = 128
local FFI_ERROR = base.FFI_ERROR
function _M.set_filter_level(level)
if not level then
return nil, [[missing "level" argument]]
end
local err = get_string_buf(ERR_BUF_SIZE)
local errlen = get_size_ptr()
errlen[0] = ERR_BUF_SIZE
local rc = ngx_lua_ffi_errlog_set_filter_level(level, err, errlen)
if rc == FFI_ERROR then
return nil, ffi_string(err, errlen[0])
end
return true
end
function _M.get_logs(max, logs)
local err = get_string_buf(ERR_BUF_SIZE)
local errlen = get_size_ptr()
errlen[0] = ERR_BUF_SIZE
local log = charpp
local loglevel = intp
local log_time = num_value
max = max or 10
if not logs then
logs = new_tab(max * 3 + 1, 0)
end
local count = 0
for i = 1, max do
local loglen = ngx_lua_ffi_errlog_get_msg(log, loglevel, err, errlen,
log_time)
if loglen == FFI_ERROR then
return nil, ffi_string(err, errlen[0])
end
if loglen > 0 then
logs[count + 1] = loglevel[0]
logs[count + 2] = log_time[0]
logs[count + 3] = ffi_string(log[0], loglen)
count = count + 3
end
if loglen < 0 then -- no error log
logs[count + 1] = nil
break
end
if i == max then -- last one
logs[count + 1] = nil
break
end
end
return logs
end
function _M.get_sys_filter_level()
local r = get_request()
return tonumber(ngx_lua_ffi_errlog_get_sys_filter_level(r))
end
function _M.raw_log(level, msg)
if type(level) ~= "number" then
error("bad argument #1 to 'raw_log' (must be a number)", 2)
end
if type(msg) ~= "string" then
error("bad argument #2 to 'raw_log' (must be a string)", 2)
end
local r = get_request()
local rc = ngx_lua_ffi_raw_log(r, level, msg, #msg)
if rc == FFI_ERROR then
error("bad log level", 2)
end
end
return _M
-- Copyright (C) Yichun Zhang (agentzh)
local base = require "resty.core.base"
base.allows_subsystem('http')
local ffi = require "ffi"
local C = ffi.C
local ffi_str = ffi.string
local get_request = base.get_request
local error = error
local tonumber = tonumber
local errmsg = base.get_errmsg_ptr()
local get_string_buf = base.get_string_buf
local get_string_buf_size = base.get_string_buf_size
local get_size_ptr = base.get_size_ptr
local FFI_DECLINED = base.FFI_DECLINED
local FFI_OK = base.FFI_OK
local FFI_BUSY = base.FFI_BUSY
ffi.cdef[[
int ngx_http_lua_ffi_ssl_get_ocsp_responder_from_der_chain(
const char *chain_data, size_t chain_len, char *out, size_t *out_size,
char **err);
int ngx_http_lua_ffi_ssl_create_ocsp_request(const char *chain_data,
size_t chain_len, unsigned char *out, size_t *out_size, char **err);
int ngx_http_lua_ffi_ssl_validate_ocsp_response(const unsigned char *resp,
size_t resp_len, const char *chain_data, size_t chain_len,
unsigned char *errbuf, size_t *errbuf_size);
int ngx_http_lua_ffi_ssl_set_ocsp_status_resp(ngx_http_request_t *r,
const unsigned char *resp, size_t resp_len, char **err);
]]
local _M = { version = base.version }
function _M.get_ocsp_responder_from_der_chain(certs, maxlen)
local buf_size = maxlen
if not buf_size then
buf_size = get_string_buf_size()
end
local buf = get_string_buf(buf_size)
local sizep = get_size_ptr()
sizep[0] = buf_size
local rc = C.ngx_http_lua_ffi_ssl_get_ocsp_responder_from_der_chain(certs,
#certs, buf, sizep, errmsg)
if rc == FFI_DECLINED then
return nil
end
if rc == FFI_OK then
return ffi_str(buf, sizep[0])
end
if rc == FFI_BUSY then
return ffi_str(buf, sizep[0]), "truncated"
end
return nil, ffi_str(errmsg[0])
end
function _M.create_ocsp_request(certs, maxlen)
local buf_size = maxlen
if not buf_size then
buf_size = get_string_buf_size()
end
local buf = get_string_buf(buf_size)
local sizep = get_size_ptr()
sizep[0] = buf_size
local rc = C.ngx_http_lua_ffi_ssl_create_ocsp_request(certs,
#certs, buf, sizep,
errmsg)
if rc == FFI_OK then
return ffi_str(buf, sizep[0])
end
if rc == FFI_BUSY then
return nil, ffi_str(errmsg[0]) .. ": " .. tonumber(sizep[0])
.. " > " .. buf_size
end
return nil, ffi_str(errmsg[0])
end
function _M.validate_ocsp_response(resp, chain, max_errmsg_len)
local errbuf_size = max_errmsg_len
if not errbuf_size then
errbuf_size = get_string_buf_size()
end
local errbuf = get_string_buf(errbuf_size)
local sizep = get_size_ptr()
sizep[0] = errbuf_size
local rc = C.ngx_http_lua_ffi_ssl_validate_ocsp_response(
resp, #resp, chain, #chain, errbuf, sizep)
if rc == FFI_OK then
return true
end
-- rc == FFI_ERROR
return nil, ffi_str(errbuf, sizep[0])
end
function _M.set_ocsp_status_resp(ocsp_resp)
local r = get_request()
if not r then
error("no request found")
end
local rc = C.ngx_http_lua_ffi_ssl_set_ocsp_status_resp(r, ocsp_resp,
#ocsp_resp,
errmsg)
if rc == FFI_DECLINED then
-- no client status req
return true, "no status req"
end
if rc == FFI_OK then
return true
end
-- rc == FFI_ERROR
return nil, ffi_str(errmsg[0])
end
return _M
-- Copyright (C) Yichun Zhang (agentzh)
local base = require "resty.core.base"
base.allows_subsystem('http')
local ffi = require 'ffi'
require "resty.core.phase" -- for ngx.get_phase
local errmsg = base.get_errmsg_ptr()
local FFI_ERROR = base.FFI_ERROR
local ffi_str = ffi.string
local ngx_phase = ngx.get_phase
local tonumber = tonumber
local process_type_names = {
[0 ] = "single",
[1 ] = "master",
[2 ] = "signaller",
[3 ] = "worker",
[4 ] = "helper",
[99] = "privileged agent",
}
local C = ffi.C
local _M = { version = base.version }
ffi.cdef[[
int ngx_http_lua_ffi_enable_privileged_agent(char **err);
int ngx_http_lua_ffi_get_process_type(void);
void ngx_http_lua_ffi_process_signal_graceful_exit(void);
int ngx_http_lua_ffi_master_pid(void);
]]
function _M.type()
local typ = C.ngx_http_lua_ffi_get_process_type()
return process_type_names[tonumber(typ)]
end
function _M.enable_privileged_agent()
if ngx_phase() ~= "init" then
return nil, "API disabled in the current context"
end
local rc = C.ngx_http_lua_ffi_enable_privileged_agent(errmsg)
if rc == FFI_ERROR then
return nil, ffi_str(errmsg[0])
end
return true
end
function _M.signal_graceful_exit()
C.ngx_http_lua_ffi_process_signal_graceful_exit()
end
function _M.get_master_pid()
local pid = C.ngx_http_lua_ffi_master_pid()
if pid == FFI_ERROR then
return nil
end
return tonumber(pid)
end
return _M
Name
====
`ngx.process` - manage the nginx processes for OpenResty/ngx_lua.
Table of Contents
=================
* [Name](#name)
* [Status](#status)
* [Synopsis](#synopsis)
* [Functions](#functions)
* [type](#type)
* [enable_privileged_agent](#enable_privileged_agent)
* [signal_graceful_exit](#signal_graceful_exit)
* [get_master_pid](#get_master_pid)
* [Community](#community)
* [English Mailing List](#english-mailing-list)
* [Chinese Mailing List](#chinese-mailing-list)
* [Bugs and Patches](#bugs-and-patches)
* [Author](#author)
* [Copyright and License](#copyright-and-license)
* [See Also](#see-also)
Status
======
This Lua module is currently considered experimental.
The API is still in flux and may change in the future without notice.
Synopsis
========
Enables privileged agent process, gets process type, and then gets the master process PID:
```nginx
# http config
init_by_lua_block {
local process = require "ngx.process"
-- enables privileged agent process
local ok, err = process.enable_privileged_agent()
if not ok then
ngx.log(ngx.ERR, "enables privileged agent failed error:", err)
end
-- output process type
ngx.log(ngx.INFO, "process type: ", process.type())
}
init_worker_by_lua_block {
local process = require "ngx.process"
ngx.log(ngx.INFO, "process type: ", process.type())
}
server {
# ...
location = /t {
content_by_lua_block {
local process = require "ngx.process"
ngx.say("process type: ", process.type())
ngx.say("master process pid: ", process.get_master_pid() or "-")
}
}
}
```
The example config above produces an output to `error.log` when
server starts:
```
[lua] init_by_lua:11: process type: master
[lua] init_worker_by_lua:3: process type: privileged agent
[lua] init_worker_by_lua:3: process type: worker
```
The example location above produces the following response body:
```
process type: worker
master process pid: 8261
```
[Back to TOC](#table-of-contents)
Functions
=========
type
----
**syntax:** *type_name = process_module.type()*
**context:** *any*
Returns the type of the current Nginx process. Depending on the calling context
and current process, the type can be one of:
* `master`: returned when this function is called from within the master
process
* `worker`: returned when this function is called from within a worker process
* `single`: returned when Nginx is running in the single process mode
* `signaller`: returned when Nginx is running as a signaller process
* `privileged agent`: returned when this funtion is called from within a
privileged agent process
For example:
```lua
local process = require "ngx.process"
ngx.say("process type:", process.type()) -- RESPONSE: worker
```
[Back to TOC](#table-of-contents)
enable_privileged_agent
-----------------------
**syntax:** *ok, err = process_module.enable_privileged_agent()*
**context:** *init_by_lua&#42;*
Enables the privileged agent process in Nginx.
The privileged agent process does not listen on any virtual server ports like those worker processes.
And it uses the same system account as the nginx master process, which is usually a privileged account
like `root`.
The `init_worker_by_lua*` directive handler still runs in the privileged agent process. And one can
use the [type](#type) function provided by this module to check if the current process is a privileged
agent.
In case of failures, returns `nil` and a string describing the error.
[Back to TOC](#table-of-contents)
signal_graceful_exit
--------------------
**syntax:** *process_module.signal_graceful_exit()*
**context:** *any*
Signals the *current* nginx (worker) process to quit gracefully, i.e., after all the timers have expired (in time or expired prematurely).
Note that this API function simply sets the nginx global C variable `ngx_quit` to signal the nginx event
loop directly. No UNIX signals or IPC are involved here.
WARNING: the official NGINX core does not perform the graceful exiting procedure when the [master_process](http://nginx.org/r/master_process)
directive is turned `off`. The OpenResty's NGINX core has a
[custom patch](https://github.com/openresty/openresty/blob/master/patches/nginx-1.11.2-single_process_graceful_exit.patch)
applied, which fixes this issue.
[Back to TOC](#table-of-contents)
get_master_pid
--------------
**syntax:** *pid = process_module.get_master_pid()*
**context:** *any*
Returns a number value for the nginx master process's process ID (or PID).
This function requires NGINX 1.13.8+ cores to work properly. Otherwise it returns `nil`.
This feature first appeared in lua-resty-core v0.1.14.
[Back to TOC](#table-of-contents)
Community
=========
[Back to TOC](#table-of-contents)
English Mailing List
--------------------
The [openresty-en](https://groups.google.com/group/openresty-en) mailing list is for English speakers.
[Back to TOC](#table-of-contents)
Chinese Mailing List
--------------------
The [openresty](https://groups.google.com/group/openresty) mailing list is for Chinese speakers.
[Back to TOC](#table-of-contents)
Bugs and Patches
================
Please report bugs or submit patches by
1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues),
1. or posting to the [OpenResty community](#community).
[Back to TOC](#table-of-contents)
Author
======
Yuansheng Wang &lt;membphis@gmail.com&gt; (membphis), OpenResty Inc.
[Back to TOC](#table-of-contents)
Copyright and License
=====================
This module is licensed under the BSD license.
Copyright (C) 2017, by Yichun "agentzh" Zhang, OpenResty Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[Back to TOC](#table-of-contents)
See Also
========
* the [lua-resty-core](https://github.com/openresty/lua-resty-core) library.
* the ngx_lua module: https://github.com/openresty/lua-nginx-module
* OpenResty: https://openresty.org
[Back to TOC](#table-of-contents)
-- I hereby assign copyright in this code to the lua-resty-core project,
-- to be licensed under the same terms as the rest of the code.
local base = require "resty.core.base"
local ffi = require 'ffi'
local bit = require "bit"
local core_regex = require "resty.core.regex"
if core_regex.no_pcre then
error("no support for 'ngx.re' module: OpenResty was " ..
"compiled without PCRE support", 3)
end
local C = ffi.C
local ffi_str = ffi.string
local sub = string.sub
local error = error
local type = type
local band = bit.band
local new_tab = base.new_tab
local tostring = tostring
local math_max = math.max
local math_min = math.min
local is_regex_cache_empty = core_regex.is_regex_cache_empty
local re_match_compile = core_regex.re_match_compile
local destroy_compiled_regex = core_regex.destroy_compiled_regex
local get_string_buf = base.get_string_buf
local get_size_ptr = base.get_size_ptr
local FFI_OK = base.FFI_OK
local subsystem = ngx.config.subsystem
local MAX_ERR_MSG_LEN = 128
local FLAG_DFA = 0x02
local PCRE_ERROR_NOMATCH = -1
local DEFAULT_SPLIT_RES_SIZE = 4
local split_ctx = new_tab(0, 1)
local ngx_lua_ffi_set_jit_stack_size
local ngx_lua_ffi_exec_regex
if subsystem == 'http' then
ffi.cdef[[
int ngx_http_lua_ffi_set_jit_stack_size(int size, unsigned char *errstr,
size_t *errstr_size);
]]
ngx_lua_ffi_exec_regex = C.ngx_http_lua_ffi_exec_regex
ngx_lua_ffi_set_jit_stack_size = C.ngx_http_lua_ffi_set_jit_stack_size
elseif subsystem == 'stream' then
ffi.cdef[[
int ngx_stream_lua_ffi_set_jit_stack_size(int size, unsigned char *errstr,
size_t *errstr_size);
]]
ngx_lua_ffi_exec_regex = C.ngx_stream_lua_ffi_exec_regex
ngx_lua_ffi_set_jit_stack_size = C.ngx_stream_lua_ffi_set_jit_stack_size
end
local _M = { version = base.version }
local function re_split_helper(subj, compiled, compile_once, flags, ctx)
local rc
do
local pos = math_max(ctx.pos, 0)
rc = ngx_lua_ffi_exec_regex(compiled, flags, subj, #subj, pos)
end
if rc == PCRE_ERROR_NOMATCH then
return nil, nil, nil
end
if rc < 0 then
if not compile_once then
destroy_compiled_regex(compiled)
end
return nil, nil, nil, "pcre_exec() failed: " .. rc
end
if rc == 0 then
if band(flags, FLAG_DFA) == 0 then
if not compile_once then
destroy_compiled_regex(compiled)
end
return nil, nil, nil, "capture size too small"
end
rc = 1
end
local caps = compiled.captures
local ncaps = compiled.ncaptures
local from = caps[0]
local to = caps[1]
if from < 0 or to < 0 then
return nil, nil, nil
end
if from == to then
-- empty match, skip to next char
ctx.pos = to + 1
else
ctx.pos = to
end
-- convert to Lua string indexes
from = from + 1
to = to + 1
-- retrieve the first sub-match capture if any
if ncaps > 0 and rc > 1 then
return from, to, sub(subj, caps[2] + 1, caps[3])
end
return from, to
end
function _M.split(subj, regex, opts, ctx, max, res)
-- we need to cast this to strings to avoid exceptions when they are
-- something else.
-- needed because of further calls to string.sub in this function.
subj = tostring(subj)
if not ctx then
ctx = split_ctx
ctx.pos = 1 -- set or reset upvalue field
elseif not ctx.pos then
-- ctx provided by user but missing pos field
ctx.pos = 1
end
max = max or 0
if not res then
-- limit the initial arr_n size of res to a reasonable value
-- 0 < narr <= DEFAULT_SPLIT_RES_SIZE
local narr = DEFAULT_SPLIT_RES_SIZE
if max > 0 then
-- the user specified a valid max limiter if max > 0
narr = math_min(narr, max)
end
res = new_tab(narr, 0)
elseif type(res) ~= "table" then
error("res is not a table", 2)
end
local len = #subj
if ctx.pos > len then
res[1] = nil
return res
end
-- compile regex
local compiled, compile_once, flags = re_match_compile(regex, opts)
if compiled == nil then
-- compiled_once holds the error string
return nil, compile_once
end
local sub_idx = ctx.pos
local res_idx = 0
local last_empty_match
-- update to split_helper PCRE indexes
ctx.pos = sub_idx - 1
-- splitting: with and without a max limiter
if max > 0 then
local count = 1
while count < max do
local from, to, capture, err = re_split_helper(subj, compiled,
compile_once, flags, ctx)
if err then
return nil, err
end
if not from then
break
end
if last_empty_match then
sub_idx = last_empty_match
end
if from == to then
last_empty_match = from
end
if from > sub_idx or not last_empty_match then
count = count + 1
res_idx = res_idx + 1
res[res_idx] = sub(subj, sub_idx, from - 1)
if capture then
res_idx = res_idx + 1
res[res_idx] = capture
end
sub_idx = to
if sub_idx > len then
break
end
end
end
else
while true do
local from, to, capture, err = re_split_helper(subj, compiled,
compile_once, flags, ctx)
if err then
return nil, err
end
if not from then
break
end
if last_empty_match then
sub_idx = last_empty_match
end
if from == to then
last_empty_match = from
end
if from > sub_idx or not last_empty_match then
res_idx = res_idx + 1
res[res_idx] = sub(subj, sub_idx, from - 1)
if capture then
res_idx = res_idx + 1
res[res_idx] = capture
end
sub_idx = to
if sub_idx > len then
break
end
end
end
end
if not compile_once then
destroy_compiled_regex(compiled)
end
-- trailing nil for non-cleared res tables
-- delete empty trailing ones (without max)
if max <= 0 and sub_idx > len then
for ety_idx = res_idx, 1, -1 do
if res[ety_idx] ~= "" then
res_idx = ety_idx
break
end
res[ety_idx] = nil
end
else
res_idx = res_idx + 1
res[res_idx] = sub(subj, sub_idx)
end
res[res_idx + 1] = nil
return res
end
function _M.opt(option, value)
if option == "jit_stack_size" then
if not is_regex_cache_empty() then
error("changing jit stack size is not allowed when some " ..
"regexs have already been compiled and cached", 2)
end
local errbuf = get_string_buf(MAX_ERR_MSG_LEN)
local sizep = get_size_ptr()
sizep[0] = MAX_ERR_MSG_LEN
local rc = ngx_lua_ffi_set_jit_stack_size(value, errbuf, sizep)
if rc == FFI_OK then
return
end
error(ffi_str(errbuf, sizep[0]), 2)
end
error("unrecognized option name", 2)
end
return _M
Name
====
ngx.re - Lua API for convenience utilities for `ngx.re`.
Table of Contents
=================
* [Name](#name)
* [Status](#status)
* [Synopsis](#synopsis)
* [Description](#description)
* [Methods](#methods)
* [split](#split)
* [opt](#opt)
* [Community](#community)
* [English Mailing List](#english-mailing-list)
* [Chinese Mailing List](#chinese-mailing-list)
* [Bugs and Patches](#bugs-and-patches)
* [Author](#author)
* [Copyright and License](#copyright-and-license)
* [See Also](#see-also)
Status
======
This Lua module is currently considered experimental.
Synopsis
========
```lua
local ngx_re = require "ngx.re"
-- split
local res, err = ngx_re.split("a,b,c,d", ",")
--> res is now {"a", "b", "c", "d"}
-- opt
ngx_re.opt("jit_stack_size", 128 * 1024)
--> the PCRE jit stack can now handle more complex regular expressions
```
[Back to TOC](#table-of-contents)
Description
===========
This Lua module provides a Lua API which implements convenience utilities for
the `ngx.re` API.
[Back to TOC](#table-of-contents)
Methods
=======
All the methods of this module are static (or module-level). That is, you do
not need an object (or instance) to call these methods.
[Back to TOC](#table-of-contents)
split
-----
**syntax:** *res, err = ngx_re.split(subject, regex, options?, ctx?, max?, res?)*
Splits the `subject` string using the Perl compatible regular expression
`regex` with the optional `options`.
This function returns a Lua (array) table (with integer keys) containing the
split values.
In case of error, `nil` will be returned as well as a string describing the
error.
When `regex` contains a sub-match capturing group, and when such a match is
found, the first submatch capture will be inserted in between each split
value, like so:
```lua
local ngx_re = require "ngx.re"
local res, err = ngx_re.split("a,b,c,d", "(,)")
-- res is now {"a", ",", "b", ",", "c", ",", "d"}
```
When `regex` is empty string `""`, the `subject` will be split into chars,
like so:
```lua
local ngx_re = require "ngx.re"
local res, err = ngx_re.split("abcd", "")
-- res is now {"a", "b", "c", "d"}
```
The optional `ctx` table argument can be a Lua table holding an optional `pos`
field. When the `pos` field in the `ctx` table argument is specified,
`ngx_re.split` will start splitting the `subject` from that index:
```lua
local ngx_re = require "ngx.re"
local res, err = ngx_re.split("a,b,c,d", ",", nil, {pos = 5})
-- res is now {"c", "d"}
```
The optional `max` argument is a number that when specified, will prevent
`ngx_re.split` from adding more than `max` matches to the `res` array:
```lua
local ngx_re = require "ngx.re"
local res, err = ngx_re.split("a,b,c,d", ",", nil, nil, 3)
-- res is now {"a", "b", "c,d"}
```
Specifying `max <= 0` disables this behavior, meaning that the number of
results won't be limited.
The optional 6th argument `res` can be a table that `ngx_re.split` will re-use
to hold the results instead of creating a new one, which can improve
performance in hot code paths. It is used like so:
```lua
local ngx_re = require "ngx.re"
local my_table = {"hello world"}
local res, err = ngx_re.split("a,b,c,d", ",", nil, nil, nil, my_table)
-- res/my_table is now {"a", "b", "c", "d"}
```
When provided with a `res` table, `ngx_re.split` won't clear the table
for performance reasons, but will rather insert a trailing `nil` value
when the split is completed:
```lua
local ngx_re = require "ngx.re"
local my_table = {"W", "X", "Y", "Z"}
local res, err = ngx_re.split("a,b", ",", nil, nil, nil, my_table)
-- res/my_table is now {"a", "b", nil, "Z"}
```
When the trailing `nil` is not enough for your purpose, you should
clear the table yourself before feeding it into the `split` function.
[Back to TOC](#table-of-contents)
opt
-----
**syntax:** *ngx_re.opt(option, value)*
Allows changing of regex settings. Currently, it can only change the
`jit_stack_size` of the PCRE engine, like so:
```nginx
init_by_lua_block { require "ngx.re".opt("jit_stack_size", 200 * 1024) }
server {
location /re {
content_by_lua_block {
-- full regex and string are taken from https://github.com/JuliaLang/julia/issues/8278
local very_long_string = [[71.163.72.113 - - [30/Jul/2014:16:40:55 -0700] ...]]
local very_complicated_regex = [[([\d\.]+) ([\w.-]+) ([\w.-]+) (\[.+\]) ...]]
local from, to, err = ngx.re.find(very_long_string, very_complicated_regex, "jo")
-- with the regular jit_stack_size, we would get the error 'pcre_exec() failed: -27'
-- instead, we get a match
ngx.print(from .. "-" .. to) -- prints '1-1563'
}
}
}
```
The `jit_stack_size` cannot be set to a value lower than PCRE's default of 32K.
This method requires the PCRE library enabled in Nginx.
This feature was first introduced in the `v0.1.12` release.
[Back to TOC](#table-of-contents)
Community
=========
[Back to TOC](#table-of-contents)
English Mailing List
--------------------
The [openresty-en](https://groups.google.com/group/openresty-en) mailing list
is for English speakers.
[Back to TOC](#table-of-contents)
Chinese Mailing List
--------------------
The [openresty](https://groups.google.com/group/openresty) mailing list is for
Chinese speakers.
[Back to TOC](#table-of-contents)
Bugs and Patches
================
Please report bugs or submit patches by
1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues),
1. or posting to the [OpenResty community](#community).
[Back to TOC](#table-of-contents)
Author
======
Thibault Charbonnier - ([@thibaultcha](https://github.com/thibaultcha))
[Back to TOC](#table-of-contents)
Copyright and License
=====================
This module is licensed under the BSD license.
Copyright (C) 2016-2017, by Yichun "agentzh" Zhang, OpenResty Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[Back to TOC](#table-of-contents)
See Also
========
* the [lua-resty-core](https://github.com/openresty/lua-resty-core) library.
* the ngx_lua module: https://github.com/openresty/lua-nginx-module
* OpenResty: https://openresty.org
[Back to TOC](#table-of-contents)
-- Copyright (C) by OpenResty Inc.
local base = require "resty.core.base"
base.allows_subsystem("http")
local core_request = require "resty.core.request"
local set_req_header = core_request.set_req_header
local _M = { version = base.version }
function _M.add_header(key, value)
set_req_header(key, value, false)
end
return _M
Name
====
ngx.req - Lua API for HTTP request handling.
Table of Contents
=================
* [Name](#name)
* [Status](#status)
* [Synopsis](#synopsis)
* [Description](#description)
* [Methods](#methods)
* [add_header](#add_header)
* [Community](#community)
* [English Mailing List](#english-mailing-list)
* [Chinese Mailing List](#chinese-mailing-list)
* [Bugs and Patches](#bugs-and-patches)
* [Copyright and License](#copyright-and-license)
* [See Also](#see-also)
Status
======
This Lua module is currently considered experimental.
Synopsis
========
```lua
local ngx_req = require "ngx.req"
-- add_header
ngx_req.add_header("Foo", "bar")
ngx_req.add_header("Foo", "baz")
--> there will be two new headers in the HTTP request:
--> Foo: bar and Foo: baz
```
[Back to TOC](#table-of-contents)
Description
===========
This module provides a Lua API to handle HTTP requests.
[Back to TOC](#table-of-contents)
Methods
=======
All methods provided by this module are static (or module-level). That is, you
do not need an object (or instance) to call these methods.
[Back to TOC](#table-of-contents)
add_header
----------
**syntax:** *ngx_req.add_header(header_name, header_value)*
**context:** *set_by_lua&#42;, rewrite_by_lua&#42;, access_by_lua&#42;, content_by_lua&#42;, header_filter_by_lua&#42;, body_filter_by_lua&#42;*
This method adds the specified header and its value to the current
request. It works similarly as
[ngx.req.set_header](https://github.com/openresty/lua-nginx-module#ngxreqset_header),
with the exception that when the header already exists, the specified value(s)
will be appended instead of overriden.
The first argument `header_name` must be a non-empty string.
When the specified `header_name` is a builtin header (e.g. `User-Agent`), this
method will override its values.
The `header_value` argument can either be a string or a non-empty, array-like
table. A `nil` or empty table value will cause this function to throw an error.
This feature was first introduced in the `v0.1.18` release.
[Back to TOC](#table-of-contents)
Community
=========
[Back to TOC](#table-of-contents)
English Mailing List
--------------------
The [openresty-en](https://groups.google.com/group/openresty-en) mailing list
is for English speakers.
[Back to TOC](#table-of-contents)
Chinese Mailing List
--------------------
The [openresty](https://groups.google.com/group/openresty) mailing list is for
Chinese speakers.
[Back to TOC](#table-of-contents)
Bugs and Patches
================
Please report bugs or submit patches by
1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues),
1. or posting to the [OpenResty community](#community).
[Back to TOC](#table-of-contents)
Copyright and License
=====================
This module is licensed under the BSD license.
Copyright (C) 2016-2019, by Yichun "agentzh" Zhang, OpenResty Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[Back to TOC](#table-of-contents)
See Also
========
* library [lua-resty-core](https://github.com/openresty/lua-resty-core)
* the ngx_lua module: https://github.com/openresty/lua-nginx-module
* OpenResty: https://openresty.org
[Back to TOC](#table-of-contents)
-- Copyright (C) Yichun Zhang. All rights reserved.
local base = require "resty.core.base"
base.allows_subsystem('http')
local core_response = require "resty.core.response"
local set_resp_header = core_response.set_resp_header
local _M = { version = base.version }
function _M.add_header(key, value)
set_resp_header(nil, key, value, true)
end
return _M
Name
====
ngx.resp - Lua API for HTTP response handling.
Table of Contents
=================
* [Name](#name)
* [Status](#status)
* [Synopsis](#synopsis)
* [Description](#description)
* [Methods](#methods)
* [add_header](#add_header)
* [Community](#community)
* [English Mailing List](#english-mailing-list)
* [Chinese Mailing List](#chinese-mailing-list)
* [Bugs and Patches](#bugs-and-patches)
* [Copyright and License](#copyright-and-license)
* [See Also](#see-also)
Status
======
This Lua module is currently considered experimental.
Synopsis
========
```lua
local ngx_resp = require "ngx.resp"
-- add_header
ngx_resp.add_header("Foo", "bar")
ngx_resp.add_header("Foo", "baz")
--> there will be two new headers in HTTP response:
--> Foo: bar and Foo: baz
```
[Back to TOC](#table-of-contents)
Description
===========
This Lua module provides Lua API which could be used to handle HTTP response.
[Back to TOC](#table-of-contents)
Methods
=======
All the methods of this module are static (or module-level). That is, you do
not need an object (or instance) to call these methods.
[Back to TOC](#table-of-contents)
add_header
----------
**syntax:** *ngx_resp.add_header(header_name, header_value)*
This function adds specified header with corresponding value to the response of
current request. The `header_value` could be either a string or a table.
The `ngx.resp.add_header` works mostly like:
* [ngx.header.HEADER](https://github.com/openresty/lua-nginx-module#ngxheaderheader)
* Nginx's [add_header](http://nginx.org/en/docs/http/ngx_http_headers_module.html#add_header) directive.
However, unlike `ngx.header.HEADER`, this method appends new header to the old
one instead of overriding it.
Unlike `add_header` directive, this method will override the builtin header
instead of appending it.
[Back to TOC](#table-of-contents)
Community
=========
[Back to TOC](#table-of-contents)
English Mailing List
--------------------
The [openresty-en](https://groups.google.com/group/openresty-en) mailing list
is for English speakers.
[Back to TOC](#table-of-contents)
Chinese Mailing List
--------------------
The [openresty](https://groups.google.com/group/openresty) mailing list is for
Chinese speakers.
[Back to TOC](#table-of-contents)
Bugs and Patches
================
Please report bugs or submit patches by
1. creating a ticket on the [GitHub Issue Tracker](https://github.com/openresty/lua-resty-core/issues),
1. or posting to the [OpenResty community](#community).
[Back to TOC](#table-of-contents)
Copyright and License
=====================
This module is licensed under the BSD license.
Copyright (C) 2018, by Yichun "agentzh" Zhang, OpenResty Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[Back to TOC](#table-of-contents)
See Also
========
* the [lua-resty-core](https://github.com/openresty/lua-resty-core) library.
* the ngx_lua module: https://github.com/openresty/lua-nginx-module
* OpenResty: https://openresty.org
[Back to TOC](#table-of-contents)
-- Copyright (C) Yichun Zhang (agentzh)
-- Copyright (C) cuiweixie
-- I hereby assign copyright in this code to the lua-resty-core project,
-- to be licensed under the same terms as the rest of the code.
local base = require "resty.core.base"
base.allows_subsystem('http', 'stream')
local ffi = require 'ffi'
local FFI_OK = base.FFI_OK
local FFI_ERROR = base.FFI_ERROR
local FFI_DECLINED = base.FFI_DECLINED
local ffi_new = ffi.new
local ffi_str = ffi.string
local ffi_gc = ffi.gc
local C = ffi.C
local type = type
local error = error
local tonumber = tonumber
local get_request = base.get_request
local get_string_buf = base.get_string_buf
local get_size_ptr = base.get_size_ptr
local setmetatable = setmetatable
local co_yield = coroutine._yield
local ERR_BUF_SIZE = 128
local subsystem = ngx.config.subsystem
local errmsg = base.get_errmsg_ptr()
local psem
local ngx_lua_ffi_sema_new
local ngx_lua_ffi_sema_post
local ngx_lua_ffi_sema_count
local ngx_lua_ffi_sema_wait
local ngx_lua_ffi_sema_gc
if subsystem == 'http' then
ffi.cdef[[
struct ngx_http_lua_sema_s;
typedef struct ngx_http_lua_sema_s ngx_http_lua_sema_t;
int ngx_http_lua_ffi_sema_new(ngx_http_lua_sema_t **psem,
int n, char **errmsg);
int ngx_http_lua_ffi_sema_post(ngx_http_lua_sema_t *sem, int n);
int ngx_http_lua_ffi_sema_count(ngx_http_lua_sema_t *sem);
int ngx_http_lua_ffi_sema_wait(ngx_http_request_t *r,
ngx_http_lua_sema_t *sem, int wait_ms,
unsigned char *errstr, size_t *errlen);
void ngx_http_lua_ffi_sema_gc(ngx_http_lua_sema_t *sem);
]]
psem = ffi_new("ngx_http_lua_sema_t *[1]")
ngx_lua_ffi_sema_new = C.ngx_http_lua_ffi_sema_new
ngx_lua_ffi_sema_post = C.ngx_http_lua_ffi_sema_post
ngx_lua_ffi_sema_count = C.ngx_http_lua_ffi_sema_count
ngx_lua_ffi_sema_wait = C.ngx_http_lua_ffi_sema_wait
ngx_lua_ffi_sema_gc = C.ngx_http_lua_ffi_sema_gc
elseif subsystem == 'stream' then
ffi.cdef[[
struct ngx_stream_lua_sema_s;
typedef struct ngx_stream_lua_sema_s ngx_stream_lua_sema_t;
int ngx_stream_lua_ffi_sema_new(ngx_stream_lua_sema_t **psem,
int n, char **errmsg);
int ngx_stream_lua_ffi_sema_post(ngx_stream_lua_sema_t *sem, int n);
int ngx_stream_lua_ffi_sema_count(ngx_stream_lua_sema_t *sem);
int ngx_stream_lua_ffi_sema_wait(ngx_stream_lua_request_t *r,
ngx_stream_lua_sema_t *sem, int wait_ms,
unsigned char *errstr, size_t *errlen);
void ngx_stream_lua_ffi_sema_gc(ngx_stream_lua_sema_t *sem);
]]
psem = ffi_new("ngx_stream_lua_sema_t *[1]")
ngx_lua_ffi_sema_new = C.ngx_stream_lua_ffi_sema_new
ngx_lua_ffi_sema_post = C.ngx_stream_lua_ffi_sema_post
ngx_lua_ffi_sema_count = C.ngx_stream_lua_ffi_sema_count
ngx_lua_ffi_sema_wait = C.ngx_stream_lua_ffi_sema_wait
ngx_lua_ffi_sema_gc = C.ngx_stream_lua_ffi_sema_gc
end
local _M = { version = base.version }
local mt = { __index = _M }
function _M.new(n)
n = tonumber(n) or 0
if n < 0 then
error("no negative number", 2)
end
local ret = ngx_lua_ffi_sema_new(psem, n, errmsg)
if ret == FFI_ERROR then
return nil, ffi_str(errmsg[0])
end
local sem = psem[0]
ffi_gc(sem, ngx_lua_ffi_sema_gc)
return setmetatable({ sem = sem }, mt)
end
function _M.wait(self, seconds)
if type(self) ~= "table" or type(self.sem) ~= "cdata" then
error("not a semaphore instance", 2)
end
local r = get_request()
if not r then
error("no request found")
end
local milliseconds = tonumber(seconds) * 1000
if milliseconds < 0 then
error("no negative number", 2)
end
local cdata_sem = self.sem
local err = get_string_buf(ERR_BUF_SIZE)
local errlen = get_size_ptr()
errlen[0] = ERR_BUF_SIZE
local ret = ngx_lua_ffi_sema_wait(r, cdata_sem,
milliseconds, err, errlen)
if ret == FFI_ERROR then
return nil, ffi_str(err, errlen[0])
end
if ret == FFI_OK then
return true
end
if ret == FFI_DECLINED then
return nil, "timeout"
end
-- Note: we cannot use the tail-call form here since we
-- might need the current function call's activation
-- record to hold the reference to our semaphore object
-- to prevent it from getting GC'd prematurely.
local ok
ok, err = co_yield()
return ok, err
end
function _M.post(self, n)
if type(self) ~= "table" or type(self.sem) ~= "cdata" then
error("not a semaphore instance", 2)
end
local cdata_sem = self.sem
local num = n and tonumber(n) or 1
if num < 1 then
error("positive number required", 2)
end
-- always return NGX_OK
ngx_lua_ffi_sema_post(cdata_sem, num)
return true
end
function _M.count(self)
if type(self) ~= "table" or type(self.sem) ~= "cdata" then
error("not a semaphore instance", 2)
end
return ngx_lua_ffi_sema_count(self.sem)
end
return _M
-- Copyright (C) Yichun Zhang (agentzh)
local base = require "resty.core.base"
base.allows_subsystem('http')
local ffi = require "ffi"
local C = ffi.C
local ffi_str = ffi.string
local get_request = base.get_request
local error = error
local errmsg = base.get_errmsg_ptr()
local get_string_buf = base.get_string_buf
local FFI_ERROR = base.FFI_ERROR
ffi.cdef[[
int ngx_http_lua_ffi_ssl_set_serialized_session(ngx_http_request_t *r,
const unsigned char *buf, int len, char **err);
int ngx_http_lua_ffi_ssl_get_serialized_session(ngx_http_request_t *r,
char *buf, char **err);
int ngx_http_lua_ffi_ssl_get_session_id(ngx_http_request_t *r,
char *buf, char **err);
int ngx_http_lua_ffi_ssl_get_serialized_session_size(ngx_http_request_t *r,
char **err);
int ngx_http_lua_ffi_ssl_get_session_id_size(ngx_http_request_t *r,
char **err);
]]
local _M = { version = base.version }
-- return session, err
function _M.get_serialized_session()
local r = get_request()
if not r then
error("no request found")
end
local len = C.ngx_http_lua_ffi_ssl_get_serialized_session_size(r, errmsg)
if len < 0 then
return nil, ffi_str(errmsg[0])
end
if len > 4096 then
return nil, "session too big to serialize"
end
local buf = get_string_buf(len)
local rc = C.ngx_http_lua_ffi_ssl_get_serialized_session(r, buf, errmsg)
if rc == FFI_ERROR then
return nil, ffi_str(errmsg[0])
end
return ffi_str(buf, len)
end
-- return session_id, err
function _M.get_session_id()
local r = get_request()
if not r then
error("no request found")
end
local len = C.ngx_http_lua_ffi_ssl_get_session_id_size(r, errmsg)
if len < 0 then
return nil, ffi_str(errmsg[0])
end
local buf = get_string_buf(len)
local rc = C.ngx_http_lua_ffi_ssl_get_session_id(r, buf, errmsg)
if rc == FFI_ERROR then
return nil, ffi_str(errmsg[0])
end
return ffi_str(buf, len)
end
-- return ok, err
function _M.set_serialized_session(sess)
local r = get_request()
if not r then
error("no request found")
end
local rc = C.ngx_http_lua_ffi_ssl_set_serialized_session(r, sess, #sess,
errmsg)
if rc == FFI_ERROR then
return nil, ffi_str(errmsg[0])
end
return true
end
return _M
-- Copyright (C) Yichun Zhang (agentzh)
local subsystem = ngx.config.subsystem
require "resty.core.var"
require "resty.core.worker"
require "resty.core.regex"
require "resty.core.shdict"
require "resty.core.time"
require "resty.core.hash"
require "resty.core.uri"
require "resty.core.exit"
require "resty.core.base64"
if subsystem == 'http' then
require "resty.core.request"
require "resty.core.response"
require "resty.core.phase"
require "resty.core.ndk"
end
require "resty.core.misc"
require "resty.core.ctx"
local base = require "resty.core.base"
return {
version = base.version
}
-- Copyright (C) Yichun Zhang (agentzh)
local ffi = require 'ffi'
local ffi_new = ffi.new
local error = error
local select = select
local ceil = math.ceil
local subsystem = ngx.config.subsystem
local str_buf_size = 4096
local str_buf
local size_ptr
local FREE_LIST_REF = 0
if subsystem == 'http' then
if not ngx.config
or not ngx.config.ngx_lua_version
or ngx.config.ngx_lua_version ~= 10016
then
error("ngx_http_lua_module 0.10.16 required")
end
elseif subsystem == 'stream' then
if not ngx.config
or not ngx.config.ngx_lua_version
or ngx.config.ngx_lua_version ~= 8
then
error("ngx_stream_lua_module 0.0.8 required")
end
else
error("ngx_http_lua_module 0.10.16 or "
.. "ngx_stream_lua_module 0.0.8 required")
end
if string.find(jit.version, " 2.0", 1, true) then
ngx.log(ngx.ALERT, "use of lua-resty-core with LuaJIT 2.0 is ",
"not recommended; use LuaJIT 2.1+ instead")
end
local ok, new_tab = pcall(require, "table.new")
if not ok then
new_tab = function (narr, nrec) return {} end
end
local clear_tab
ok, clear_tab = pcall(require, "table.clear")
if not ok then
local pairs = pairs
clear_tab = function (tab)
for k, _ in pairs(tab) do
tab[k] = nil
end
end
end
-- XXX for now LuaJIT 2.1 cannot compile require()
-- so we make the fast code path Lua only in our own
-- wrapper so that most of the require() calls in hot
-- Lua code paths can be JIT compiled.
do
local orig_require = require
local pkg_loaded = package.loaded
local function my_require(name)
local mod = pkg_loaded[name]
if mod then
return mod
end
return orig_require(name)
end
getfenv(0).require = my_require
end
if not pcall(ffi.typeof, "ngx_str_t") then
ffi.cdef[[
typedef struct {
size_t len;
const unsigned char *data;
} ngx_str_t;
]]
end
if subsystem == 'http' then
if not pcall(ffi.typeof, "ngx_http_request_t") then
ffi.cdef[[
typedef struct ngx_http_request_s ngx_http_request_t;
]]
end
if not pcall(ffi.typeof, "ngx_http_lua_ffi_str_t") then
ffi.cdef[[
typedef struct {
int len;
const unsigned char *data;
} ngx_http_lua_ffi_str_t;
]]
end
elseif subsystem == 'stream' then
if not pcall(ffi.typeof, "ngx_stream_lua_request_t") then
ffi.cdef[[
typedef struct ngx_stream_lua_request_s ngx_stream_lua_request_t;
]]
end
if not pcall(ffi.typeof, "ngx_stream_lua_ffi_str_t") then
ffi.cdef[[
typedef struct {
int len;
const unsigned char *data;
} ngx_stream_lua_ffi_str_t;
]]
end
else
error("unknown subsystem: " .. subsystem)
end
local c_buf_type = ffi.typeof("char[?]")
local _M = new_tab(0, 18)
_M.version = "0.1.18"
_M.new_tab = new_tab
_M.clear_tab = clear_tab
local errmsg
function _M.get_errmsg_ptr()
if not errmsg then
errmsg = ffi_new("char *[1]")
end
return errmsg
end
if not ngx then
error("no existing ngx. table found")
end
function _M.set_string_buf_size(size)
if size <= 0 then
return
end
if str_buf then
str_buf = nil
end
str_buf_size = ceil(size)
end
function _M.get_string_buf_size()
return str_buf_size
end
function _M.get_size_ptr()
if not size_ptr then
size_ptr = ffi_new("size_t[1]")
end
return size_ptr
end
function _M.get_string_buf(size, must_alloc)
-- ngx.log(ngx.ERR, "str buf size: ", str_buf_size)
if size > str_buf_size or must_alloc then
return ffi_new(c_buf_type, size)
end
if not str_buf then
str_buf = ffi_new(c_buf_type, str_buf_size)
end
return str_buf
end
function _M.ref_in_table(tb, key)
if key == nil then
return -1
end
local ref = tb[FREE_LIST_REF]
if ref and ref ~= 0 then
tb[FREE_LIST_REF] = tb[ref]
else
ref = #tb + 1
end
tb[ref] = key
-- print("ref key_id returned ", ref)
return ref
end
function _M.allows_subsystem(...)
local total = select("#", ...)
for i = 1, total do
if select(i, ...) == subsystem then
return
end
end
error("unsupported subsystem: " .. subsystem, 2)
end
_M.FFI_OK = 0
_M.FFI_NO_REQ_CTX = -100
_M.FFI_BAD_CONTEXT = -101
_M.FFI_ERROR = -1
_M.FFI_AGAIN = -2
_M.FFI_BUSY = -3
_M.FFI_DONE = -4
_M.FFI_DECLINED = -5
do
local exdata
ok, exdata = pcall(require, "thread.exdata")
if ok and exdata then
function _M.get_request()
local r = exdata()
if r ~= nil then
return r
end
end
else
local getfenv = getfenv
function _M.get_request()
return getfenv(0).__ngx_req
end
end
end
return _M
-- Copyright (C) Yichun Zhang (agentzh)
local ffi = require "ffi"
local base = require "resty.core.base"
local C = ffi.C
local ffi_string = ffi.string
local ngx = ngx
local type = type
local error = error
local floor = math.floor
local tostring = tostring
local get_string_buf = base.get_string_buf
local get_size_ptr = base.get_size_ptr
local subsystem = ngx.config.subsystem
local ngx_lua_ffi_encode_base64
local ngx_lua_ffi_decode_base64
if subsystem == "http" then
ffi.cdef[[
size_t ngx_http_lua_ffi_encode_base64(const unsigned char *src,
size_t len, unsigned char *dst,
int no_padding);
int ngx_http_lua_ffi_decode_base64(const unsigned char *src,
size_t len, unsigned char *dst,
size_t *dlen);
]]
ngx_lua_ffi_encode_base64 = C.ngx_http_lua_ffi_encode_base64
ngx_lua_ffi_decode_base64 = C.ngx_http_lua_ffi_decode_base64
elseif subsystem == "stream" then
ffi.cdef[[
size_t ngx_stream_lua_ffi_encode_base64(const unsigned char *src,
size_t len, unsigned char *dst,
int no_padding);
int ngx_stream_lua_ffi_decode_base64(const unsigned char *src,
size_t len, unsigned char *dst,
size_t *dlen);
]]
ngx_lua_ffi_encode_base64 = C.ngx_stream_lua_ffi_encode_base64
ngx_lua_ffi_decode_base64 = C.ngx_stream_lua_ffi_decode_base64
end
local function base64_encoded_length(len, no_padding)
return no_padding and floor((len * 8 + 5) / 6) or
floor((len + 2) / 3) * 4
end
ngx.encode_base64 = function (s, no_padding)
if type(s) ~= 'string' then
if not s then
s = ''
else
s = tostring(s)
end
end
local slen = #s
local no_padding_bool = false;
local no_padding_int = 0;
if no_padding then
if no_padding ~= true then
local typ = type(no_padding)
error("bad no_padding: boolean expected, got " .. typ, 2)
end
no_padding_bool = true
no_padding_int = 1;
end
local dlen = base64_encoded_length(slen, no_padding_bool)
local dst = get_string_buf(dlen)
local r_dlen = ngx_lua_ffi_encode_base64(s, slen, dst, no_padding_int)
-- if dlen ~= r_dlen then error("discrepancy in len") end
return ffi_string(dst, r_dlen)
end
local function base64_decoded_length(len)
return floor((len + 3) / 4) * 3
end
ngx.decode_base64 = function (s)
if type(s) ~= 'string' then
error("string argument only", 2)
end
local slen = #s
local dlen = base64_decoded_length(slen)
-- print("dlen: ", tonumber(dlen))
local dst = get_string_buf(dlen)
local pdlen = get_size_ptr()
local ok = ngx_lua_ffi_decode_base64(s, slen, dst, pdlen)
if ok == 0 then
return nil
end
return ffi_string(dst, pdlen[0])
end
return {
version = base.version
}
-- Copyright (C) Yichun Zhang (agentzh)
local ffi = require "ffi"
local debug = require "debug"
local base = require "resty.core.base"
local misc = require "resty.core.misc"
local C = ffi.C
local register_getter = misc.register_ngx_magic_key_getter
local register_setter = misc.register_ngx_magic_key_setter
local registry = debug.getregistry()
local new_tab = base.new_tab
local ref_in_table = base.ref_in_table
local get_request = base.get_request
local FFI_NO_REQ_CTX = base.FFI_NO_REQ_CTX
local FFI_OK = base.FFI_OK
local error = error
local subsystem = ngx.config.subsystem
local ngx_lua_ffi_get_ctx_ref
local ngx_lua_ffi_set_ctx_ref
if subsystem == "http" then
ffi.cdef[[
int ngx_http_lua_ffi_get_ctx_ref(ngx_http_request_t *r);
int ngx_http_lua_ffi_set_ctx_ref(ngx_http_request_t *r, int ref);
]]
ngx_lua_ffi_get_ctx_ref = C.ngx_http_lua_ffi_get_ctx_ref
ngx_lua_ffi_set_ctx_ref = C.ngx_http_lua_ffi_set_ctx_ref
elseif subsystem == "stream" then
ffi.cdef[[
int ngx_stream_lua_ffi_get_ctx_ref(ngx_stream_lua_request_t *r);
int ngx_stream_lua_ffi_set_ctx_ref(ngx_stream_lua_request_t *r, int ref);
]]
ngx_lua_ffi_get_ctx_ref = C.ngx_stream_lua_ffi_get_ctx_ref
ngx_lua_ffi_set_ctx_ref = C.ngx_stream_lua_ffi_set_ctx_ref
end
local _M = {
_VERSION = base.version
}
local function get_ctx_table()
local r = get_request()
if not r then
error("no request found")
end
local ctx_ref = ngx_lua_ffi_get_ctx_ref(r)
if ctx_ref == FFI_NO_REQ_CTX then
error("no request ctx found")
end
local ctxs = registry.ngx_lua_ctx_tables
if ctx_ref < 0 then
local ctx = new_tab(0, 4)
ctx_ref = ref_in_table(ctxs, ctx)
if ngx_lua_ffi_set_ctx_ref(r, ctx_ref) ~= FFI_OK then
return nil
end
return ctx
end
return ctxs[ctx_ref]
end
register_getter("ctx", get_ctx_table)
local function set_ctx_table(ctx)
local r = get_request()
if not r then
error("no request found")
end
local ctx_ref = ngx_lua_ffi_get_ctx_ref(r)
if ctx_ref == FFI_NO_REQ_CTX then
error("no request ctx found")
end
local ctxs = registry.ngx_lua_ctx_tables
if ctx_ref < 0 then
ctx_ref = ref_in_table(ctxs, ctx)
ngx_lua_ffi_set_ctx_ref(r, ctx_ref)
return
end
ctxs[ctx_ref] = ctx
end
register_setter("ctx", set_ctx_table)
return _M
-- Copyright (C) Yichun Zhang (agentzh)
local ffi = require "ffi"
local base = require "resty.core.base"
local C = ffi.C
local ffi_string = ffi.string
local ngx = ngx
local error = error
local get_string_buf = base.get_string_buf
local get_size_ptr = base.get_size_ptr
local get_request = base.get_request
local co_yield = coroutine._yield
local subsystem = ngx.config.subsystem
local ngx_lua_ffi_exit
if subsystem == "http" then
ffi.cdef[[
int ngx_http_lua_ffi_exit(ngx_http_request_t *r, int status,
unsigned char *err, size_t *errlen);
]]
ngx_lua_ffi_exit = C.ngx_http_lua_ffi_exit
elseif subsystem == "stream" then
ffi.cdef[[
int ngx_stream_lua_ffi_exit(ngx_stream_lua_request_t *r, int status,
unsigned char *err, size_t *errlen);
]]
ngx_lua_ffi_exit = C.ngx_stream_lua_ffi_exit
end
local ERR_BUF_SIZE = 128
local FFI_DONE = base.FFI_DONE
ngx.exit = function (rc)
local err = get_string_buf(ERR_BUF_SIZE)
local errlen = get_size_ptr()
local r = get_request()
if r == nil then
error("no request found")
end
errlen[0] = ERR_BUF_SIZE
rc = ngx_lua_ffi_exit(r, rc, err, errlen)
if rc == 0 then
-- print("yielding...")
return co_yield()
end
if rc == FFI_DONE then
return
end
error(ffi_string(err, errlen[0]), 2)
end
return {
version = base.version
}
-- Copyright (C) Yichun Zhang (agentzh)
local ffi = require "ffi"
local base = require "resty.core.base"
local C = ffi.C
local ffi_new = ffi.new
local ffi_string = ffi.string
local ngx = ngx
local type = type
local error = error
local tostring = tostring
local subsystem = ngx.config.subsystem
local ngx_lua_ffi_md5
local ngx_lua_ffi_md5_bin
local ngx_lua_ffi_sha1_bin
local ngx_lua_ffi_crc32_long
local ngx_lua_ffi_crc32_short
if subsystem == "http" then
ffi.cdef[[
void ngx_http_lua_ffi_md5_bin(const unsigned char *src, size_t len,
unsigned char *dst);
void ngx_http_lua_ffi_md5(const unsigned char *src, size_t len,
unsigned char *dst);
int ngx_http_lua_ffi_sha1_bin(const unsigned char *src, size_t len,
unsigned char *dst);
unsigned int ngx_http_lua_ffi_crc32_long(const unsigned char *src,
size_t len);
unsigned int ngx_http_lua_ffi_crc32_short(const unsigned char *src,
size_t len);
]]
ngx_lua_ffi_md5 = C.ngx_http_lua_ffi_md5
ngx_lua_ffi_md5_bin = C.ngx_http_lua_ffi_md5_bin
ngx_lua_ffi_sha1_bin = C.ngx_http_lua_ffi_sha1_bin
ngx_lua_ffi_crc32_short = C.ngx_http_lua_ffi_crc32_short
ngx_lua_ffi_crc32_long = C.ngx_http_lua_ffi_crc32_long
elseif subsystem == "stream" then
ffi.cdef[[
void ngx_stream_lua_ffi_md5_bin(const unsigned char *src, size_t len,
unsigned char *dst);
void ngx_stream_lua_ffi_md5(const unsigned char *src, size_t len,
unsigned char *dst);
int ngx_stream_lua_ffi_sha1_bin(const unsigned char *src, size_t len,
unsigned char *dst);
unsigned int ngx_stream_lua_ffi_crc32_long(const unsigned char *src,
size_t len);
unsigned int ngx_stream_lua_ffi_crc32_short(const unsigned char *src,
size_t len);
]]
ngx_lua_ffi_md5 = C.ngx_stream_lua_ffi_md5
ngx_lua_ffi_md5_bin = C.ngx_stream_lua_ffi_md5_bin
ngx_lua_ffi_sha1_bin = C.ngx_stream_lua_ffi_sha1_bin
ngx_lua_ffi_crc32_short = C.ngx_stream_lua_ffi_crc32_short
ngx_lua_ffi_crc32_long = C.ngx_stream_lua_ffi_crc32_long
end
local MD5_DIGEST_LEN = 16
local md5_buf = ffi_new("unsigned char[?]", MD5_DIGEST_LEN)
ngx.md5_bin = function (s)
if type(s) ~= 'string' then
if not s then
s = ''
else
s = tostring(s)
end
end
ngx_lua_ffi_md5_bin(s, #s, md5_buf)
return ffi_string(md5_buf, MD5_DIGEST_LEN)
end
local MD5_HEX_DIGEST_LEN = MD5_DIGEST_LEN * 2
local md5_hex_buf = ffi_new("unsigned char[?]", MD5_HEX_DIGEST_LEN)
ngx.md5 = function (s)
if type(s) ~= 'string' then
if not s then
s = ''
else
s = tostring(s)
end
end
ngx_lua_ffi_md5(s, #s, md5_hex_buf)
return ffi_string(md5_hex_buf, MD5_HEX_DIGEST_LEN)
end
local SHA_DIGEST_LEN = 20
local sha_buf = ffi_new("unsigned char[?]", SHA_DIGEST_LEN)
ngx.sha1_bin = function (s)
if type(s) ~= 'string' then
if not s then
s = ''
else
s = tostring(s)
end
end
local ok = ngx_lua_ffi_sha1_bin(s, #s, sha_buf)
if ok == 0 then
error("SHA-1 support missing in Nginx")
end
return ffi_string(sha_buf, SHA_DIGEST_LEN)
end
ngx.crc32_short = function (s)
if type(s) ~= "string" then
if not s then
s = ""
else
s = tostring(s)
end
end
return ngx_lua_ffi_crc32_short(s, #s)
end
ngx.crc32_long = function (s)
if type(s) ~= "string" then
if not s then
s = ""
else
s = tostring(s)
end
end
return ngx_lua_ffi_crc32_long(s, #s)
end
return {
version = base.version
}
-- Copyright (C) Yichun Zhang (agentzh)
local base = require "resty.core.base"
local ffi = require "ffi"
local os = require "os"
local C = ffi.C
local ffi_new = ffi.new
local ffi_str = ffi.string
local ngx = ngx
local type = type
local error = error
local rawget = rawget
local rawset = rawset
local tonumber = tonumber
local setmetatable = setmetatable
local FFI_OK = base.FFI_OK
local FFI_NO_REQ_CTX = base.FFI_NO_REQ_CTX
local FFI_BAD_CONTEXT = base.FFI_BAD_CONTEXT
local new_tab = base.new_tab
local get_request = base.get_request
local get_size_ptr = base.get_size_ptr
local get_string_buf = base.get_string_buf
local get_string_buf_size = base.get_string_buf_size
local subsystem = ngx.config.subsystem
local ngx_lua_ffi_get_resp_status
local ngx_lua_ffi_get_conf_env
local ngx_magic_key_getters
local ngx_magic_key_setters
local _M = new_tab(0, 3)
local ngx_mt = new_tab(0, 2)
if subsystem == "http" then
ngx_magic_key_getters = new_tab(0, 4)
ngx_magic_key_setters = new_tab(0, 2)
elseif subsystem == "stream" then
ngx_magic_key_getters = new_tab(0, 2)
ngx_magic_key_setters = new_tab(0, 1)
end
local function register_getter(key, func)
ngx_magic_key_getters[key] = func
end
_M.register_ngx_magic_key_getter = register_getter
local function register_setter(key, func)
ngx_magic_key_setters[key] = func
end
_M.register_ngx_magic_key_setter = register_setter
ngx_mt.__index = function (tb, key)
local f = ngx_magic_key_getters[key]
if f then
return f()
end
return rawget(tb, key)
end
ngx_mt.__newindex = function (tb, key, ctx)
local f = ngx_magic_key_setters[key]
if f then
return f(ctx)
end
return rawset(tb, key, ctx)
end
setmetatable(ngx, ngx_mt)
if subsystem == "http" then
ffi.cdef[[
int ngx_http_lua_ffi_get_resp_status(ngx_http_request_t *r);
int ngx_http_lua_ffi_set_resp_status(ngx_http_request_t *r, int r);
int ngx_http_lua_ffi_is_subrequest(ngx_http_request_t *r);
int ngx_http_lua_ffi_headers_sent(ngx_http_request_t *r);
int ngx_http_lua_ffi_get_conf_env(const unsigned char *name,
unsigned char **env_buf,
size_t *name_len);
]]
ngx_lua_ffi_get_resp_status = C.ngx_http_lua_ffi_get_resp_status
ngx_lua_ffi_get_conf_env = C.ngx_http_lua_ffi_get_conf_env
-- ngx.status
local function set_status(status)
local r = get_request()
if not r then
error("no request found")
end
if type(status) ~= 'number' then
status = tonumber(status)
end
local rc = C.ngx_http_lua_ffi_set_resp_status(r, status)
if rc == FFI_BAD_CONTEXT then
error("API disabled in the current context", 2)
end
return
end
register_setter("status", set_status)
-- ngx.is_subrequest
local function is_subreq()
local r = get_request()
if not r then
error("no request found")
end
local rc = C.ngx_http_lua_ffi_is_subrequest(r)
if rc == FFI_BAD_CONTEXT then
error("API disabled in the current context", 2)
end
return rc == 1
end
register_getter("is_subrequest", is_subreq)
-- ngx.headers_sent
local function headers_sent()
local r = get_request()
if not r then
error("no request found")
end
local rc = C.ngx_http_lua_ffi_headers_sent(r)
if rc == FFI_NO_REQ_CTX then
error("no request ctx found")
end
if rc == FFI_BAD_CONTEXT then
error("API disabled in the current context", 2)
end
return rc == 1
end
register_getter("headers_sent", headers_sent)
elseif subsystem == "stream" then
ffi.cdef[[
int ngx_stream_lua_ffi_get_resp_status(ngx_stream_lua_request_t *r);
int ngx_stream_lua_ffi_get_conf_env(const unsigned char *name,
unsigned char **env_buf,
size_t *name_len);
]]
ngx_lua_ffi_get_resp_status = C.ngx_stream_lua_ffi_get_resp_status
ngx_lua_ffi_get_conf_env = C.ngx_stream_lua_ffi_get_conf_env
end
-- ngx.status
local function get_status()
local r = get_request()
if not r then
error("no request found")
end
local rc = ngx_lua_ffi_get_resp_status(r)
if rc == FFI_BAD_CONTEXT then
error("API disabled in the current context", 2)
end
return rc
end
register_getter("status", get_status)
do
local _getenv = os.getenv
local env_ptr = ffi_new("unsigned char *[1]")
os.getenv = function (name)
local r = get_request()
if r then
-- past init_by_lua* phase now
os.getenv = _getenv
env_ptr = nil
return os.getenv(name)
end
local size = get_string_buf_size()
env_ptr[0] = get_string_buf(size)
local name_len_ptr = get_size_ptr()
local rc = ngx_lua_ffi_get_conf_env(name, env_ptr, name_len_ptr)
if rc == FFI_OK then
return ffi_str(env_ptr[0] + name_len_ptr[0] + 1)
end
-- FFI_DECLINED
local value = _getenv(name)
if value ~= nil then
return value
end
return nil
end
end
_M._VERSION = base.version
return _M
-- Copyright (C) by OpenResty Inc.
local ffi = require 'ffi'
local base = require "resty.core.base"
base.allows_subsystem('http')
local C = ffi.C
local ffi_cast = ffi.cast
local ffi_new = ffi.new
local ffi_str = ffi.string
local FFI_OK = base.FFI_OK
local new_tab = base.new_tab
local get_string_buf = base.get_string_buf
local get_request = base.get_request
local setmetatable = setmetatable
local type = type
local tostring = tostring
local error = error
local _M = {
version = base.version
}
ffi.cdef[[
typedef void * ndk_set_var_value_pt;
int ngx_http_lua_ffi_ndk_lookup_directive(const unsigned char *var_data,
size_t var_len, ndk_set_var_value_pt *func);
int ngx_http_lua_ffi_ndk_set_var_get(ngx_http_request_t *r,
ndk_set_var_value_pt func, const unsigned char *arg_data, size_t arg_len,
ngx_http_lua_ffi_str_t *value);
]]
local func_p = ffi_new("void*[1]")
local ffi_str_size = ffi.sizeof("ngx_http_lua_ffi_str_t")
local ffi_str_type = ffi.typeof("ngx_http_lua_ffi_str_t*")
local function ndk_set_var_get(self, var)
if type(var) ~= "string" then
var = tostring(var)
end
if C.ngx_http_lua_ffi_ndk_lookup_directive(var, #var, func_p) ~= FFI_OK then
error('ndk.set_var: directive "' .. var
.. '" not found or does not use ndk_set_var_value', 2)
end
local func = func_p[0]
return function (arg)
local r = get_request()
if not r then
error("no request found")
end
if type(arg) ~= "string" then
arg = tostring(arg)
end
local buf = get_string_buf(ffi_str_size)
local value = ffi_cast(ffi_str_type, buf)
local rc = C.ngx_http_lua_ffi_ndk_set_var_get(r, func, arg, #arg, value)
if rc ~= FFI_OK then
error("calling directive " .. var .. " failed with code " .. rc, 2)
end
return ffi_str(value.data, value.len)
end
end
local function ndk_set_var_set()
error("not allowed", 2)
end
if ndk then
local mt = new_tab(0, 2)
mt.__newindex = ndk_set_var_set
mt.__index = ndk_set_var_get
ndk.set_var = setmetatable(new_tab(0, 0), mt)
end
return _M
local ffi = require 'ffi'
local base = require "resty.core.base"
local C = ffi.C
local FFI_ERROR = base.FFI_ERROR
local get_request = base.get_request
local error = error
local tostring = tostring
ffi.cdef[[
int ngx_http_lua_ffi_get_phase(ngx_http_request_t *r, char **err)
]]
local errmsg = base.get_errmsg_ptr()
local context_names = {
[0x0001] = "set",
[0x0002] = "rewrite",
[0x0004] = "access",
[0x0008] = "content",
[0x0010] = "log",
[0x0020] = "header_filter",
[0x0040] = "body_filter",
[0x0080] = "timer",
[0x0100] = "init_worker",
[0x0200] = "balancer",
[0x0400] = "ssl_cert",
[0x0800] = "ssl_session_store",
[0x1000] = "ssl_session_fetch",
}
function ngx.get_phase()
local r = get_request()
-- if we have no request object, assume we are called from the "init" phase
if not r then
return "init"
end
local context = C.ngx_http_lua_ffi_get_phase(r, errmsg)
if context == FFI_ERROR then -- NGX_ERROR
error(errmsg, 2)
end
local phase = context_names[context]
if not phase then
error("unknown phase: " .. tostring(context))
end
return phase
end
return {
version = base.version
}
-- Copyright (C) Yichun Zhang (agentzh)
local ffi = require 'ffi'
local base = require "resty.core.base"
local C = ffi.C
local ffi_cast = ffi.cast
local ffi_str = ffi.string
local new_tab = base.new_tab
local FFI_BAD_CONTEXT = base.FFI_BAD_CONTEXT
local FFI_NO_REQ_CTX = base.FFI_NO_REQ_CTX
local FFI_DECLINED = base.FFI_DECLINED
local get_string_buf = base.get_string_buf
local setmetatable = setmetatable
local type = type
local tostring = tostring
local get_request = base.get_request
local error = error
local ngx = ngx
local _M = {
version = base.version
}
local MAX_HEADER_VALUES = 100
local errmsg = base.get_errmsg_ptr()
local ffi_str_type = ffi.typeof("ngx_http_lua_ffi_str_t*")
local ffi_str_size = ffi.sizeof("ngx_http_lua_ffi_str_t")
ffi.cdef[[
int ngx_http_lua_ffi_set_resp_header(ngx_http_request_t *r,
const char *key_data, size_t key_len, int is_nil,
const char *sval, size_t sval_len, ngx_http_lua_ffi_str_t *mvals,
size_t mvals_len, int override, char **errmsg);
int ngx_http_lua_ffi_get_resp_header(ngx_http_request_t *r,
const unsigned char *key, size_t key_len,
unsigned char *key_buf, ngx_http_lua_ffi_str_t *values,
int max_nvalues, char **errmsg);
]]
local function set_resp_header(tb, key, value, no_override)
local r = get_request()
if not r then
error("no request found")
end
if type(key) ~= "string" then
key = tostring(key)
end
local rc
if value == nil then
if no_override then
error("invalid header value", 3)
end
rc = C.ngx_http_lua_ffi_set_resp_header(r, key, #key, true, nil, 0, nil,
0, 1, errmsg)
else
local sval, sval_len, mvals, mvals_len, buf
if type(value) == "table" then
mvals_len = #value
if mvals_len == 0 and no_override then
return
end
buf = get_string_buf(ffi_str_size * mvals_len)
mvals = ffi_cast(ffi_str_type, buf)
for i = 1, mvals_len do
local s = value[i]
if type(s) ~= "string" then
s = tostring(s)
value[i] = s
end
local str = mvals[i - 1]
str.data = s
str.len = #s
end
sval_len = 0
else
if type(value) ~= "string" then
sval = tostring(value)
else
sval = value
end
sval_len = #sval
mvals_len = 0
end
local override_int = no_override and 0 or 1
rc = C.ngx_http_lua_ffi_set_resp_header(r, key, #key, false, sval,
sval_len, mvals, mvals_len,
override_int, errmsg)
end
if rc == 0 or rc == FFI_DECLINED then
return
end
if rc == FFI_NO_REQ_CTX then
error("no request ctx found")
end
if rc == FFI_BAD_CONTEXT then
error("API disabled in the current context", 2)
end
-- rc == FFI_ERROR
error(ffi_str(errmsg[0]), 2)
end
_M.set_resp_header = set_resp_header
local function get_resp_header(tb, key)
local r = get_request()
if not r then
error("no request found")
end
if type(key) ~= "string" then
key = tostring(key)
end
local key_len = #key
local key_buf = get_string_buf(key_len + ffi_str_size * MAX_HEADER_VALUES)
local values = ffi_cast(ffi_str_type, key_buf + key_len)
local n = C.ngx_http_lua_ffi_get_resp_header(r, key, key_len, key_buf,
values, MAX_HEADER_VALUES,
errmsg)
-- print("retval: ", n)
if n == FFI_BAD_CONTEXT then
error("API disabled in the current context", 2)
end
if n == 0 then
return nil
end
if n == 1 then
local v = values[0]
return ffi_str(v.data, v.len)
end
if n > 0 then
local ret = new_tab(n, 0)
for i = 1, n do
local v = values[i - 1]
ret[i] = ffi_str(v.data, v.len)
end
return ret
end
-- n == FFI_ERROR
error(ffi_str(errmsg[0]), 2)
end
do
local mt = new_tab(0, 2)
mt.__newindex = set_resp_header
mt.__index = get_resp_header
ngx.header = setmetatable(new_tab(0, 0), mt)
end
return _M
-- Copyright (C) Yichun Zhang (agentzh)
local ffi = require 'ffi'
local base = require "resty.core.base"
local error = error
local tonumber = tonumber
local type = type
local C = ffi.C
local ffi_new = ffi.new
local ffi_str = ffi.string
local time_val = ffi_new("long[1]")
local get_string_buf = base.get_string_buf
local ngx = ngx
local FFI_ERROR = base.FFI_ERROR
local subsystem = ngx.config.subsystem
local ngx_lua_ffi_now
local ngx_lua_ffi_time
local ngx_lua_ffi_today
local ngx_lua_ffi_localtime
local ngx_lua_ffi_utctime
local ngx_lua_ffi_update_time
if subsystem == 'http' then
ffi.cdef[[
double ngx_http_lua_ffi_now(void);
long ngx_http_lua_ffi_time(void);
void ngx_http_lua_ffi_today(unsigned char *buf);
void ngx_http_lua_ffi_localtime(unsigned char *buf);
void ngx_http_lua_ffi_utctime(unsigned char *buf);
void ngx_http_lua_ffi_update_time(void);
int ngx_http_lua_ffi_cookie_time(unsigned char *buf, long t);
void ngx_http_lua_ffi_http_time(unsigned char *buf, long t);
void ngx_http_lua_ffi_parse_http_time(const unsigned char *str, size_t len,
long *time);
]]
ngx_lua_ffi_now = C.ngx_http_lua_ffi_now
ngx_lua_ffi_time = C.ngx_http_lua_ffi_time
ngx_lua_ffi_today = C.ngx_http_lua_ffi_today
ngx_lua_ffi_localtime = C.ngx_http_lua_ffi_localtime
ngx_lua_ffi_utctime = C.ngx_http_lua_ffi_utctime
ngx_lua_ffi_update_time = C.ngx_http_lua_ffi_update_time
elseif subsystem == 'stream' then
ffi.cdef[[
double ngx_stream_lua_ffi_now(void);
long ngx_stream_lua_ffi_time(void);
void ngx_stream_lua_ffi_today(unsigned char *buf);
void ngx_stream_lua_ffi_localtime(unsigned char *buf);
void ngx_stream_lua_ffi_utctime(unsigned char *buf);
void ngx_stream_lua_ffi_update_time(void);
]]
ngx_lua_ffi_now = C.ngx_stream_lua_ffi_now
ngx_lua_ffi_time = C.ngx_stream_lua_ffi_time
ngx_lua_ffi_today = C.ngx_stream_lua_ffi_today
ngx_lua_ffi_localtime = C.ngx_stream_lua_ffi_localtime
ngx_lua_ffi_utctime = C.ngx_stream_lua_ffi_utctime
ngx_lua_ffi_update_time = C.ngx_stream_lua_ffi_update_time
end
function ngx.now()
return tonumber(ngx_lua_ffi_now())
end
function ngx.time()
return tonumber(ngx_lua_ffi_time())
end
function ngx.update_time()
ngx_lua_ffi_update_time()
end
function ngx.today()
-- the format of today is 2010-11-19
local today_buf_size = 10
local buf = get_string_buf(today_buf_size)
ngx_lua_ffi_today(buf)
return ffi_str(buf, today_buf_size)
end
function ngx.localtime()
-- the format of localtime is 2010-11-19 20:56:31
local localtime_buf_size = 19
local buf = get_string_buf(localtime_buf_size)
ngx_lua_ffi_localtime(buf)
return ffi_str(buf, localtime_buf_size)
end
function ngx.utctime()
-- the format of utctime is 2010-11-19 20:56:31
local utctime_buf_size = 19
local buf = get_string_buf(utctime_buf_size)
ngx_lua_ffi_utctime(buf)
return ffi_str(buf, utctime_buf_size)
end
if subsystem == 'http' then
function ngx.cookie_time(sec)
if type(sec) ~= "number" then
error("number argument only", 2)
end
-- the format of cookie time is Mon, 28-Sep-2038 06:00:00 GMT
-- or Mon, 28-Sep-18 06:00:00 GMT
local cookie_time_buf_size = 29
local buf = get_string_buf(cookie_time_buf_size)
local used_size = C.ngx_http_lua_ffi_cookie_time(buf, sec)
return ffi_str(buf, used_size)
end
function ngx.http_time(sec)
if type(sec) ~= "number" then
error("number argument only", 2)
end
-- the format of http time is Mon, 28 Sep 1970 06:00:00 GMT
local http_time_buf_size = 29
local buf = get_string_buf(http_time_buf_size)
C.ngx_http_lua_ffi_http_time(buf, sec)
return ffi_str(buf, http_time_buf_size)
end
function ngx.parse_http_time(time_str)
if type(time_str) ~= "string" then
error("string argument only", 2)
end
C.ngx_http_lua_ffi_parse_http_time(time_str, #time_str, time_val)
local res = time_val[0]
if res == FFI_ERROR then
return nil
end
return tonumber(res)
end
end
return {
version = base.version
}
-- Copyright (C) Yichun Zhang (agentzh)
local ffi = require "ffi"
local base = require "resty.core.base"
local C = ffi.C
local ffi_string = ffi.string
local ngx = ngx
local type = type
local tostring = tostring
local get_string_buf = base.get_string_buf
local subsystem = ngx.config.subsystem
local ngx_lua_ffi_escape_uri
local ngx_lua_ffi_unescape_uri
local ngx_lua_ffi_uri_escaped_length
if subsystem == "http" then
ffi.cdef[[
size_t ngx_http_lua_ffi_uri_escaped_length(const unsigned char *src,
size_t len);
void ngx_http_lua_ffi_escape_uri(const unsigned char *src, size_t len,
unsigned char *dst);
size_t ngx_http_lua_ffi_unescape_uri(const unsigned char *src,
size_t len, unsigned char *dst);
]]
ngx_lua_ffi_escape_uri = C.ngx_http_lua_ffi_escape_uri
ngx_lua_ffi_unescape_uri = C.ngx_http_lua_ffi_unescape_uri
ngx_lua_ffi_uri_escaped_length = C.ngx_http_lua_ffi_uri_escaped_length
elseif subsystem == "stream" then
ffi.cdef[[
size_t ngx_stream_lua_ffi_uri_escaped_length(const unsigned char *src,
size_t len);
void ngx_stream_lua_ffi_escape_uri(const unsigned char *src, size_t len,
unsigned char *dst);
size_t ngx_stream_lua_ffi_unescape_uri(const unsigned char *src,
size_t len, unsigned char *dst);
]]
ngx_lua_ffi_escape_uri = C.ngx_stream_lua_ffi_escape_uri
ngx_lua_ffi_unescape_uri = C.ngx_stream_lua_ffi_unescape_uri
ngx_lua_ffi_uri_escaped_length = C.ngx_stream_lua_ffi_uri_escaped_length
end
ngx.escape_uri = function (s)
if type(s) ~= 'string' then
if not s then
s = ''
else
s = tostring(s)
end
end
local slen = #s
local dlen = ngx_lua_ffi_uri_escaped_length(s, slen)
-- print("dlen: ", tonumber(dlen))
if dlen == slen then
return s
end
local dst = get_string_buf(dlen)
ngx_lua_ffi_escape_uri(s, slen, dst)
return ffi_string(dst, dlen)
end
ngx.unescape_uri = function (s)
if type(s) ~= 'string' then
if not s then
s = ''
else
s = tostring(s)
end
end
local slen = #s
local dlen = slen
local dst = get_string_buf(dlen)
dlen = ngx_lua_ffi_unescape_uri(s, slen, dst)
return ffi_string(dst, dlen)
end
return {
version = base.version,
}
-- Copyright (C) Yichun Zhang (agentzh)
local ffi = require "ffi"
local base = require "resty.core.base"
base.allows_subsystem("http")
local C = ffi.C
local ffi_str = ffi.string
local ffi_copy = ffi.copy
local byte = string.byte
local str_find = string.find
local get_string_buf = base.get_string_buf
ffi.cdef[[
void ngx_http_lua_ffi_str_replace_char(unsigned char *buf, size_t len,
const unsigned char find, const unsigned char replace);
]]
local _M = {
version = base.version
}
function _M.str_replace_char(str, find, replace)
if not str_find(str, find, nil, true) then
return str
end
local len = #str
local buf = get_string_buf(len)
ffi_copy(buf, str)
C.ngx_http_lua_ffi_str_replace_char(buf, len, byte(find),
byte(replace))
return ffi_str(buf, len)
end
return _M
-- Copyright (C) Yichun Zhang (agentzh)
local ffi = require "ffi"
local base = require "resty.core.base"
local C = ffi.C
local ffi_new = ffi.new
local ffi_str = ffi.string
local type = type
local error = error
local tostring = tostring
local setmetatable = setmetatable
local get_request = base.get_request
local get_string_buf = base.get_string_buf
local get_size_ptr = base.get_size_ptr
local new_tab = base.new_tab
local subsystem = ngx.config.subsystem
local ngx_lua_ffi_var_get
local ngx_lua_ffi_var_set
local ERR_BUF_SIZE = 256
ngx.var = new_tab(0, 0)
if subsystem == "http" then
ffi.cdef[[
int ngx_http_lua_ffi_var_get(ngx_http_request_t *r,
const char *name_data, size_t name_len, char *lowcase_buf,
int capture_id, char **value, size_t *value_len, char **err);
int ngx_http_lua_ffi_var_set(ngx_http_request_t *r,
const unsigned char *name_data, size_t name_len,
unsigned char *lowcase_buf, const unsigned char *value,
size_t value_len, unsigned char *errbuf, size_t *errlen);
]]
ngx_lua_ffi_var_get = C.ngx_http_lua_ffi_var_get
ngx_lua_ffi_var_set = C.ngx_http_lua_ffi_var_set
elseif subsystem == "stream" then
ffi.cdef[[
int ngx_stream_lua_ffi_var_get(ngx_stream_lua_request_t *r,
const char *name_data, size_t name_len, char *lowcase_buf,
int capture_id, char **value, size_t *value_len, char **err);
int ngx_stream_lua_ffi_var_set(ngx_stream_lua_request_t *r,
const unsigned char *name_data, size_t name_len,
unsigned char *lowcase_buf, const unsigned char *value,
size_t value_len, unsigned char *errbuf, size_t *errlen);
]]
ngx_lua_ffi_var_get = C.ngx_stream_lua_ffi_var_get
ngx_lua_ffi_var_set = C.ngx_stream_lua_ffi_var_set
end
local value_ptr = ffi_new("unsigned char *[1]")
local errmsg = base.get_errmsg_ptr()
local function var_get(self, name)
local r = get_request()
if not r then
error("no request found")
end
local value_len = get_size_ptr()
local rc
if type(name) == "number" then
rc = ngx_lua_ffi_var_get(r, nil, 0, nil, name, value_ptr, value_len,
errmsg)
else
if type(name) ~= "string" then
error("bad variable name", 2)
end
local name_len = #name
local lowcase_buf = get_string_buf(name_len)
rc = ngx_lua_ffi_var_get(r, name, name_len, lowcase_buf, 0, value_ptr,
value_len, errmsg)
end
-- ngx.log(ngx.WARN, "rc = ", rc)
if rc == 0 then -- NGX_OK
return ffi_str(value_ptr[0], value_len[0])
end
if rc == -5 then -- NGX_DECLINED
return nil
end
if rc == -1 then -- NGX_ERROR
error(ffi_str(errmsg[0]), 2)
end
end
local function var_set(self, name, value)
local r = get_request()
if not r then
error("no request found")
end
if type(name) ~= "string" then
error("bad variable name", 2)
end
local name_len = #name
local errlen = get_size_ptr()
errlen[0] = ERR_BUF_SIZE
local lowcase_buf = get_string_buf(name_len + ERR_BUF_SIZE)
local value_len
if value == nil then
value_len = 0
else
if type(value) ~= 'string' then
value = tostring(value)
end
value_len = #value
end
local errbuf = lowcase_buf + name_len
local rc = ngx_lua_ffi_var_set(r, name, name_len, lowcase_buf, value,
value_len, errbuf, errlen)
-- ngx.log(ngx.WARN, "rc = ", rc)
if rc == 0 then -- NGX_OK
return
end
if rc == -1 then -- NGX_ERROR
error(ffi_str(errbuf, errlen[0]), 2)
end
end
do
local mt = new_tab(0, 2)
mt.__index = var_get
mt.__newindex = var_set
setmetatable(ngx.var, mt)
end
return {
version = base.version
}
-- Copyright (C) Yichun Zhang (agentzh)
local ffi = require "ffi"
local base = require "resty.core.base"
local C = ffi.C
local new_tab = base.new_tab
local subsystem = ngx.config.subsystem
local ngx_lua_ffi_worker_id
local ngx_lua_ffi_worker_pid
local ngx_lua_ffi_worker_count
local ngx_lua_ffi_worker_exiting
ngx.worker = new_tab(0, 4)
if subsystem == "http" then
ffi.cdef[[
int ngx_http_lua_ffi_worker_id(void);
int ngx_http_lua_ffi_worker_pid(void);
int ngx_http_lua_ffi_worker_count(void);
int ngx_http_lua_ffi_worker_exiting(void);
]]
ngx_lua_ffi_worker_id = C.ngx_http_lua_ffi_worker_id
ngx_lua_ffi_worker_pid = C.ngx_http_lua_ffi_worker_pid
ngx_lua_ffi_worker_count = C.ngx_http_lua_ffi_worker_count
ngx_lua_ffi_worker_exiting = C.ngx_http_lua_ffi_worker_exiting
elseif subsystem == "stream" then
ffi.cdef[[
int ngx_stream_lua_ffi_worker_id(void);
int ngx_stream_lua_ffi_worker_pid(void);
int ngx_stream_lua_ffi_worker_count(void);
int ngx_stream_lua_ffi_worker_exiting(void);
]]
ngx_lua_ffi_worker_id = C.ngx_stream_lua_ffi_worker_id
ngx_lua_ffi_worker_pid = C.ngx_stream_lua_ffi_worker_pid
ngx_lua_ffi_worker_count = C.ngx_stream_lua_ffi_worker_count
ngx_lua_ffi_worker_exiting = C.ngx_stream_lua_ffi_worker_exiting
end
function ngx.worker.exiting()
return ngx_lua_ffi_worker_exiting() ~= 0
end
function ngx.worker.pid()
return ngx_lua_ffi_worker_pid()
end
function ngx.worker.id()
local id = ngx_lua_ffi_worker_id()
if id < 0 then
return nil
end
return id
end
function ngx.worker.count()
return ngx_lua_ffi_worker_count()
end
return {
_VERSION = base.version
}
No preview for this file type
----------------------------------------页面跳转url--------------------------------
local _ReM = {}
------跳转到google验证页面
function _ReM.checkgoogle(self)
source_url = ngx.encode_base64(ngx.var.scheme .. '://' ..
ngx.var.host .. ':' .. ngx.var.server_port .. ngx.var.request_uri)
dest = 'http://passport.ichunt.com/static/login.html' .. '?continue=' .. source_url
ngx.redirect(dest,302)
ngx.exit(ngx.OK)
end
return _ReM
\ No newline at end of file
This diff is collapsed. Click to expand it.
-- Copyright (C) Yichun Zhang (agentzh)
local subsystem = ngx.config.subsystem
require "resty.core.var"
require "resty.core.worker"
require "resty.core.regex"
require "resty.core.shdict"
require "resty.core.time"
require "resty.core.hash"
require "resty.core.uri"
require "resty.core.exit"
require "resty.core.base64"
if subsystem == 'http' then
require "resty.core.request"
require "resty.core.response"
require "resty.core.phase"
require "resty.core.ndk"
end
require "resty.core.misc"
require "resty.core.ctx"
local base = require "resty.core.base"
return {
version = base.version
}
-- Copyright (C) Yichun Zhang (agentzh)
local ffi = require 'ffi'
local ffi_new = ffi.new
local error = error
local select = select
local ceil = math.ceil
local subsystem = ngx.config.subsystem
local str_buf_size = 4096
local str_buf
local size_ptr
local FREE_LIST_REF = 0
if subsystem == 'http' then
if not ngx.config
or not ngx.config.ngx_lua_version
or ngx.config.ngx_lua_version ~= 10016
then
error("ngx_http_lua_module 0.10.16 required")
end
elseif subsystem == 'stream' then
if not ngx.config
or not ngx.config.ngx_lua_version
or ngx.config.ngx_lua_version ~= 8
then
error("ngx_stream_lua_module 0.0.8 required")
end
else
error("ngx_http_lua_module 0.10.16 or "
.. "ngx_stream_lua_module 0.0.8 required")
end
if string.find(jit.version, " 2.0", 1, true) then
ngx.log(ngx.ALERT, "use of lua-resty-core with LuaJIT 2.0 is ",
"not recommended; use LuaJIT 2.1+ instead")
end
local ok, new_tab = pcall(require, "table.new")
if not ok then
new_tab = function (narr, nrec) return {} end
end
local clear_tab
ok, clear_tab = pcall(require, "table.clear")
if not ok then
local pairs = pairs
clear_tab = function (tab)
for k, _ in pairs(tab) do
tab[k] = nil
end
end
end
-- XXX for now LuaJIT 2.1 cannot compile require()
-- so we make the fast code path Lua only in our own
-- wrapper so that most of the require() calls in hot
-- Lua code paths can be JIT compiled.
do
local orig_require = require
local pkg_loaded = package.loaded
local function my_require(name)
local mod = pkg_loaded[name]
if mod then
return mod
end
return orig_require(name)
end
getfenv(0).require = my_require
end
if not pcall(ffi.typeof, "ngx_str_t") then
ffi.cdef[[
typedef struct {
size_t len;
const unsigned char *data;
} ngx_str_t;
]]
end
if subsystem == 'http' then
if not pcall(ffi.typeof, "ngx_http_request_t") then
ffi.cdef[[
typedef struct ngx_http_request_s ngx_http_request_t;
]]
end
if not pcall(ffi.typeof, "ngx_http_lua_ffi_str_t") then
ffi.cdef[[
typedef struct {
int len;
const unsigned char *data;
} ngx_http_lua_ffi_str_t;
]]
end
elseif subsystem == 'stream' then
if not pcall(ffi.typeof, "ngx_stream_lua_request_t") then
ffi.cdef[[
typedef struct ngx_stream_lua_request_s ngx_stream_lua_request_t;
]]
end
if not pcall(ffi.typeof, "ngx_stream_lua_ffi_str_t") then
ffi.cdef[[
typedef struct {
int len;
const unsigned char *data;
} ngx_stream_lua_ffi_str_t;
]]
end
else
error("unknown subsystem: " .. subsystem)
end
local c_buf_type = ffi.typeof("char[?]")
local _M = new_tab(0, 18)
_M.version = "0.1.18"
_M.new_tab = new_tab
_M.clear_tab = clear_tab
local errmsg
function _M.get_errmsg_ptr()
if not errmsg then
errmsg = ffi_new("char *[1]")
end
return errmsg
end
if not ngx then
error("no existing ngx. table found")
end
function _M.set_string_buf_size(size)
if size <= 0 then
return
end
if str_buf then
str_buf = nil
end
str_buf_size = ceil(size)
end
function _M.get_string_buf_size()
return str_buf_size
end
function _M.get_size_ptr()
if not size_ptr then
size_ptr = ffi_new("size_t[1]")
end
return size_ptr
end
function _M.get_string_buf(size, must_alloc)
-- ngx.log(ngx.ERR, "str buf size: ", str_buf_size)
if size > str_buf_size or must_alloc then
return ffi_new(c_buf_type, size)
end
if not str_buf then
str_buf = ffi_new(c_buf_type, str_buf_size)
end
return str_buf
end
function _M.ref_in_table(tb, key)
if key == nil then
return -1
end
local ref = tb[FREE_LIST_REF]
if ref and ref ~= 0 then
tb[FREE_LIST_REF] = tb[ref]
else
ref = #tb + 1
end
tb[ref] = key
-- print("ref key_id returned ", ref)
return ref
end
function _M.allows_subsystem(...)
local total = select("#", ...)
for i = 1, total do
if select(i, ...) == subsystem then
return
end
end
error("unsupported subsystem: " .. subsystem, 2)
end
_M.FFI_OK = 0
_M.FFI_NO_REQ_CTX = -100
_M.FFI_BAD_CONTEXT = -101
_M.FFI_ERROR = -1
_M.FFI_AGAIN = -2
_M.FFI_BUSY = -3
_M.FFI_DONE = -4
_M.FFI_DECLINED = -5
do
local exdata
ok, exdata = pcall(require, "thread.exdata")
if ok and exdata then
function _M.get_request()
local r = exdata()
if r ~= nil then
return r
end
end
else
local getfenv = getfenv
function _M.get_request()
return getfenv(0).__ngx_req
end
end
end
return _M
-- Copyright (C) Yichun Zhang (agentzh)
local ffi = require "ffi"
local base = require "resty.core.base"
local C = ffi.C
local ffi_string = ffi.string
local ngx = ngx
local type = type
local error = error
local floor = math.floor
local tostring = tostring
local get_string_buf = base.get_string_buf
local get_size_ptr = base.get_size_ptr
local subsystem = ngx.config.subsystem
local ngx_lua_ffi_encode_base64
local ngx_lua_ffi_decode_base64
if subsystem == "http" then
ffi.cdef[[
size_t ngx_http_lua_ffi_encode_base64(const unsigned char *src,
size_t len, unsigned char *dst,
int no_padding);
int ngx_http_lua_ffi_decode_base64(const unsigned char *src,
size_t len, unsigned char *dst,
size_t *dlen);
]]
ngx_lua_ffi_encode_base64 = C.ngx_http_lua_ffi_encode_base64
ngx_lua_ffi_decode_base64 = C.ngx_http_lua_ffi_decode_base64
elseif subsystem == "stream" then
ffi.cdef[[
size_t ngx_stream_lua_ffi_encode_base64(const unsigned char *src,
size_t len, unsigned char *dst,
int no_padding);
int ngx_stream_lua_ffi_decode_base64(const unsigned char *src,
size_t len, unsigned char *dst,
size_t *dlen);
]]
ngx_lua_ffi_encode_base64 = C.ngx_stream_lua_ffi_encode_base64
ngx_lua_ffi_decode_base64 = C.ngx_stream_lua_ffi_decode_base64
end
local function base64_encoded_length(len, no_padding)
return no_padding and floor((len * 8 + 5) / 6) or
floor((len + 2) / 3) * 4
end
ngx.encode_base64 = function (s, no_padding)
if type(s) ~= 'string' then
if not s then
s = ''
else
s = tostring(s)
end
end
local slen = #s
local no_padding_bool = false;
local no_padding_int = 0;
if no_padding then
if no_padding ~= true then
local typ = type(no_padding)
error("bad no_padding: boolean expected, got " .. typ, 2)
end
no_padding_bool = true
no_padding_int = 1;
end
local dlen = base64_encoded_length(slen, no_padding_bool)
local dst = get_string_buf(dlen)
local r_dlen = ngx_lua_ffi_encode_base64(s, slen, dst, no_padding_int)
-- if dlen ~= r_dlen then error("discrepancy in len") end
return ffi_string(dst, r_dlen)
end
local function base64_decoded_length(len)
return floor((len + 3) / 4) * 3
end
ngx.decode_base64 = function (s)
if type(s) ~= 'string' then
error("string argument only", 2)
end
local slen = #s
local dlen = base64_decoded_length(slen)
-- print("dlen: ", tonumber(dlen))
local dst = get_string_buf(dlen)
local pdlen = get_size_ptr()
local ok = ngx_lua_ffi_decode_base64(s, slen, dst, pdlen)
if ok == 0 then
return nil
end
return ffi_string(dst, pdlen[0])
end
return {
version = base.version
}
-- Copyright (C) Yichun Zhang (agentzh)
local ffi = require "ffi"
local debug = require "debug"
local base = require "resty.core.base"
local misc = require "resty.core.misc"
local C = ffi.C
local register_getter = misc.register_ngx_magic_key_getter
local register_setter = misc.register_ngx_magic_key_setter
local registry = debug.getregistry()
local new_tab = base.new_tab
local ref_in_table = base.ref_in_table
local get_request = base.get_request
local FFI_NO_REQ_CTX = base.FFI_NO_REQ_CTX
local FFI_OK = base.FFI_OK
local error = error
local subsystem = ngx.config.subsystem
local ngx_lua_ffi_get_ctx_ref
local ngx_lua_ffi_set_ctx_ref
if subsystem == "http" then
ffi.cdef[[
int ngx_http_lua_ffi_get_ctx_ref(ngx_http_request_t *r);
int ngx_http_lua_ffi_set_ctx_ref(ngx_http_request_t *r, int ref);
]]
ngx_lua_ffi_get_ctx_ref = C.ngx_http_lua_ffi_get_ctx_ref
ngx_lua_ffi_set_ctx_ref = C.ngx_http_lua_ffi_set_ctx_ref
elseif subsystem == "stream" then
ffi.cdef[[
int ngx_stream_lua_ffi_get_ctx_ref(ngx_stream_lua_request_t *r);
int ngx_stream_lua_ffi_set_ctx_ref(ngx_stream_lua_request_t *r, int ref);
]]
ngx_lua_ffi_get_ctx_ref = C.ngx_stream_lua_ffi_get_ctx_ref
ngx_lua_ffi_set_ctx_ref = C.ngx_stream_lua_ffi_set_ctx_ref
end
local _M = {
_VERSION = base.version
}
local function get_ctx_table()
local r = get_request()
if not r then
error("no request found")
end
local ctx_ref = ngx_lua_ffi_get_ctx_ref(r)
if ctx_ref == FFI_NO_REQ_CTX then
error("no request ctx found")
end
local ctxs = registry.ngx_lua_ctx_tables
if ctx_ref < 0 then
local ctx = new_tab(0, 4)
ctx_ref = ref_in_table(ctxs, ctx)
if ngx_lua_ffi_set_ctx_ref(r, ctx_ref) ~= FFI_OK then
return nil
end
return ctx
end
return ctxs[ctx_ref]
end
register_getter("ctx", get_ctx_table)
local function set_ctx_table(ctx)
local r = get_request()
if not r then
error("no request found")
end
local ctx_ref = ngx_lua_ffi_get_ctx_ref(r)
if ctx_ref == FFI_NO_REQ_CTX then
error("no request ctx found")
end
local ctxs = registry.ngx_lua_ctx_tables
if ctx_ref < 0 then
ctx_ref = ref_in_table(ctxs, ctx)
ngx_lua_ffi_set_ctx_ref(r, ctx_ref)
return
end
ctxs[ctx_ref] = ctx
end
register_setter("ctx", set_ctx_table)
return _M
-- Copyright (C) Yichun Zhang (agentzh)
local ffi = require "ffi"
local base = require "resty.core.base"
local C = ffi.C
local ffi_string = ffi.string
local ngx = ngx
local error = error
local get_string_buf = base.get_string_buf
local get_size_ptr = base.get_size_ptr
local get_request = base.get_request
local co_yield = coroutine._yield
local subsystem = ngx.config.subsystem
local ngx_lua_ffi_exit
if subsystem == "http" then
ffi.cdef[[
int ngx_http_lua_ffi_exit(ngx_http_request_t *r, int status,
unsigned char *err, size_t *errlen);
]]
ngx_lua_ffi_exit = C.ngx_http_lua_ffi_exit
elseif subsystem == "stream" then
ffi.cdef[[
int ngx_stream_lua_ffi_exit(ngx_stream_lua_request_t *r, int status,
unsigned char *err, size_t *errlen);
]]
ngx_lua_ffi_exit = C.ngx_stream_lua_ffi_exit
end
local ERR_BUF_SIZE = 128
local FFI_DONE = base.FFI_DONE
ngx.exit = function (rc)
local err = get_string_buf(ERR_BUF_SIZE)
local errlen = get_size_ptr()
local r = get_request()
if r == nil then
error("no request found")
end
errlen[0] = ERR_BUF_SIZE
rc = ngx_lua_ffi_exit(r, rc, err, errlen)
if rc == 0 then
-- print("yielding...")
return co_yield()
end
if rc == FFI_DONE then
return
end
error(ffi_string(err, errlen[0]), 2)
end
return {
version = base.version
}
This diff is collapsed. Click to expand it.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment