openresty是如何通过lua代码获取nginx内请求数据的

2022-06-05 00:17:54 浏览数 (2)

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;
}

0 人点赞