From 1bf444121bd69c23dd5a38e2339332e76966c4e4 Mon Sep 17 00:00:00 2001 From: goecho Date: Wed, 5 Aug 2015 15:44:06 +0800 Subject: [PATCH 1/3] bugfix:ngx.encode_args() not escaped "|" to "%7c". see: https://en.wikipedia.org/wiki/Percent-encoding --- src/ngx_http_lua_util.c | 43 +++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 65916be29c..8e5b6bd400 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1841,6 +1841,26 @@ ngx_http_lua_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) /* ~}| {zyx wvut srqp onml kjih gfed cba` */ 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + }; + + /* not ALPHA, DIGIT, "-", ".", "_", "~" */ + + static uint32_t uri_component[] = { + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + + /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ + 0xfc009fff, /* 1111 1100 0000 0000 1001 1111 1111 1111 */ + + /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ + 0x78000001, /* 0111 1000 0000 0000 0000 0000 0000 0001 */ + + /* ~}| {zyx wvut srqp onml kjih gfed cba` */ + 0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ @@ -1909,9 +1929,8 @@ ngx_http_lua_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) /* mail_auth is the same as memcached */ - static uint32_t *map[] = - { uri, args, html, refresh, memcached, memcached }; - + static uint32_t *map[] = + { uri, args, uri_component, html, refresh, memcached, memcached }; escape = map[type]; @@ -2317,7 +2336,7 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, key = (u_char *) lua_tolstring(L, -2, &key_len); key_escape = 2 * ngx_http_lua_escape_uri(NULL, key, key_len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI_COMPONENT); total_escape += key_escape; switch (lua_type(L, -1)) { @@ -2326,7 +2345,7 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, value = (u_char *) lua_tolstring(L, -1, &value_len); total_escape += 2 * ngx_http_lua_escape_uri(NULL, value, value_len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI_COMPONENT); len += key_len + value_len + (sizeof("=") - 1); n++; @@ -2367,7 +2386,7 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, total_escape += 2 * ngx_http_lua_escape_uri(NULL, value, value_len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI_COMPONENT); len += key_len + value_len + (sizeof("=") - 1); } @@ -2424,7 +2443,7 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, if (total_escape) { p = (u_char *) ngx_http_lua_escape_uri(p, key, key_len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI_COMPONENT); } else { dd("shortcut: no escape required"); @@ -2438,7 +2457,7 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, if (total_escape) { p = (u_char *) ngx_http_lua_escape_uri(p, value, value_len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI_COMPONENT); } else { p = ngx_copy(p, value, value_len); @@ -2457,7 +2476,7 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, if (lua_toboolean(L, -1)) { if (total_escape) { p = (u_char *) ngx_http_lua_escape_uri(p, key, key_len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI_COMPONENT); } else { dd("shortcut: no escape required"); @@ -2485,7 +2504,7 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, if (total_escape) { p = (u_char *) ngx_http_lua_escape_uri(p, key, key_len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI_COMPONENT); } else { dd("shortcut: no escape required"); @@ -2504,7 +2523,7 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, p = (u_char *) ngx_http_lua_escape_uri(p, key, key_len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI_COMPONENT); } else { dd("shortcut: no escape required"); @@ -2520,7 +2539,7 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, p = (u_char *) ngx_http_lua_escape_uri(p, value, value_len, - NGX_ESCAPE_URI); + NGX_ESCAPE_URI_COMPONENT); } else { p = ngx_copy(p, value, value_len); From 5e3992e62792789b02b09adaeefdb9c8de1674bd Mon Sep 17 00:00:00 2001 From: goecho Date: Mon, 10 Aug 2015 19:26:55 +0800 Subject: [PATCH 2/3] bugfix:ngx.encode_args() not escaped "|",",","$","@","`";100% compatible with What Google Chrome's JavaScript API function encodeURIComponent() does. see:https://tools.ietf.org/html/rfc2396. --- src/ngx_http_lua_util.c | 18 +++++++----- t/030-uri-args.t | 62 +++++++++++++++++++++++++---------------- 2 files changed, 49 insertions(+), 31 deletions(-) diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index 8e5b6bd400..98f1fbd3f6 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1853,7 +1853,7 @@ ngx_http_lua_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ - 0xfc009fff, /* 1111 1100 0000 0000 1001 1111 1111 1111 */ + 0xfc00987d, /* 1111 1100 0000 0000 1001 1000 0111 1101 */ /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ 0x78000001, /* 0111 1000 0000 0000 0000 0000 0000 0001 */ @@ -1929,7 +1929,7 @@ ngx_http_lua_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) /* mail_auth is the same as memcached */ - static uint32_t *map[] = + static uint32_t *map[] = { uri, args, uri_component, html, refresh, memcached, memcached }; escape = map[type]; @@ -2443,7 +2443,8 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, if (total_escape) { p = (u_char *) ngx_http_lua_escape_uri(p, key, key_len, - NGX_ESCAPE_URI_COMPONENT); + NGX_ESCAPE_URI_COMPONENT + ); } else { dd("shortcut: no escape required"); @@ -2457,7 +2458,8 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, if (total_escape) { p = (u_char *) ngx_http_lua_escape_uri(p, value, value_len, - NGX_ESCAPE_URI_COMPONENT); + NGX_ESCAPE_URI_COMPONENT + ); } else { p = ngx_copy(p, value, value_len); @@ -2476,7 +2478,7 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, if (lua_toboolean(L, -1)) { if (total_escape) { p = (u_char *) ngx_http_lua_escape_uri(p, key, key_len, - NGX_ESCAPE_URI_COMPONENT); + NGX_ESCAPE_URI_COMPONENT); } else { dd("shortcut: no escape required"); @@ -2523,7 +2525,8 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, p = (u_char *) ngx_http_lua_escape_uri(p, key, key_len, - NGX_ESCAPE_URI_COMPONENT); + NGX_ESCAPE_URI_COMPONENT + ); } else { dd("shortcut: no escape required"); @@ -2539,7 +2542,8 @@ ngx_http_lua_process_args_option(ngx_http_request_t *r, lua_State *L, p = (u_char *) ngx_http_lua_escape_uri(p, value, value_len, - NGX_ESCAPE_URI_COMPONENT); + NGX_ESCAPE_URI_COMPONENT + ); } else { p = ngx_copy(p, value, value_len); diff --git a/t/030-uri-args.t b/t/030-uri-args.t index 83b3842a7a..bd24e16071 100644 --- a/t/030-uri-args.t +++ b/t/030-uri-args.t @@ -750,7 +750,21 @@ args: -=== TEST 33: ngx.encode_args (bad arg) +=== TEST 33: ngx.encode_args (escaping) +--- config + location /lua { + content_by_lua ' + local t = {bar = "-_.!~*\'()", foo = ",$@|`"} + ngx.say("args: ", ngx.encode_args(t)) + '; + } +--- request +GET /lua +--- response_body +args: foo=%2C%24%40%7C%60&bar=-_.!~*'() + + +=== TEST 34: ngx.encode_args (bad arg) --- config location /lua { content_by_lua ' @@ -765,7 +779,7 @@ rc: false, err: bad argument #1 to '?' (table expected, got boolean) -=== TEST 34: max args (limited after normal key=value) +=== TEST 35: max args (limited after normal key=value) --- config location /lua { content_by_lua ' @@ -792,7 +806,7 @@ lua hit query args limit 2 -=== TEST 35: max args (limited after an orphan key) +=== TEST 36: max args (limited after an orphan key) --- config location /lua { content_by_lua ' @@ -819,7 +833,7 @@ lua hit query args limit 2 -=== TEST 36: max args (limited after an empty key, but non-emtpy values) +=== TEST 37: max args (limited after an empty key, but non-emtpy values) --- config location /lua { content_by_lua ' @@ -848,7 +862,7 @@ lua hit query args limit 2 -=== TEST 37: default max 100 args +=== TEST 38: default max 100 args --- config location /lua { content_by_lua ' @@ -896,7 +910,7 @@ lua hit query args limit 100 -=== TEST 38: custom max 102 args +=== TEST 39: custom max 102 args --- config location /lua { content_by_lua ' @@ -944,7 +958,7 @@ lua hit query args limit 102 -=== TEST 39: custom unlimited args +=== TEST 40: custom unlimited args --- config location /lua { content_by_lua ' @@ -989,7 +1003,7 @@ CORE::join("", @k); -=== TEST 40: rewrite uri and args (multi-value args) +=== TEST 41: rewrite uri and args (multi-value args) --- config location /bar { echo $server_protocol $query_string; @@ -1009,7 +1023,7 @@ HTTP/1.0 a=3&b=5&b=6 -=== TEST 41: ngx.decode_args (sanity) +=== TEST 42: ngx.decode_args (sanity) --- config location /lua { content_by_lua ' @@ -1027,7 +1041,7 @@ b = foo -=== TEST 42: ngx.decode_args (multi-value) +=== TEST 43: ngx.decode_args (multi-value) --- config location /lua { content_by_lua ' @@ -1045,7 +1059,7 @@ b = foo -=== TEST 43: ngx.decode_args (empty string) +=== TEST 44: ngx.decode_args (empty string) --- config location /lua { content_by_lua ' @@ -1061,7 +1075,7 @@ n = 0 -=== TEST 44: ngx.decode_args (boolean args) +=== TEST 45: ngx.decode_args (boolean args) --- config location /lua { content_by_lua ' @@ -1079,7 +1093,7 @@ b = true -=== TEST 45: ngx.decode_args (empty value args) +=== TEST 46: ngx.decode_args (empty value args) --- config location /lua { content_by_lua ' @@ -1097,7 +1111,7 @@ b = -=== TEST 46: ngx.decode_args (max_args = 1) +=== TEST 47: ngx.decode_args (max_args = 1) --- config location /lua { content_by_lua ' @@ -1115,7 +1129,7 @@ b = nil -=== TEST 47: ngx.decode_args (max_args = -1) +=== TEST 48: ngx.decode_args (max_args = -1) --- config location /lua { content_by_lua ' @@ -1133,7 +1147,7 @@ b = foo -=== TEST 48: ngx.decode_args should not modify lua strings in place +=== TEST 49: ngx.decode_args should not modify lua strings in place --- config location /lua { content_by_lua ' @@ -1161,7 +1175,7 @@ s = f+f=bar&B=foo -=== TEST 49: ngx.decode_args should not modify lua strings in place (sample from Xu Jian) +=== TEST 50: ngx.decode_args should not modify lua strings in place (sample from Xu Jian) --- config lua_need_request_body on; location /t { @@ -1221,7 +1235,7 @@ method: zadd -=== TEST 50: recursive rewrite +=== TEST 51: recursive rewrite --- config rewrite_by_lua ' local args = ngx.var.args @@ -1253,7 +1267,7 @@ rewrite or internal redirection cycle while processing "/jump" -=== TEST 51: boolean values in ngx.encode_args (trailing arg) +=== TEST 52: boolean values in ngx.encode_args (trailing arg) --- config location /lua { set_by_lua $args_str ' @@ -1277,7 +1291,7 @@ GET /lua -=== TEST 52: false boolean values in ngx.encode_args +=== TEST 53: false boolean values in ngx.encode_args --- config location /lua { set_by_lua $args_str ' @@ -1300,7 +1314,7 @@ GET /lua -=== TEST 53: false boolean values in ngx.encode_args (escaping) +=== TEST 54: false boolean values in ngx.encode_args (escaping) --- config location /lua { set_by_lua $args_str ' @@ -1323,7 +1337,7 @@ GET /lua -=== TEST 54: true boolean values in ngx.encode_args (escaping) +=== TEST 55: true boolean values in ngx.encode_args (escaping) --- config location /lua { set_by_lua $args_str ' @@ -1347,7 +1361,7 @@ GET /lua -=== TEST 55: rewrite uri and args (boolean in multi-value args) +=== TEST 56: rewrite uri and args (boolean in multi-value args) --- config location /bar { echo $server_protocol $query_string; @@ -1373,7 +1387,7 @@ GET /lua -=== TEST 56: rewrite uri and args (boolean value) +=== TEST 57: rewrite uri and args (boolean value) --- config location /bar { echo $server_protocol $query_string; From b226e979415316479e22483bda637f2097097487 Mon Sep 17 00:00:00 2001 From: goecho Date: Mon, 10 Aug 2015 19:32:09 +0800 Subject: [PATCH 3/3] add a simple test case on ngx.encode_args() --- t/030-uri-args.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/030-uri-args.t b/t/030-uri-args.t index bd24e16071..6ff0a9bd08 100644 --- a/t/030-uri-args.t +++ b/t/030-uri-args.t @@ -10,7 +10,7 @@ log_level('warn'); repeat_each(2); #repeat_each(1); -plan tests => repeat_each() * (blocks() * 2 + 17); +plan tests => repeat_each() * (blocks() * 2 + 18); no_root_location();