Skip to content

Commit f1b1e76

Browse files
dndxdoujiang24
authored andcommitted
feature: add the balancer.recreate_request function, which allows user to recreate request buffer in balancer phase. (#302)
This allows certain request parameters, such as headers (including `Host` header) to be modified between balancer retries.
1 parent fa672ab commit f1b1e76

File tree

3 files changed

+106
-1
lines changed

3 files changed

+106
-1
lines changed

lib/ngx/balancer.lua

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ if subsystem == 'http' then
3838
int ngx_http_lua_ffi_balancer_set_timeouts(ngx_http_request_t *r,
3939
long connect_timeout, long send_timeout,
4040
long read_timeout, char **err);
41+
42+
int ngx_http_lua_ffi_balancer_recreate_request(ngx_http_request_t *r,
43+
char **err);
4144
]]
4245

4346
ngx_lua_ffi_balancer_set_current_peer =
@@ -207,4 +210,25 @@ function _M.set_timeouts(connect_timeout, send_timeout, read_timeout)
207210
end
208211

209212

213+
if subsystem == 'http' then
214+
function _M.recreate_request()
215+
local r = get_request()
216+
if not r then
217+
error("no request found")
218+
end
219+
220+
local rc = C.ngx_http_lua_ffi_balancer_recreate_request(r, errmsg)
221+
if rc == FFI_OK then
222+
return true
223+
end
224+
225+
if errmsg[0] ~= nil then
226+
return nil, ffi_str(errmsg[0])
227+
end
228+
229+
return nil, "failed to recreate the upstream request"
230+
end
231+
end
232+
233+
210234
return _M

lib/ngx/balancer.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,15 @@ Table of Contents
99
* [Name](#name)
1010
* [Status](#status)
1111
* [Synopsis](#synopsis)
12+
* [http subsystem](#http-subsystem)
13+
* [stream subsystem](#stream-subsystem)
1214
* [Description](#description)
1315
* [Methods](#methods)
1416
* [set_current_peer](#set_current_peer)
1517
* [set_more_tries](#set_more_tries)
1618
* [get_last_failure](#get_last_failure)
1719
* [set_timeouts](#set_timeouts)
20+
* [recreate_request](#recreate_request)
1821
* [Community](#community)
1922
* [English Mailing List](#english-mailing-list)
2023
* [Chinese Mailing List](#chinese-mailing-list)
@@ -79,6 +82,8 @@ http {
7982
}
8083
```
8184

85+
[Back to TOC](#table-of-contents)
86+
8287
stream subsystem
8388
----------------
8489

@@ -121,6 +126,8 @@ stream {
121126
}
122127
```
123128

129+
[Back to TOC](#table-of-contents)
130+
124131
Description
125132
===========
126133

@@ -237,6 +244,32 @@ This function was first added in the `0.1.7` version of this library.
237244

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

247+
recreate_request
248+
----------------
249+
**syntax:** `ok, err = balancer.recreate_request()`
250+
251+
**context:** *balancer_by_lua**
252+
253+
Recreates the request buffer for sending to the upstream server. This is useful, for example
254+
if you want to change a request header field to the new upstream server on balancer retries.
255+
256+
Normally this does not work because the request buffer is created once during upstream module
257+
initialization and won't be regenerated for subsequent retries. However you can use
258+
`proxy_set_header My-Header $my_header` and set the `ngx.var.my_header` variable inside the
259+
balancer phase. Calling `balancer.recreate_request()` after updating a header field will
260+
cause the request buffer to be re-generated and the `My-Header` header will thus contain
261+
the new value.
262+
263+
**Warning:** because the request buffer has to be recreated and such allocation occurs on the
264+
request memory pool, the old buffer has to be thrown away and will only be freed after the request
265+
finishes. Do not call this function too often or memory leaks may be noticeable. Even so, a call
266+
to this function should be made **only** if you know the request buffer must be regenerated,
267+
instead of unconditionally in each balancer retries.
268+
269+
This function was first added in the `0.1.20` version of this library.
270+
271+
[Back to TOC](#table-of-contents)
272+
240273
Community
241274
=========
242275

t/balancer.t

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use t::TestCore;
99

1010
repeat_each(2);
1111

12-
plan tests => repeat_each() * (blocks() * 4 + 5);
12+
plan tests => repeat_each() * (blocks() * 4 + 6);
1313

1414
$ENV{TEST_NGINX_LUA_PACKAGE_PATH} = "$t::TestCore::lua_package_path";
1515

@@ -834,3 +834,51 @@ GET /t
834834
[lua] log_by_lua(nginx.conf:59):2: ngx.var.upstream_addr is 127.0.0.3:12345, 127.0.0.3:12346
835835
--- no_error_log
836836
[alert]
837+
838+
839+
840+
=== TEST 19: recreate upstream module requests with header change
841+
--- http_config
842+
lua_package_path "$TEST_NGINX_LUA_PACKAGE_PATH";
843+
844+
upstream backend {
845+
server 0.0.0.1;
846+
847+
balancer_by_lua_block {
848+
print("here")
849+
local b = require "ngx.balancer"
850+
851+
if ngx.ctx.balancer_run then
852+
assert(b.set_current_peer("127.0.0.1", tonumber(ngx.var.server_port)))
853+
ngx.var.test = "second"
854+
assert(b.recreate_request())
855+
856+
else
857+
ngx.ctx.balancer_run = true
858+
assert(b.set_current_peer("127.0.0.3", 12345))
859+
assert(b.set_more_tries(1))
860+
end
861+
}
862+
}
863+
--- config
864+
location = /t {
865+
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504 http_403 http_404;
866+
proxy_next_upstream_tries 2;
867+
868+
set $test "first";
869+
870+
proxy_set_header X-Test $test;
871+
proxy_pass http://backend/upstream;
872+
}
873+
874+
location = /upstream {
875+
return 200 "value is: $http_x_test";
876+
}
877+
--- request
878+
GET /t
879+
--- response_body: value is: second
880+
--- error_log
881+
connect() failed (111: Connection refused) while connecting to upstream, client: 127.0.0.1
882+
--- no_error_log
883+
[warn]
884+
[crit]

0 commit comments

Comments
 (0)