Skip to content

Commit 5d15172

Browse files
zhuizhuhaomengagentzh
authored andcommitted
feature: ngx.req.set_uri(): added the 'binary' optional boolean arg to allow arbitrary binary data in the unencoded URI.
Signed-off-by: Yichun Zhang (agentzh) <[email protected]>
1 parent 8746f64 commit 5d15172

File tree

8 files changed

+166
-41
lines changed

8 files changed

+166
-41
lines changed

README.markdown

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4431,7 +4431,7 @@ See also [ngx.req.get_method](#ngxreqget_method).
44314431
ngx.req.set_uri
44324432
---------------
44334433

4434-
**syntax:** *ngx.req.set_uri(uri, jump?)*
4434+
**syntax:** *ngx.req.set_uri(uri, jump?, binary?)*
44354435

44364436
**context:** *set_by_lua&#42;, rewrite_by_lua&#42;, access_by_lua&#42;, content_by_lua&#42;, header_filter_by_lua&#42;, body_filter_by_lua&#42;*
44374437

@@ -4527,6 +4527,18 @@ or
45274527
ngx.req.set_uri("/foo", true)
45284528
```
45294529

4530+
Starting from `0.10.16` of this module, this function accepts an
4531+
optional boolean `binary` argument to allow arbitrary binary URI
4532+
data. By default, this `binary` argument is false and this function
4533+
will throw out a Lua error such as the one below when the `uri`
4534+
argument contains any control characters (ASCII Code 0 ~ 0x08, 0x0A ~ 0x1F and 0x7F).
4535+
4536+
4537+
[error] 23430#23430: *1 lua entry thread aborted: runtime error:
4538+
content_by_lua(nginx.conf:44):3: ngx.req.set_uri unsafe byte "0x00"
4539+
in "\x00foo" (maybe you want to set the 'binary' argument?)
4540+
4541+
45304542
This interface was first introduced in the `v0.3.1rc14` release.
45314543

45324544
[Back to TOC](#nginx-api-for-lua)

doc/HttpLuaModule.wiki

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3685,7 +3685,7 @@ See also [[#ngx.req.get_method|ngx.req.get_method]].
36853685
36863686
== ngx.req.set_uri ==
36873687
3688-
'''syntax:''' ''ngx.req.set_uri(uri, jump?)''
3688+
'''syntax:''' ''ngx.req.set_uri(uri, jump?, binary?)''
36893689
36903690
'''context:''' ''set_by_lua*, rewrite_by_lua*, access_by_lua*, content_by_lua*, header_filter_by_lua*, body_filter_by_lua*''
36913691
@@ -3771,6 +3771,18 @@ or
37713771
ngx.req.set_uri("/foo", true)
37723772
</geshi>
37733773
3774+
Starting from <code>0.10.16</code> of this module, this function accepts an
3775+
optional boolean <code>binary</code> argument to allow arbitrary binary URI
3776+
data. By default, this <code>binary</code> argument is false and this function
3777+
will throw out a Lua error such as the one below when the <code>uri</code>
3778+
argument contains any control characters (ASCII Code 0 ~ 0x08, 0x0A ~ 0x1F and 0x7F).
3779+
3780+
<geshi lang="text">
3781+
[error] 23430#23430: *1 lua entry thread aborted: runtime error:
3782+
content_by_lua(nginx.conf:44):3: ngx.req.set_uri unsafe byte "0x00"
3783+
in "\x00foo" (maybe you want to set the 'binary' argument?)
3784+
</geshi>
3785+
37743786
This interface was first introduced in the <code>v0.3.1rc14</code> release.
37753787
37763788
== ngx.req.set_uri_args ==

src/ngx_http_lua_control.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,12 @@ ngx_http_lua_ngx_redirect(lua_State *L)
186186
int n;
187187
u_char *p;
188188
u_char *uri;
189+
u_char byte;
189190
size_t len;
190191
ngx_table_elt_t *h;
191192
ngx_http_request_t *r;
193+
size_t buf_len;
194+
u_char *buf;
192195

193196
n = lua_gettop(L);
194197

@@ -239,8 +242,17 @@ ngx_http_lua_ngx_redirect(lua_State *L)
239242
"the headers");
240243
}
241244

242-
if (ngx_http_lua_check_unsafe_string(r, p, len, "redirect uri") != NGX_OK) {
243-
return luaL_error(L, "attempt to set unsafe redirect uri");
245+
if (ngx_http_lua_check_unsafe_uri_bytes(r, p, len, &byte) != NGX_OK) {
246+
buf_len = ngx_http_lua_escape_log(NULL, p, len) + 1;
247+
buf = ngx_palloc(r->pool, buf_len);
248+
if (buf == NULL) {
249+
return NGX_ERROR;
250+
}
251+
252+
ngx_http_lua_escape_log(buf, p, len);
253+
buf[buf_len - 1] = '\0';
254+
return luaL_error(L, "unsafe byte \"0x%02x\" in redirect uri \"%s\"",
255+
byte, buf);
244256
}
245257

246258
uri = ngx_palloc(r->pool, len);

src/ngx_http_lua_uri.c

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,18 @@ ngx_http_lua_ngx_req_set_uri(lua_State *L)
3232
ngx_http_request_t *r;
3333
size_t len;
3434
u_char *p;
35+
u_char byte;
3536
int n;
3637
int jump = 0;
38+
int binary = 0;
3739
ngx_http_lua_ctx_t *ctx;
40+
size_t buf_len;
41+
u_char *buf;
3842

3943
n = lua_gettop(L);
4044

41-
if (n != 1 && n != 2) {
42-
return luaL_error(L, "expecting 1 or 2 arguments but seen %d", n);
45+
if (n < 1 || n > 3) {
46+
return luaL_error(L, "expecting 1, 2 or 3 arguments but seen %d", n);
4347
}
4448

4549
r = ngx_http_lua_get_req(L);
@@ -55,8 +59,29 @@ ngx_http_lua_ngx_req_set_uri(lua_State *L)
5559
return luaL_error(L, "attempt to use zero-length uri");
5660
}
5761

58-
if (n == 2) {
62+
if (n >= 3) {
63+
luaL_checktype(L, 3, LUA_TBOOLEAN);
64+
binary = lua_toboolean(L, 3);
65+
}
66+
67+
if (!binary
68+
&& ngx_http_lua_check_unsafe_uri_bytes(r, p, len, &byte) != NGX_OK)
69+
{
70+
buf_len = ngx_http_lua_escape_log(NULL, p, len) + 1;
71+
buf = ngx_palloc(r->pool, buf_len);
72+
if (buf == NULL) {
73+
return NGX_ERROR;
74+
}
75+
76+
ngx_http_lua_escape_log(buf, p, len);
77+
buf[buf_len - 1] = '\0';
78+
79+
return luaL_error(L, "unsafe byte \"0x%02x\" in uri \"%s\" "
80+
"(maybe you want to set the 'binary' argument?)",
81+
byte, buf);
82+
}
5983

84+
if (n >= 2) {
6085
luaL_checktype(L, 2, LUA_TBOOLEAN);
6186
jump = lua_toboolean(L, 2);
6287

src/ngx_http_lua_util.h

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -496,17 +496,16 @@ ngx_inet_get_port(struct sockaddr *sa)
496496

497497

498498
static ngx_inline ngx_int_t
499-
ngx_http_lua_check_unsafe_string(ngx_http_request_t *r, u_char *str, size_t len,
500-
const char *name)
499+
ngx_http_lua_check_unsafe_uri_bytes(ngx_http_request_t *r, u_char *str,
500+
size_t len, u_char *byte)
501501
{
502-
size_t i, buf_len;
502+
size_t i;
503503
u_char c;
504-
u_char *buf, *src = str;
505504

506-
/* %00-%1F, %7F */
505+
/* %00-%08, %0A-%1F, %7F */
507506

508507
static uint32_t unsafe[] = {
509-
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
508+
0xfffffdff, /* 1111 1111 1111 1111 1111 1101 1111 1111 */
510509

511510
/* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
512511
0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */
@@ -526,20 +525,7 @@ ngx_http_lua_check_unsafe_string(ngx_http_request_t *r, u_char *str, size_t len,
526525
for (i = 0; i < len; i++, str++) {
527526
c = *str;
528527
if (unsafe[c >> 5] & (1 << (c & 0x1f))) {
529-
buf_len = ngx_http_lua_escape_log(NULL, src, len);
530-
buf = ngx_palloc(r->pool, buf_len);
531-
if (buf == NULL) {
532-
return NGX_ERROR;
533-
}
534-
535-
ngx_http_lua_escape_log(buf, src, len);
536-
537-
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
538-
"unsafe byte \"0x%uxd\" in %s \"%*s\"",
539-
(unsigned) c, name, buf_len, buf);
540-
541-
ngx_pfree(r->pool, buf);
542-
528+
*byte = c;
543529
return NGX_ERROR;
544530
}
545531
}

t/022-redirect.t

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use Test::Nginx::Socket::Lua;
99
repeat_each(2);
1010
#repeat_each(1);
1111

12-
plan tests => repeat_each() * (blocks() * 3 + 14);
12+
plan tests => repeat_each() * (blocks() * 3 + 9);
1313

1414
#no_diff();
1515
#no_long_string();
@@ -339,8 +339,7 @@ Location:
339339
foo:
340340
bar:
341341
--- error_log
342-
unsafe byte "0xd" in redirect uri "http://agentzh.org/foo\x0Dfoo:bar\x0Abar:foo"
343-
attempt to set unsafe redirect uri
342+
unsafe byte "0x0d" in redirect uri "http://agentzh.org/foo\x0Dfoo:bar\x0Abar:foo"
344343

345344

346345

@@ -360,8 +359,7 @@ Location:
360359
foo:
361360
bar:
362361
--- error_log
363-
unsafe byte "0xa" in redirect uri "http://agentzh.org/foo\x0Afoo:bar\x0Dbar:foo"
364-
attempt to set unsafe redirect uri
362+
unsafe byte "0x0a" in redirect uri "http://agentzh.org/foo\x0Afoo:bar\x0Dbar:foo"
365363

366364

367365

@@ -380,8 +378,7 @@ GET /t
380378
Location:
381379
foo:
382380
--- error_log
383-
unsafe byte "0xa" in redirect uri "\x0Afoo:http://agentzh.org/foo"
384-
attempt to set unsafe redirect uri
381+
unsafe byte "0x0a" in redirect uri "\x0Afoo:http://agentzh.org/foo"
385382

386383

387384

@@ -400,8 +397,7 @@ GET /t
400397
Location:
401398
foo:
402399
--- error_log
403-
unsafe byte "0xd" in redirect uri "\x0Dfoo:http://agentzh.org/foo"
404-
attempt to set unsafe redirect uri
400+
unsafe byte "0x0d" in redirect uri "\x0Dfoo:http://agentzh.org/foo"
405401

406402

407403

@@ -420,5 +416,4 @@ GET /t
420416
Location:
421417
foo:
422418
--- error_log
423-
unsafe byte "0xd" in redirect uri "\x0Dhttp\x5C://\x22agentzh.org\x22/foo"
424-
attempt to set unsafe redirect uri
419+
unsafe byte "0x0d" in redirect uri "\x0Dhttp\x5C://\x22agentzh.org\x22/foo"

t/030-uri-args.t

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ log_level('warn');
99
repeat_each(2);
1010
#repeat_each(1);
1111

12-
plan tests => repeat_each() * (blocks() * 2 + 21);
12+
13+
plan tests => repeat_each() * (blocks() * 2 + 23);
14+
1315

1416
no_root_location();
1517

@@ -1579,7 +1581,7 @@ args: foo=%2C%24%40%7C%60&bar=-_.!~*'()
15791581
location /t {
15801582
content_by_lua_block {
15811583
local new_uri = '\0foo'
1582-
ngx.req.set_uri(new_uri)
1584+
ngx.req.set_uri(new_uri, false, true)
15831585
ngx.say(ngx.var.uri)
15841586
}
15851587
}
@@ -1684,3 +1686,84 @@ bad argument #1 to 'set_uri_args' (string, number, or table expected, but got ni
16841686
--- error_code: 500
16851687
--- error_log
16861688
bad argument #1 to 'set_uri_args' (string, number, or table expected, but got userdata)
1689+
1690+
1691+
1692+
=== TEST 64: set_uri binary option with unsafe uri
1693+
explict specify binary option to true
1694+
--- config
1695+
location /t {
1696+
rewrite_by_lua_block {
1697+
local new_uri = "/foo\r\nbar"
1698+
ngx.req.set_uri(new_uri, false, true)
1699+
}
1700+
1701+
proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT;
1702+
}
1703+
1704+
location /foo {
1705+
content_by_lua_block {
1706+
ngx.say("request_uri: ", ngx.var.request_uri)
1707+
ngx.say("uri: ", ngx.var.uri)
1708+
}
1709+
}
1710+
--- request
1711+
GET /t
1712+
--- response_body eval
1713+
["request_uri: /foo%0D%0Abar\nuri: /foo\r\nbar\n", "request_uri: /foo%0D%0Abar\nuri: /foo\r\nbar\n"]
1714+
--- no_error_log
1715+
[error]
1716+
1717+
1718+
1719+
=== TEST 65: set_uri binary option with unsafe uri
1720+
explict specify binary option to false
1721+
--- config
1722+
location /t {
1723+
rewrite_by_lua_block {
1724+
local new_uri = "/foo\r\nbar"
1725+
ngx.req.set_uri(new_uri, false, false)
1726+
}
1727+
1728+
proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT;
1729+
}
1730+
1731+
location /foo {
1732+
content_by_lua_block {
1733+
ngx.say("request_uri: ", ngx.var.request_uri)
1734+
ngx.say("uri: ", ngx.var.uri)
1735+
}
1736+
}
1737+
--- request
1738+
GET /t
1739+
--- error_code: 500
1740+
--- error_log eval
1741+
qr{\[error\] \d+#\d+: \*\d+ lua entry thread aborted: runtime error: rewrite_by_lua\(nginx.conf:\d+\):\d+: unsafe byte "0x0d" in uri "/foo\\x0D\\x0Abar" \(maybe you want to set the 'binary' argument\?\)}
1742+
1743+
1744+
1745+
=== TEST 66: set_uri binary option with safe uri
1746+
explict specify binary option to false
1747+
--- config
1748+
location /t {
1749+
rewrite_by_lua_block {
1750+
local new_uri = "/foo bar"
1751+
ngx.req.set_uri(new_uri, false, true)
1752+
}
1753+
1754+
proxy_pass http://127.0.0.1:$TEST_NGINX_SERVER_PORT;
1755+
}
1756+
1757+
location /foo {
1758+
content_by_lua_block {
1759+
ngx.say("request_uri: ", ngx.var.request_uri)
1760+
ngx.say("uri: ", ngx.var.uri)
1761+
}
1762+
}
1763+
--- request
1764+
GET /t
1765+
--- response_body
1766+
request_uri: /foo%20bar
1767+
uri: /foo bar
1768+
--- no_error_log
1769+
[error]

t/162-static-module-location.t

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ __DATA__
1818
rewrite_by_lua_block {
1919
ngx.req.read_body();
2020
local args, _ = ngx.req.get_post_args();
21-
ngx.req.set_uri(args["url"], true);
21+
ngx.req.set_uri(args["url"], true, true);
2222
}
2323
}
2424
--- request

0 commit comments

Comments
 (0)