Skip to content

Commit

Permalink
feature: support ngx.location.capture and ngx.location.capture_multi …
Browse files Browse the repository at this point in the history
…with `headers` option.
  • Loading branch information
ytlm authored Jul 7, 2024
1 parent 39d165c commit 0a1c704
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 10 deletions.
30 changes: 29 additions & 1 deletion README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -966,7 +966,6 @@ TODO
* cosocket: add support in the context of [init_by_lua*](#init_by_lua).
* cosocket: review and merge aviramc's [patch](https://github.com/openresty/lua-nginx-module/pull/290) for adding the `bsdrecv` method.
* cosocket: add configure options for different strategies of handling the cosocket connection exceeding in the pools.
* review and apply vadim-pavlov's patch for [ngx.location.capture](#ngxlocationcapture)'s `extra_headers` option
* use `ngx_hash_t` to optimize the built-in header look-up process for [ngx.req.set_header](#ngxreqset_header), and etc.
* add `ignore_resp_headers`, `ignore_resp_body`, and `ignore_resp` options to [ngx.location.capture](#ngxlocationcapture) and [ngx.location.capture_multi](#ngxlocationcapture_multi) methods, to allow micro performance tuning on the user side.
* add automatic Lua code time slicing support by yielding and resuming the Lua VM actively via Lua's debug hooks.
Expand Down Expand Up @@ -4305,6 +4304,8 @@ argument, which supports the options:
specify the subrequest's request body (string value only).
* `args`
specify the subrequest's URI query arguments (both string value and Lua tables are accepted)
* `headers`
specify the subrequest's request headers (Lua table only). this headers will override the original headers of the subrequest.
* `ctx`
specify a Lua table to be the [ngx.ctx](#ngxctx) table for the subrequest. It can be the current request's [ngx.ctx](#ngxctx) table, which effectively makes the parent and its subrequest to share exactly the same context table. This option was first introduced in the `v0.3.1rc25` release.
* `vars`
Expand Down Expand Up @@ -4456,6 +4457,33 @@ Accessing `/lua` will yield the output
dog = hello
cat = 32

The `headers` option can be used to specify the request headers for the subrequest. The value of this option should be a Lua table where the keys are the header names and the values are the header values. For example,

```lua

location /foo {
content_by_lua_block {
ngx.print(ngx.var.http_x_test)
}
}

location /lua {
content_by_lua_block {
local res = ngx.location.capture("/foo", {
headers = {
["X-Test"] = "aa",
}
})
ngx.print(res.body)
}
}
```

Accessing `/lua` will yield the output


aa


The `ctx` option can be used to specify a custom Lua table to serve as the [ngx.ctx](#ngxctx) table for the subrequest.

Expand Down
66 changes: 57 additions & 9 deletions src/ngx_http_lua_subrequest.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,10 @@ static ngx_str_t ngx_http_lua_content_length_header_key =
static ngx_int_t ngx_http_lua_adjust_subrequest(ngx_http_request_t *sr,
ngx_uint_t method, int forward_body,
ngx_http_request_body_t *body, unsigned vars_action,
ngx_array_t *extra_vars);
ngx_array_t *extra_vars, ngx_array_t *extra_headers);
static int ngx_http_lua_ngx_location_capture(lua_State *L);
static int ngx_http_lua_ngx_location_capture_multi(lua_State *L);
static void ngx_http_lua_process_vars_option(ngx_http_request_t *r,
static void ngx_http_lua_process_keyval_option(ngx_http_request_t *r,
lua_State *L, int table, ngx_array_t **varsp);
static ngx_int_t ngx_http_lua_subrequest_add_extra_vars(ngx_http_request_t *r,
ngx_array_t *extra_vars);
Expand All @@ -79,7 +79,7 @@ static void ngx_http_lua_cancel_subreq(ngx_http_request_t *r);
static ngx_int_t ngx_http_post_request_to_head(ngx_http_request_t *r);
static ngx_int_t ngx_http_lua_copy_in_file_request_body(ngx_http_request_t *r);
static ngx_int_t ngx_http_lua_copy_request_headers(ngx_http_request_t *sr,
ngx_http_request_t *pr, int pr_not_chunked);
ngx_http_request_t *pr, int pr_not_chunked, ngx_array_t *extra_headers);


enum {
Expand Down Expand Up @@ -127,6 +127,7 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L)
ngx_http_lua_ctx_t *sr_ctx;
ngx_http_lua_ctx_t *ctx;
ngx_array_t *extra_vars;
ngx_array_t *extra_headers;
ngx_str_t uri;
ngx_str_t args;
ngx_str_t extra_args;
Expand Down Expand Up @@ -224,6 +225,7 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L)
coctx->pending_subreqs = 0;

extra_vars = NULL;
extra_headers = NULL;

for (index = 0; index < nsubreqs; index++) {
coctx->pending_subreqs++;
Expand Down Expand Up @@ -263,6 +265,11 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L)
extra_vars->nelts = 0;
}

if (extra_headers != NULL) {
/* flush out existing elements in the array */
extra_headers->nelts = 0;
}

vars_action = 0;

custom_ctx = 0;
Expand Down Expand Up @@ -318,7 +325,7 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L)

switch (lua_type(L, -1)) {
case LUA_TTABLE:
ngx_http_lua_process_vars_option(r, L, -1, &extra_vars);
ngx_http_lua_process_keyval_option(r, L, -1, &extra_vars);

dd("post process vars top: %d", lua_gettop(L));
break;
Expand All @@ -335,6 +342,29 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L)

dd("queries query uri opts: %d", lua_gettop(L));

/* check the headers option */

lua_getfield(L, 4, "headers");

switch (lua_type(L, -1)) {
case LUA_TTABLE:
ngx_http_lua_process_keyval_option(r, L, -1, &extra_headers);

dd("post process vars top: %d", lua_gettop(L));
break;

case LUA_TNIL:
/* do nothing */
break;

default:
return luaL_error(L, "Bad headers option value");
}

lua_pop(L, 1); /* pop the headers */

dd("queries query uri opts: %d", lua_gettop(L));

/* check the share_all_vars option */

lua_getfield(L, 4, "share_all_vars");
Expand Down Expand Up @@ -595,7 +625,8 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L)
ngx_http_set_ctx(sr, sr_ctx, ngx_http_lua_module);

rc = ngx_http_lua_adjust_subrequest(sr, method, always_forward_body,
body, vars_action, extra_vars);
body, vars_action, extra_vars,
extra_headers);

if (rc != NGX_OK) {
ngx_http_lua_cancel_subreq(sr);
Expand Down Expand Up @@ -631,7 +662,7 @@ ngx_http_lua_ngx_location_capture_multi(lua_State *L)
static ngx_int_t
ngx_http_lua_adjust_subrequest(ngx_http_request_t *sr, ngx_uint_t method,
int always_forward_body, ngx_http_request_body_t *body,
unsigned vars_action, ngx_array_t *extra_vars)
unsigned vars_action, ngx_array_t *extra_vars, ngx_array_t *extra_headers)
{
ngx_http_request_t *r;
ngx_http_core_main_conf_t *cmcf;
Expand Down Expand Up @@ -667,7 +698,9 @@ ngx_http_lua_adjust_subrequest(ngx_http_request_t *sr, ngx_uint_t method,
}
}

if (ngx_http_lua_copy_request_headers(sr, r, pr_not_chunked) != NGX_OK) {
if (ngx_http_lua_copy_request_headers(sr, r, pr_not_chunked, extra_headers)
!= NGX_OK)
{
return NGX_ERROR;
}

Expand Down Expand Up @@ -882,7 +915,7 @@ ngx_http_lua_subrequest_add_extra_vars(ngx_http_request_t *sr,


static void
ngx_http_lua_process_vars_option(ngx_http_request_t *r, lua_State *L,
ngx_http_lua_process_keyval_option(ngx_http_request_t *r, lua_State *L,
int table, ngx_array_t **varsp)
{
ngx_array_t *vars;
Expand Down Expand Up @@ -1635,10 +1668,11 @@ ngx_http_lua_copy_in_file_request_body(ngx_http_request_t *r)

static ngx_int_t
ngx_http_lua_copy_request_headers(ngx_http_request_t *sr,
ngx_http_request_t *pr, int pr_not_chunked)
ngx_http_request_t *pr, int pr_not_chunked, ngx_array_t *extra_headers)
{
ngx_table_elt_t *clh, *header;
ngx_list_part_t *part;
ngx_keyval_t *header_keyval;
ngx_chain_t *in;
ngx_uint_t i;
u_char *p;
Expand Down Expand Up @@ -1742,6 +1776,20 @@ ngx_http_lua_copy_request_headers(ngx_http_request_t *sr,
}
}

if (extra_headers && extra_headers->nelts > 0) {

header_keyval = extra_headers->elts;

for (i = 0; i < extra_headers->nelts; i++, header_keyval++) {

if (ngx_http_lua_set_input_header(sr, header_keyval->key,
header_keyval->value, 1) == NGX_ERROR)
{
return NGX_ERROR;
}
}
}

dd("after: parent req headers count: %d",
(int) pr->headers_in.headers.part.nelts);

Expand Down
72 changes: 72 additions & 0 deletions t/027-multi-capture.t
Original file line number Diff line number Diff line change
Expand Up @@ -752,3 +752,75 @@ proxy_cache_path conf/cache levels=1:2 keys_zone=STATIC:10m inactive=10m max_siz
GET /foo
--- response_body
ok



=== TEST 14: capture multi with headers
--- config
location /foo {
content_by_lua_block {
local res1, res2, res3 = ngx.location.capture_multi{
{"/test", { headers = { ["X-Test-Header"] = "aa"} } },
{"/test", { headers = { ["X-Test-Header"] = "bb"} } },
{"/test"},
}
ngx.say("res1.status = " .. res1.status)
ngx.say("res1.body = " .. res1.body)
ngx.say("res2.status = " .. res2.status)
ngx.say("res2.body = " .. res2.body)
ngx.say("res3.status = " .. res3.status)
ngx.say("res3.body = " .. res3.body)
}
}

location = /test {
content_by_lua_block {
ngx.print(ngx.var.http_x_test_header)
}
}
--- request
GET /foo
--- response_body
res1.status = 200
res1.body = aa
res2.status = 200
res2.body = bb
res3.status = 200
res3.body = nil



=== TEST 15: capture multi with headers override
--- config
location /foo {
content_by_lua_block {
local res1, res2, res3 = ngx.location.capture_multi{
{"/test", { headers = { ["X-Test-Header"] = "aa"} } },
{"/test", { headers = { ["X-Test-Header"] = "bb"} } },
{"/test"},
}
ngx.say("res1.status = " .. res1.status)
ngx.say("res1.body = " .. res1.body)
ngx.say("res2.status = " .. res2.status)
ngx.say("res2.body = " .. res2.body)
ngx.say("res3.status = " .. res3.status)
ngx.say("res3.body = " .. res3.body)
}
}

location = /test {
content_by_lua_block {
ngx.print(ngx.var.http_x_test_header)
}
}
--- request
GET /foo
--- more_headers
X-Test-Header: cc
--- response_body
res1.status = 200
res1.body = aa
res2.status = 200
res2.body = bb
res3.status = 200
res3.body = cc

0 comments on commit 0a1c704

Please sign in to comment.