diff --git a/src/ngx_http_lua_args.c b/src/ngx_http_lua_args.c index 2712bcd7c2..0c700a8718 100644 --- a/src/ngx_http_lua_args.c +++ b/src/ngx_http_lua_args.c @@ -89,16 +89,25 @@ ngx_http_lua_ngx_req_get_uri_args(lua_State *L) int retval; int n; int max; + int raw = 0; n = lua_gettop(L); - if (n != 0 && n != 1) { - return luaL_error(L, "expecting 0 or 1 arguments but seen %d", n); + if (n != 0 && n != 1 && n != 2) { + return luaL_error(L, "expecting 0 or 1 or 2 arguments but seen %d", n); } - if (n == 1) { - max = luaL_checkinteger(L, 1); - lua_pop(L, 1); + if (n >= 1) { + if (lua_isnil(L, 1)) { + max = NGX_HTTP_LUA_MAX_ARGS; + + } else { + max = luaL_checkinteger(L, 1); + } + + if (n == 2) { + raw = lua_toboolean(L, 2); + } } else { max = NGX_HTTP_LUA_MAX_ARGS; @@ -130,7 +139,7 @@ ngx_http_lua_ngx_req_get_uri_args(lua_State *L) last = buf + r->args.len; - retval = ngx_http_lua_parse_args(L, buf, last, max); + retval = ngx_http_lua_parse_args(L, buf, last, max, raw); ngx_pfree(r->pool, buf); @@ -150,16 +159,25 @@ ngx_http_lua_ngx_req_get_post_args(lua_State *L) u_char *last; int n; int max; + int raw = 0; n = lua_gettop(L); - if (n != 0 && n != 1) { - return luaL_error(L, "expecting 0 or 1 arguments but seen %d", n); + if (n != 0 && n != 1 && n != 2) { + return luaL_error(L, "expecting 0 or 1 or 2 arguments but seen %d", n); } - if (n == 1) { - max = luaL_checkinteger(L, 1); - lua_pop(L, 1); + if (n >= 1) { + if (lua_isnil(L, 1)) { + max = NGX_HTTP_LUA_MAX_ARGS; + + } else { + max = luaL_checkinteger(L, 1); + } + + if (n == 2) { + raw = lua_toboolean(L, 2); + } } else { max = NGX_HTTP_LUA_MAX_ARGS; @@ -224,7 +242,7 @@ ngx_http_lua_ngx_req_get_post_args(lua_State *L) last = buf + len; - retval = ngx_http_lua_parse_args(L, buf, last, max); + retval = ngx_http_lua_parse_args(L, buf, last, max, raw); ngx_pfree(r->pool, buf); @@ -233,7 +251,8 @@ ngx_http_lua_ngx_req_get_post_args(lua_State *L) int -ngx_http_lua_parse_args(lua_State *L, u_char *buf, u_char *last, int max) +ngx_http_lua_parse_args(lua_State *L, u_char *buf, u_char *last, + int max, int raw) { u_char *p, *q; u_char *src, *dst; @@ -241,6 +260,7 @@ ngx_http_lua_parse_args(lua_State *L, u_char *buf, u_char *last, int max) size_t len; int count = 0; int top; + ngx_uint_t type; top = lua_gettop(L); @@ -248,15 +268,14 @@ ngx_http_lua_parse_args(lua_State *L, u_char *buf, u_char *last, int max) parsing_value = 0; q = p; - + type = raw ? NGX_UNESCAPE_URI_COMPONENT_RAW : NGX_UNESCAPE_URI_COMPONENT; while (p != last) { if (*p == '=' && ! parsing_value) { /* key data is between p and q */ src = q; dst = q; - ngx_http_lua_unescape_uri(&dst, &src, p - q, - NGX_UNESCAPE_URI_COMPONENT); + ngx_http_lua_unescape_uri(&dst, &src, p - q, type); dd("pushing key %.*s", (int) (dst - q), q); @@ -273,8 +292,7 @@ ngx_http_lua_parse_args(lua_State *L, u_char *buf, u_char *last, int max) /* reached the end of a key or a value, just save it */ src = q; dst = q; - ngx_http_lua_unescape_uri(&dst, &src, p - q, - NGX_UNESCAPE_URI_COMPONENT); + ngx_http_lua_unescape_uri(&dst, &src, p - q, type); dd("pushing key or value %.*s", (int) (dst - q), q); @@ -326,8 +344,7 @@ ngx_http_lua_parse_args(lua_State *L, u_char *buf, u_char *last, int max) if (p != q || parsing_value) { src = q; dst = q; - ngx_http_lua_unescape_uri(&dst, &src, p - q, - NGX_UNESCAPE_URI_COMPONENT); + ngx_http_lua_unescape_uri(&dst, &src, p - q, type); dd("pushing key or value %.*s", (int) (dst - q), q); @@ -439,9 +456,10 @@ ngx_http_lua_ffi_req_get_uri_args_count(ngx_http_request_t *r, int max, int ngx_http_lua_ffi_req_get_uri_args(ngx_http_request_t *r, u_char *buf, - ngx_http_lua_ffi_table_elt_t *out, int count) + ngx_http_lua_ffi_table_elt_t *out, int count, int raw) { int i, parsing_value = 0; + ngx_uint_t type; u_char *last, *p, *q; u_char *src, *dst; @@ -455,6 +473,7 @@ ngx_http_lua_ffi_req_get_uri_args(ngx_http_request_t *r, u_char *buf, last = buf + r->args.len; p = buf; q = p; + type = raw ? NGX_UNESCAPE_URI_COMPONENT_RAW : NGX_UNESCAPE_URI_COMPONENT; while (p != last) { if (*p == '=' && !parsing_value) { @@ -462,8 +481,7 @@ ngx_http_lua_ffi_req_get_uri_args(ngx_http_request_t *r, u_char *buf, src = q; dst = q; - ngx_http_lua_unescape_uri(&dst, &src, p - q, - NGX_UNESCAPE_URI_COMPONENT); + ngx_http_lua_unescape_uri(&dst, &src, p - q, type); dd("saving key %.*s", (int) (dst - q), q); @@ -480,8 +498,7 @@ ngx_http_lua_ffi_req_get_uri_args(ngx_http_request_t *r, u_char *buf, /* reached the end of a key or a value, just save it */ src = q; dst = q; - ngx_http_lua_unescape_uri(&dst, &src, p - q, - NGX_UNESCAPE_URI_COMPONENT); + ngx_http_lua_unescape_uri(&dst, &src, p - q, type); dd("pushing key or value %.*s", (int) (dst - q), q); @@ -525,8 +542,7 @@ ngx_http_lua_ffi_req_get_uri_args(ngx_http_request_t *r, u_char *buf, if (p != q || parsing_value) { src = q; dst = q; - ngx_http_lua_unescape_uri(&dst, &src, p - q, - NGX_UNESCAPE_URI_COMPONENT); + ngx_http_lua_unescape_uri(&dst, &src, p - q, type); dd("pushing key or value %.*s", (int) (dst - q), q); diff --git a/src/ngx_http_lua_args.h b/src/ngx_http_lua_args.h index d89889fbc9..cd4ae5d3cb 100644 --- a/src/ngx_http_lua_args.h +++ b/src/ngx_http_lua_args.h @@ -12,7 +12,8 @@ void ngx_http_lua_inject_req_args_api(lua_State *L); -int ngx_http_lua_parse_args(lua_State *L, u_char *buf, u_char *last, int max); +int ngx_http_lua_parse_args(lua_State *L, u_char *buf, u_char *last, + int max, int raw); #endif /* _NGX_HTTP_LUA_ARGS_H_INCLUDED_ */ diff --git a/src/ngx_http_lua_string.c b/src/ngx_http_lua_string.c index 239b2322ab..3df7043382 100644 --- a/src/ngx_http_lua_string.c +++ b/src/ngx_http_lua_string.c @@ -143,17 +143,24 @@ static int ngx_http_lua_ngx_unescape_uri(lua_State *L) { size_t len, dlen; + ngx_uint_t type = NGX_UNESCAPE_URI_COMPONENT; + int n; u_char *p; u_char *src, *dst; - if (lua_gettop(L) != 1) { - return luaL_error(L, "expecting one argument"); + n = lua_gettop(L); + + if (n != 1 && n != 2) { + return luaL_error(L, "expecting 1 or 2 arguments, but got %d", n); } if (lua_isnil(L, 1)) { lua_pushliteral(L, ""); return 1; } + if (n == 2 && lua_toboolean(L, 2)) { + type = NGX_UNESCAPE_URI_COMPONENT_RAW; + } src = (u_char *) luaL_checklstring(L, 1, &len); @@ -164,7 +171,7 @@ ngx_http_lua_ngx_unescape_uri(lua_State *L) dst = p; - ngx_http_lua_unescape_uri(&dst, &src, len, NGX_UNESCAPE_URI_COMPONENT); + ngx_http_lua_unescape_uri(&dst, &src, len, type); lua_pushlstring(L, (char *) p, dst - p); @@ -602,17 +609,29 @@ ngx_http_lua_ngx_decode_args(lua_State *L) size_t len = 0; int n; int max; + int raw = 0; n = lua_gettop(L); - if (n != 1 && n != 2) { - return luaL_error(L, "expecting 1 or 2 arguments but seen %d", n); + if (n != 1 && n != 2 && n!= 3) { + return luaL_error(L, "expecting 1 or 2 or 3 arguments but seen %d", n); } buf = (u_char *) luaL_checklstring(L, 1, &len); - if (n == 2) { - max = luaL_checkint(L, 2); + if (n >= 2) { + if (lua_isnil(L, 2)) { + max = NGX_HTTP_LUA_MAX_ARGS; + + } else { + max = luaL_checkinteger(L, 2); + } + + if (n == 3) { + raw = lua_toboolean(L, 3); + lua_pop(L, 1); + } + lua_pop(L, 1); } else { @@ -624,7 +643,7 @@ ngx_http_lua_ngx_decode_args(lua_State *L) lua_createtable(L, 0, 4); - return ngx_http_lua_parse_args(L, tmp, tmp + len, max); + return ngx_http_lua_parse_args(L, tmp, tmp + len, max, raw); } @@ -738,12 +757,15 @@ ngx_http_lua_ffi_decode_base64(const u_char *src, size_t slen, u_char *dst, size_t -ngx_http_lua_ffi_unescape_uri(const u_char *src, size_t len, u_char *dst) +ngx_http_lua_ffi_unescape_uri(const u_char *src, size_t len, + u_char *dst, int raw) { - u_char *p = dst; + u_char *p = dst; + ngx_uint_t type; + + type = raw ? NGX_UNESCAPE_URI_COMPONENT_RAW : NGX_UNESCAPE_URI_COMPONENT; - ngx_http_lua_unescape_uri(&p, (u_char **) &src, len, - NGX_UNESCAPE_URI_COMPONENT); + ngx_http_lua_unescape_uri(&p, (u_char **) &src, len, type); return p - dst; } diff --git a/src/ngx_http_lua_util.c b/src/ngx_http_lua_util.c index f7a537ee96..4fc7dd4b7c 100644 --- a/src/ngx_http_lua_util.c +++ b/src/ngx_http_lua_util.c @@ -1968,7 +1968,7 @@ ngx_http_lua_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) } -/* XXX we also decode '+' to ' ' */ +/* XXX we also decode '+' to ' ' when type not NGX_UNESCAPE_URI_COMPONENT_RAW */ void ngx_http_lua_unescape_uri(u_char **dst, u_char **src, size_t size, ngx_uint_t type) @@ -2004,7 +2004,7 @@ ngx_http_lua_unescape_uri(u_char **dst, u_char **src, size_t size, break; } - if (ch == '+') { + if (ch == '+' && !(type & NGX_UNESCAPE_URI_COMPONENT_RAW)) { *d++ = ' '; break; } diff --git a/src/ngx_http_lua_util.h b/src/ngx_http_lua_util.h index 7dcc6f7585..4eeee8e7e2 100644 --- a/src/ngx_http_lua_util.h +++ b/src/ngx_http_lua_util.h @@ -15,6 +15,7 @@ #ifndef NGX_UNESCAPE_URI_COMPONENT #define NGX_UNESCAPE_URI_COMPONENT 0 +#define NGX_UNESCAPE_URI_COMPONENT_RAW 4 #endif diff --git a/t/006-escape.t b/t/006-escape.t index a21d3cb509..e08032752c 100644 --- a/t/006-escape.t +++ b/t/006-escape.t @@ -197,3 +197,28 @@ GET /lua %2C%24%40%7C%60 --- no_error_log [error] + + + +=== TEST 15: unescape uri raw is not set +--- config + location /unescape { + content_by_lua "ngx.say(ngx.unescape_uri('a+%e4%bd%a0'))"; + } +--- request +GET /unescape +--- response_body +a 你 + + + +=== TEST 16: unescape uri raw is true +--- config + location /unescape { + content_by_lua "ngx.say(ngx.unescape_uri('a+%e4%bd%a0', true))"; + } +--- request +GET /unescape +--- response_body +a+你 + diff --git a/t/030-uri-args.t b/t/030-uri-args.t index a9d46ff97b..e299b20e65 100644 --- a/t/030-uri-args.t +++ b/t/030-uri-args.t @@ -9,7 +9,7 @@ log_level('warn'); repeat_each(2); #repeat_each(1); -plan tests => repeat_each() * (blocks() * 2 + 18); +plan tests => repeat_each() * (blocks() * 2 + 19); no_root_location(); @@ -1547,3 +1547,155 @@ GET /lua args: foo=%2C%24%40%7C%60&bar=-_.!~*'() --- no_error_log [error] + + + +=== TEST 58: ngx.decode_args raw is not set +--- config + location /lua { + content_by_lua ' + local args = "a=bar+%2B&b=foo" + args = ngx.decode_args(args) + ngx.say("a = ", args.a) + ngx.say("b = ", args.b) + '; + } +--- request +GET /lua +--- response_body +a = bar + +b = foo + + + +=== TEST 59: ngx.decode_args raw is true +--- config + location /lua { + content_by_lua ' + local args = "a=bar+%2B&b=foo" + args = ngx.decode_args(args, -1, true) + ngx.say("a = ", args.a) + ngx.say("b = ", args.b) + '; + } +--- request +GET /lua +--- response_body +a = bar++ +b = foo + + + +=== TEST 60: ngx.decode_args raw is true work with max_args +--- config + location /lua { + content_by_lua ' + local args = "a=bar+%2B&b=foo" + args = ngx.decode_args(args, 1, true) + ngx.say("a = ", args.a) + ngx.say("b = ", args.b) + '; + } +--- request +GET /lua +--- response_body +a = bar++ +b = nil + + + +=== TEST 61: get_uri_args raw is not set(decode '+' to ' ') +--- config + location /lua { + content_by_lua ' + local args = ngx.req.get_uri_args() + local keys = {} + for key, val in pairs(args) do + table.insert(keys, key) + end + + table.sort(keys) + for i, key in ipairs(keys) do + ngx.say(key, " = ", args[key]) + end + '; + } +--- request +GET /lua?a=3+5&b=4&c +--- response_body +a = 3 5 +b = 4 +c = true + + + +=== TEST 62: get_uri_args raw is true with max_args +--- config + location /lua { + content_by_lua ' + local args = ngx.req.get_uri_args(2, true) + local keys = {} + for key, val in pairs(args) do + table.insert(keys, key) + end + + table.sort(keys) + for i, key in ipairs(keys) do + ngx.say(key, " = ", args[key]) + end + '; + } +--- request +GET /lua?a=3+5&b=4&c +--- response_body +a = 3+5 +b = 4 + + + +=== TEST 63: get_uri_args raw is true with max_args is not set(default 100) +--- config + location /lua { + content_by_lua ' + local args = ngx.req.get_uri_args(nil, true) + local keys = {} + for key, val in pairs(args) do + table.insert(keys, key) + end + + table.sort(keys) + for i, key in ipairs(keys) do + ngx.say(key, " = ", args[key]) + end + '; + } +--- request eval +my $s = "GET /lua?"; +my $i = 1; +while ($i <= 102) { + if ($i != 1) { + $s .= '&'; + } + $s .= "a$i=$i+$i"; + $i++; +} +$s +--- response_body eval +my @k; +my $i = 1; +while ($i <= 100) { + push @k, "a$i"; + $i++; +} +@k = sort @k; +for my $k (@k) { + if ($k =~ /\d+/) { + $k .= " = $&+$&\n"; + } +} +CORE::join("", @k); +--- timeout: 4 +--- error_log +lua hit query args limit 100 +--- log_level: debug + diff --git a/t/031-post-args.t b/t/031-post-args.t index 4659f059fc..62bab5807b 100644 --- a/t/031-post-args.t +++ b/t/031-post-args.t @@ -8,7 +8,7 @@ use Test::Nginx::Socket::Lua; repeat_each(2); -plan tests => repeat_each() * (blocks() * 2 + 6); +plan tests => repeat_each() * (blocks() * 2 + 7); #no_diff(); no_long_string(); @@ -404,3 +404,105 @@ a=3&b=4&c err: request body in temp file not supported --- no_error_log [error] + + + +=== TEST 11: raw is not set(decode '+' to ' ') +--- config + location /lua { + lua_need_request_body on; + content_by_lua ' + local args = ngx.req.get_post_args() + local keys = {} + for key, val in pairs(args) do + table.insert(keys, key) + end + + table.sort(keys) + for i, key in ipairs(keys) do + ngx.say(key, " = ", args[key]) + end + '; + } +--- request +POST /lua +a=3+5&b=4&c +--- response_body +a = 3 5 +b = 4 +c = true + + + +=== TEST 12: raw is true with max_args +--- config + location /lua { + lua_need_request_body on; + content_by_lua ' + local args = ngx.req.get_post_args(2, true) + local keys = {} + for key, val in pairs(args) do + table.insert(keys, key) + end + + table.sort(keys) + for i, key in ipairs(keys) do + ngx.say(key, " = ", args[key]) + end + '; + } +--- request +POST /lua +a=3+5&b=4&c +--- response_body +a = 3+5 +b = 4 + + + +=== TEST 13: raw is true with max_args is not set(default 100) +--- config + location /lua { + content_by_lua ' + ngx.req.read_body(); + local args = ngx.req.get_post_args(nil, true) + local keys = {} + for key, val in pairs(args) do + table.insert(keys, key) + end + + table.sort(keys) + for i, key in ipairs(keys) do + ngx.say(key, " = ", args[key]) + end + '; + } +--- request eval +my $s = "POST /lua\n"; +my $i = 1; +while ($i <= 102) { + if ($i != 1) { + $s .= '&'; + } + $s .= "a$i=$i+$i"; + $i++; +} +$s +--- response_body eval +my @k; +my $i = 1; +while ($i <= 100) { + push @k, "a$i"; + $i++; +} +@k = sort @k; +for my $k (@k) { + if ($k =~ /\d+/) { + $k .= " = $&+$&\n"; + } +} +CORE::join("", @k); +--- timeout: 4 +--- error_log +lua hit query args limit 100 +