nginx中处理请求是围绕ngx_http_request_t结构体进行的。
ngx_http_request_t结构体包含了当前http请求的所有数据。
ngx_http_lua_module与nginx进行交互,主要围绕这个结构体实现的,lua代码获取nginx内部http请求数据,然后进行处理。
lua_module为此在建立新的协程,将ngx_http_request_t的指针保存在了lua_State的全局变量中。
经过 ngx_http_lua_set_req 将请求与协程关联。
代码语言:javascript复制static ngx_inline void
ngx_http_lua_set_req(lua_State *L, ngx_http_request_t *r)
{
#ifdef OPENRESTY_LUAJIT
lua_setexdata(L, (void *) r);
#else
lua_pushlightuserdata(L, r);
lua_setglobal(L, ngx_http_lua_req_key);
#endif
}
经过ngx_http_lua_get_req获取请求的ngx_http_request_t结构体,从结构体中把想要获取的http数据返回。
代码语言:javascript复制// ngx_http_lua_util.h文件
// 经过 ngx_http_lua_get_req 从lua_State中获取协程关联的请求
static ngx_inline ngx_http_request_t *
ngx_http_lua_get_req(lua_State *L)
{
ngx_http_request_t *r;
lua_getglobal(L, ngx_http_lua_req_key);
r = lua_touserdata(L, -1);
lua_pop(L, 1);
return r;
}
lua获取nginx请求方法
代码语言:javascript复制function ngx.req.get_method()
local r = get_request()
if not r then
error("no request found")
end
do
local id = C.ngx_http_lua_ffi_req_get_method(r)
if id == FFI_BAD_CONTEXT then
error("API disabled in the current context", 2)
end
local method = methods[id]
if method then
return method
end
end
local sizep = get_size_ptr()
local rc = C.ngx_http_lua_ffi_req_get_method_name(r, namep, sizep)
if rc ~= 0 then
return nil
end
return ffi_str(namep[0], sizep[0])
end
ngx_http_lua_req_method.c
int
ngx_http_lua_ffi_req_get_method(ngx_http_request_t *r)
{
if (r->connection->fd == (ngx_socket_t) -1) {
return NGX_HTTP_LUA_FFI_BAD_CONTEXT;
}
return r->method;
}
int
ngx_http_lua_ffi_req_get_method_name(ngx_http_request_t *r, u_char **name,
size_t *len)
{
if (r->connection->fd == (ngx_socket_t) -1) {
return NGX_HTTP_LUA_FFI_BAD_CONTEXT;
}
*name = r->method_name.data;
*len = r->method_name.len;
return NGX_OK;
}
lua获取nginx请求参数
代码语言:javascript复制function ngx.req.get_uri_args(max_args)
-- ...
-- 获取请求参数个数
local n = C.ngx_http_lua_ffi_req_get_uri_args_count(r, max_args, truncated)
-- 获取请求参数长度
local args_len = C.ngx_http_lua_ffi_req_get_querystring_len(r)
-- 用于存放请求参数的数据结构
local strbuf = get_string_buf(args_len n * table_elt_size)
local kvbuf = ffi_cast(table_elt_type, strbuf args_len)
-- nargs为请求参数的个数
-- kvbuf为table类型kv结构 用于保存请求参数/index.html?aa=11&bb=22&cc=33
local nargs = C.ngx_http_lua_ffi_req_get_uri_args(r, strbuf, kvbuf, n)
-- 最终请求参数保存到 args 表中返回
local args = new_tab(0, nargs)
for i = 0, nargs - 1 do
local arg = kvbuf[i]
local key = arg.key
key = ffi_str(key.data, key.len)
local value = arg.value
-- value 为arg.value.data
-- 最终保存到args table中
args[key] = value
-- 如果 参数keys值有重复
args[key] = {existvalue, value}
end
if truncated[0] ~= 0 then
return args, "truncated"
end
return args
end
ngx_http_lua_args.c
代码语言:javascript复制int
ngx_http_lua_ffi_req_get_uri_args_count(ngx_http_request_t *r, int max,
int *truncated)
{
int count;
u_char *p, *last;
if (r->connection->fd == (ngx_socket_t) -1) {
return NGX_HTTP_LUA_FFI_BAD_CONTEXT;
}
*truncated = 0;
if (max < 0) {
max = NGX_HTTP_LUA_MAX_ARGS;
}
last = r->args.data r->args.len;
count = 0;
for (p = r->args.data; p != last; p ) {
if (*p == '&') {
if (count == 0) {
count = 2;
} else {
count ;
}
}
}
if (count) {
if (max > 0 && count > max) {
count = max;
*truncated = 1;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"lua hit query args limit %d", max);
}
return count;
}
if (r->args.len) {
return 1;
}
return 0;
}
ngx_http_lua_ffi_req_get_querystring_len函数
ngx_http_lua_ffi_req_get_uri_args函数
代码语言:javascript复制size_t
ngx_http_lua_ffi_req_get_querystring_len(ngx_http_request_t *r)
{
return r->args.len;
}
int
ngx_http_lua_ffi_req_get_uri_args(ngx_http_request_t *r, u_char *buf,
ngx_http_lua_ffi_table_elt_t *out, int count)
{
int i, parsing_value = 0;
u_char *last, *p, *q;
u_char *src, *dst;
if (count <= 0) {
return NGX_OK;
}
ngx_memcpy(buf, r->args.data, r->args.len);
i = 0;
last = buf r->args.len;
p = buf;
q = p;
while (p != last) {
if (*p == '=' && !parsing_value) {
/* key data is between p and q */
src = q; dst = q;
ngx_http_lua_unescape_uri(&dst, &src, p - q,
NGX_UNESCAPE_URI_COMPONENT);
dd("saving key %.*s", (int) (dst - q), q);
out[i].key.data = q;
out[i].key.len = (int) (dst - q);
/* skip the current '=' char */
p ;
q = p;
parsing_value = 1;
} else if (*p == '&') {
/* reached the end of a key or a value, just save it */
src = q; dst = q;
ngx_http_lua_unescape_uri(&dst, &src, p - q,
NGX_UNESCAPE_URI_COMPONENT);
dd("pushing key or value %.*s", (int) (dst - q), q);
if (parsing_value) {
/* end of the current pair's value */
parsing_value = 0;
if (out[i].key.len) {
out[i].value.data = q;
out[i].value.len = (int) (dst - q);
i ;
}
} else {
/* the current parsing pair takes no value,
* just push the value "true" */
dd("pushing boolean true");
if (dst - q) {
out[i].key.data = q;
out[i].key.len = (int) (dst - q);
out[i].value.len = -1;
i ;
}
}
if (i == count) {
return i;
}
/* skip the current '&' char */
p ;
q = p;
} else {
p ;
}
}
if (p != q || parsing_value) {
src = q; dst = q;
ngx_http_lua_unescape_uri(&dst, &src, p - q,
NGX_UNESCAPE_URI_COMPONENT);
dd("pushing key or value %.*s", (int) (dst - q), q);
if (parsing_value) {
if (out[i].key.len) {
out[i].value.data = q;
out[i].value.len = (int) (dst - q);
i ;
}
} else {
if (dst - q) {
out[i].key.data = q;
out[i].key.len = (int) (dst - q);
out[i].value.len = (int) -1;
i ;
}
}
}
return i;
}