Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ Table of Contents
* [ngx.req.append_body](#ngxreqappend_body)
* [ngx.req.finish_body](#ngxreqfinish_body)
* [ngx.req.socket](#ngxreqsocket)
* [ngx.resp.get_headers](#ngxrespget_headers)
* [ngx.exec](#ngxexec)
* [ngx.redirect](#ngxredirect)
* [ngx.send_headers](#ngxsend_headers)
Expand Down Expand Up @@ -3277,6 +3278,33 @@ This function was first introduced in the `v0.5.0rc1` release.

[Back to TOC](#table-of-contents)

ngx.resp.get_headers
--------------------
**syntax:** *headers = ngx.resp.get_headers(max_headers?, raw?)*

**context:** *set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua, log_by_lua**

Returns a Lua table holding all the current response headers.

```lua

local h = ngx.resp.get_headers()
for k, v in pairs(h) do
...
end
```

To read an individual header:

```lua

ngx.say("ETag: ", ngx.resp.get_headers()["ETag"])
```

This function has the same signature as [ngx.req.get_headers](#ngxreqget_headers) except getting response headers instead of request headers.

[Back to TOC](#table-of-contents)

ngx.exec
--------
**syntax:** *ngx.exec(uri, args?)*
Expand Down
194 changes: 165 additions & 29 deletions src/ngx_http_lua_headers.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ static int ngx_http_lua_ngx_header_set(lua_State *L);
static int ngx_http_lua_ngx_req_get_headers(lua_State *L);
static int ngx_http_lua_ngx_req_header_clear(lua_State *L);
static int ngx_http_lua_ngx_req_header_set(lua_State *L);
static int ngx_http_lua_ngx_resp_get_headers(lua_State *L);


static int
Expand Down Expand Up @@ -338,7 +339,7 @@ ngx_http_lua_ngx_req_get_headers(lua_State *L)
lua_createtable(L, 0, count);

if (!raw) {
lua_pushlightuserdata(L, &ngx_http_lua_req_get_headers_metatable_key);
lua_pushlightuserdata(L, &ngx_http_lua_get_headers_metatable_key);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_setmetatable(L, -2);
}
Expand Down Expand Up @@ -388,6 +389,127 @@ ngx_http_lua_ngx_req_get_headers(lua_State *L)
}


static int
ngx_http_lua_ngx_resp_get_headers(lua_State *L)
{
ngx_list_part_t *part;
ngx_table_elt_t *header;
ngx_http_request_t *r;
u_char *lowcase_key = NULL;
size_t lowcase_key_sz = 0;
ngx_uint_t i;
int n;
int max;
int raw = 0;
int count = 0;

n = lua_gettop(L);

if (n >= 1) {
if (lua_isnil(L, 1)) {
max = NGX_HTTP_LUA_MAX_HEADERS;

} else {
max = luaL_checkinteger(L, 1);
}

if (n >= 2) {
raw = lua_toboolean(L, 2);
}

} else {
max = NGX_HTTP_LUA_MAX_HEADERS;
}

r = ngx_http_lua_get_req(L);
if (r == NULL) {
return luaL_error(L, "no request object found");
}

ngx_http_lua_check_fake_request(L, r);

part = &r->headers_out.headers.part;
count = part->nelts;
while (part->next) {
part = part->next;
count += part->nelts;
}

if (max > 0 && count > max) {
count = max;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"lua exceeding request header limit %d", max);
}

lua_createtable(L, 0, count);

if (!raw) {
lua_pushlightuserdata(L, &ngx_http_lua_get_headers_metatable_key);
lua_rawget(L, LUA_REGISTRYINDEX);
lua_setmetatable(L, -2);
}

part = &r->headers_out.headers.part;
header = part->elts;

for (i = 0; /* void */; i++) {

dd("stack top: %d", lua_gettop(L));

if (i >= part->nelts) {
if (part->next == NULL) {
break;
}

part = part->next;
header = part->elts;
i = 0;
}

if (header[i].hash == 0) {
continue;
}

if (raw) {
lua_pushlstring(L, (char *) header[i].key.data, header[i].key.len);

} else {
/* nginx does not even bother initializing output header entry's
* "lowcase_key" field. so we cannot count on that at all. */
if (header[i].key.len > lowcase_key_sz) {
lowcase_key_sz = header[i].key.len * 2;

/* we allocate via Lua's GC to prevent in-request
* leaks in the nginx request memory pools */
lowcase_key = lua_newuserdata(L, lowcase_key_sz);
lua_insert(L, 1);
}

ngx_strlow(lowcase_key, header[i].key.data, header[i].key.len);
lua_pushlstring(L, (char *) lowcase_key, header[i].key.len);
}

/* stack: [udata] table key */

lua_pushlstring(L, (char *) header[i].value.data,
header[i].value.len); /* stack: [udata] table key
value */

ngx_http_lua_set_multi_value_table(L, -3);

ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"lua response header: \"%V: %V\"",
&header[i].key, &header[i].value);

if (--count == 0) {
return 1;
}
}

return 1;
}


static int
ngx_http_lua_ngx_header_get(lua_State *L)
{
Expand Down Expand Up @@ -717,6 +839,27 @@ ngx_http_lua_ngx_req_header_set_helper(lua_State *L)
}


void
ngx_http_lua_inject_req_header_api(lua_State *L)
{
lua_pushcfunction(L, ngx_http_lua_ngx_req_http_version);
lua_setfield(L, -2, "http_version");

lua_pushcfunction(L, ngx_http_lua_ngx_req_raw_header);
lua_setfield(L, -2, "raw_header");

lua_pushcfunction(L, ngx_http_lua_ngx_req_header_clear);
lua_setfield(L, -2, "clear_header");

lua_pushcfunction(L, ngx_http_lua_ngx_req_header_set);
lua_setfield(L, -2, "set_header");

lua_pushcfunction(L, ngx_http_lua_ngx_req_get_headers);
lua_setfield(L, -2, "get_headers");

}


void
ngx_http_lua_inject_resp_header_api(lua_State *L)
{
Expand All @@ -730,53 +873,46 @@ ngx_http_lua_inject_resp_header_api(lua_State *L)
lua_setmetatable(L, -2);

lua_setfield(L, -2, "header");
}


void
ngx_http_lua_inject_req_header_api(ngx_log_t *log, lua_State *L)
{
int rc;

lua_pushcfunction(L, ngx_http_lua_ngx_req_http_version);
lua_setfield(L, -2, "http_version");
lua_createtable(L, 0, 1); /* .resp */

lua_pushcfunction(L, ngx_http_lua_ngx_req_raw_header);
lua_setfield(L, -2, "raw_header");

lua_pushcfunction(L, ngx_http_lua_ngx_req_header_clear);
lua_setfield(L, -2, "clear_header");
lua_pushcfunction(L, ngx_http_lua_ngx_resp_get_headers);
lua_setfield(L, -2, "get_headers");

lua_pushcfunction(L, ngx_http_lua_ngx_req_header_set);
lua_setfield(L, -2, "set_header");
lua_setfield(L, -2, "resp");
}

lua_pushcfunction(L, ngx_http_lua_ngx_req_get_headers);
lua_setfield(L, -2, "get_headers");

lua_pushlightuserdata(L, &ngx_http_lua_req_get_headers_metatable_key);
lua_createtable(L, 0, 1); /* metatable for ngx.req.get_headers(_, true) */
void
ngx_http_lua_inject_metatable_header_api(ngx_log_t *log, lua_State *L)
{
int rc;
const char buf[] =
"local tb, key = ...\n"
"local new_key = string.gsub(string.lower(key), '_', '-')\n"
"if new_key ~= key then return tb[new_key] else return nil end";

{
const char buf[] =
"local tb, key = ...\n"
"local new_key = string.gsub(string.lower(key), '_', '-')\n"
"if new_key ~= key then return tb[new_key] else return nil end";
lua_pushlightuserdata(L, &ngx_http_lua_get_headers_metatable_key);
/* metatable for ngx.req.get_headers(_, true)
* and ngx.resp.get_headers(_, true) */
lua_createtable(L, 0, 1);

rc = luaL_loadbuffer(L, buf, sizeof(buf) - 1,
"ngx.req.get_headers __index");
}
rc = luaL_loadbuffer(L, buf, sizeof(buf) - 1,
"ngx_req.get_headers and ngx.resp.get_headers __index");

if (rc != 0) {
ngx_log_error(NGX_LOG_ERR, log, 0,
"failed to load Lua code of the metamethod for "
"ngx.req.get_headers: %i: %s", rc, lua_tostring(L, -1));
"ngx.req.get_headers, ngx.resp.get_headers: %i: %s", rc, lua_tostring(L, -1));

lua_pop(L, 3);
return;
}

lua_setfield(L, -2, "__index");
lua_rawset(L, LUA_REGISTRYINDEX);

}


Expand Down
3 changes: 2 additions & 1 deletion src/ngx_http_lua_headers.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
#include "ngx_http_lua_common.h"


void ngx_http_lua_inject_req_header_api(lua_State *L);
void ngx_http_lua_inject_resp_header_api(lua_State *L);
void ngx_http_lua_inject_req_header_api(ngx_log_t *log, lua_State *L);
void ngx_http_lua_inject_metatable_header_api(ngx_log_t *log, lua_State *L);


#endif /* _NGX_HTTP_LUA_HEADERS_H_INCLUDED_ */
Expand Down
8 changes: 4 additions & 4 deletions src/ngx_http_lua_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,7 @@ char ngx_http_lua_code_cache_key;
char ngx_http_lua_regex_cache_key;
char ngx_http_lua_socket_pool_key;
char ngx_http_lua_coroutines_key;
char ngx_http_lua_req_get_headers_metatable_key;

char ngx_http_lua_get_headers_metatable_key;

ngx_uint_t ngx_http_lua_location_hash = 0;
ngx_uint_t ngx_http_lua_content_length_hash = 0;
Expand Down Expand Up @@ -782,7 +781,7 @@ static void
ngx_http_lua_inject_ngx_api(lua_State *L, ngx_http_lua_main_conf_t *lmcf,
ngx_log_t *log)
{
lua_createtable(L, 0 /* narr */, 97 /* nrec */); /* ngx.* */
lua_createtable(L, 0 /* narr */, 98 /* nrec */); /* ngx.* */

ngx_http_lua_inject_arg_api(L);

Expand All @@ -804,6 +803,7 @@ ngx_http_lua_inject_ngx_api(lua_State *L, ngx_http_lua_main_conf_t *lmcf,

ngx_http_lua_inject_req_api(log, L);
ngx_http_lua_inject_resp_header_api(L);
ngx_http_lua_inject_metatable_header_api(log, L);
ngx_http_lua_inject_variable_api(L);
ngx_http_lua_inject_shdict_api(lmcf, L);
ngx_http_lua_inject_socket_tcp_api(log, L);
Expand Down Expand Up @@ -2151,7 +2151,7 @@ ngx_http_lua_inject_req_api(ngx_log_t *log, lua_State *L)

lua_createtable(L, 0 /* narr */, 23 /* nrec */); /* .req */

ngx_http_lua_inject_req_header_api(log, L);
ngx_http_lua_inject_req_header_api(L);
ngx_http_lua_inject_req_uri_api(log, L);
ngx_http_lua_inject_req_args_api(L);
ngx_http_lua_inject_req_body_api(L);
Expand Down
4 changes: 2 additions & 2 deletions src/ngx_http_lua_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ extern char ngx_http_lua_coroutine_parents_key;
/* coroutine anchoring table key in Lua VM registry */
extern char ngx_http_lua_coroutines_key;

/* key to the metatable for ngx.req.get_headers() */
extern char ngx_http_lua_req_get_headers_metatable_key;
/* key to the metatable for ngx.req.get_headers() and ngx.resp.get_headers() */
extern char ngx_http_lua_get_headers_metatable_key;


#ifndef ngx_str_set
Expand Down
Loading