Skip to content

Instantly share code, notes, and snippets.

@AndrewBarba
Last active May 31, 2023 15:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AndrewBarba/09f71d8269d98785c0b686207d3c0f5a to your computer and use it in GitHub Desktop.
Save AndrewBarba/09f71d8269d98785c0b686207d3c0f5a to your computer and use it in GitHub Desktop.
---@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&timestamp=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