Last active
May 31, 2023 15:22
-
-
Save AndrewBarba/09f71d8269d98785c0b686207d3c0f5a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
---@param input string | |
---@return table<string> | |
local function parse_raw(input) | |
local res = {} | |
local is_key = true | |
local is_value = false | |
local key_t = {} | |
local value_t = {} | |
local function set_kv() | |
if #key_t == 0 then | |
return | |
end | |
local key = ngx.unescape_uri(table.concat(key_t, '')) | |
local value = ngx.unescape_uri(table.concat(value_t, '')) | |
res[#res + 1] = key | |
res[#res + 1] = value | |
key_t = {} | |
value_t = {} | |
end | |
for i = 1, #input do | |
local char = input:sub(i, i) | |
if char == '=' and is_key then | |
is_key = false | |
is_value = true | |
goto continue | |
end | |
if char == '&' then | |
is_key = true | |
is_value = false | |
set_kv() | |
goto continue | |
end | |
if is_key then | |
key_t[#key_t + 1] = char | |
goto continue | |
end | |
if is_value then | |
value_t[#value_t + 1] = char | |
goto continue | |
end | |
::continue:: | |
end | |
set_kv() | |
return res | |
end | |
---@param raw table<string> | |
---@return string | |
local function stringify(raw) | |
local pairs = {} | |
for i = 1, #raw, 2 do | |
local key = raw[i] | |
local value = raw[i + 1] | |
table.insert(pairs, ngx.escape_uri(key) .. '=' .. ngx.escape_uri(value)) | |
end | |
return table.concat(pairs, '&') | |
end | |
describe('#only URLSearchParams', function() | |
it('should parse', function() | |
local res = parse_raw('') | |
assert.equal(0, #res) | |
assert.equal('', stringify(res)) | |
end) | |
it('should parse', function() | |
local res = parse_raw('&&&&&&&&&') | |
assert.equal(0, #res) | |
assert.equal('', stringify(res)) | |
end) | |
it('should parse', function() | |
local res = parse_raw('&&&&&a&&&&') | |
assert.equal(2, #res) | |
assert.equal('a', res[1]) | |
assert.equal('', res[2]) | |
assert.equal('a=', stringify(res)) | |
end) | |
it('should parse', function() | |
local res = parse_raw('a') | |
assert.equal(2, #res) | |
assert.equal('a', res[1]) | |
assert.equal('', res[2]) | |
assert.equal('a=', stringify(res)) | |
end) | |
it('should parse', function() | |
local res = parse_raw('a==') | |
assert.equal(2, #res) | |
assert.equal('a', res[1]) | |
assert.equal('=', res[2]) | |
assert.equal('a=%3D', stringify(res)) | |
end) | |
it('should parse', function() | |
local res = parse_raw('a&') | |
assert.equal(2, #res) | |
assert.equal('a', res[1]) | |
assert.equal('', res[2]) | |
assert.equal('a=', stringify(res)) | |
end) | |
it('should parse', function() | |
local res = parse_raw('a=&') | |
assert.equal(2, #res) | |
assert.equal('a', res[1]) | |
assert.equal('', res[2]) | |
assert.equal('a=', stringify(res)) | |
end) | |
it('should parse', function() | |
local res = parse_raw('&a') | |
assert.equal(2, #res) | |
assert.equal('a', res[1]) | |
assert.equal('', res[2]) | |
assert.equal('a=', stringify(res)) | |
end) | |
it('should parse', function() | |
local res = parse_raw('&a=') | |
assert.equal(2, #res) | |
assert.equal('a', res[1]) | |
assert.equal('', res[2]) | |
assert.equal('a=', stringify(res)) | |
end) | |
it('should parse', function() | |
local res = parse_raw('a&b') | |
assert.equal(4, #res) | |
assert.equal('a', res[1]) | |
assert.equal('', res[2]) | |
assert.equal('b', res[3]) | |
assert.equal('', res[4]) | |
assert.equal('a=&b=', stringify(res)) | |
end) | |
it('should parse', function() | |
local res = parse_raw('a=&b') | |
assert.equal(4, #res) | |
assert.equal('a', res[1]) | |
assert.equal('', res[2]) | |
assert.equal('b', res[3]) | |
assert.equal('', res[4]) | |
assert.equal('a=&b=', stringify(res)) | |
end) | |
it('should parse', function() | |
local res = parse_raw('a&b=') | |
assert.equal(4, #res) | |
assert.equal('a', res[1]) | |
assert.equal('', res[2]) | |
assert.equal('b', res[3]) | |
assert.equal('', res[4]) | |
assert.equal('a=&b=', stringify(res)) | |
end) | |
it('should parse', function() | |
local res = parse_raw('a=&b=') | |
assert.equal(4, #res) | |
assert.equal('a', res[1]) | |
assert.equal('', res[2]) | |
assert.equal('b', res[3]) | |
assert.equal('', res[4]) | |
assert.equal('a=&b=', stringify(res)) | |
end) | |
it('should parse', function() | |
local res = parse_raw('a=1&b=2&a=3') | |
assert.equal(6, #res) | |
assert.equal('a', res[1]) | |
assert.equal('1', res[2]) | |
assert.equal('b', res[3]) | |
assert.equal('2', res[4]) | |
assert.equal('a', res[5]) | |
assert.equal('3', res[6]) | |
assert.equal('a=1&b=2&a=3', stringify(res)) | |
end) | |
it('should parse', function() | |
local res = parse_raw('url=/foo?a=b&b=$path') | |
assert.equal(4, #res) | |
assert.equal('url', res[1]) | |
assert.equal('/foo?a=b', res[2]) | |
assert.equal('b', res[3]) | |
assert.equal('$path', res[4]) | |
assert.equal('url=%2Ffoo%3Fa%3Db&b=%24path', stringify(res)) | |
end) | |
it('should parse', function() | |
ngx.update_time() | |
local start = ngx.now() | |
for _ = 1, 1000 do | |
parse_raw( | |
'userId=1234567890&userStatus=active&userRole=administrator&location=unitedStates&category=subcategory1|subcategory2|subcategory3×tamp=164124841&token=abcd1234efgh5678ijkl9012mnopqrst&sortOrder=desc&pageSize=50&pageNumber=1&fields=name,email,phone,address') | |
end | |
ngx.update_time() | |
local ms = (ngx.now() - start) * 1000 | |
assert(ms < 100) | |
end) | |
end) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment