Skip to content

Commit

Permalink
Merge pull request #117 from Tieske/multi-value
Browse files Browse the repository at this point in the history
fix(header/query): both can have duplicate keys
  • Loading branch information
EvandroLG committed Jan 23, 2023
2 parents 431e444 + 5111904 commit 3b92059
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 17 deletions.
32 changes: 25 additions & 7 deletions src/pegasus/request.lua
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,21 @@ function Request:parseFirstLine()
self.querystring = self:parseUrlEncoded(querystring)
end

function Request:parseUrlEncoded(value)
function Request:parseUrlEncoded(data)
local output = {}

if value then
for k, v in string.gmatch(value, Request.PATTERN_QUERY_STRING) do
output[k] = v
if data then
for key, value in string.gmatch(data, Request.PATTERN_QUERY_STRING) do
if key and value then
local v = output[key]
if not v then
output[key] = value
elseif type(v) == "string" then
output[key] = { v, value }
else -- v is a table
v[#v + 1] = value
end
end
end
end

Expand Down Expand Up @@ -128,20 +137,29 @@ function Request:headers()

local data = self.client:receive()

local headers = {}
while (data ~= nil) and (data:len() > 0) do
local key, value = string.match(data, Request.PATTERN_HEADER)

if key and value then
self._headers[key] = value
local v = headers[key]
if not v then
headers[key] = value
elseif type(v) == "string" then
headers[key] = { v, value }
else -- t == "table", v is a table
v[#v + 1] = value
end
end

data = self.client:receive()
end

self._headerParsed = true
self._contentLength = tonumber(self._headers["Content-Length"] or 0)
self._contentLength = tonumber(headers["Content-Length"] or 0)
self._headers = headers

return self._headers
return headers
end

function Request:receiveBody(size)
Expand Down
16 changes: 11 additions & 5 deletions src/pegasus/response.lua
Original file line number Diff line number Diff line change
Expand Up @@ -113,13 +113,19 @@ function Response:statusCode(statusCode, statusText)
end

function Response:_getHeaders()
local headers = ''

for key, value in pairs(self._headers) do
headers = headers .. key .. ': ' .. value .. '\r\n'
local headers = {}

for header_name, header_value in pairs(self._headers) do
if type(header_value) == "table" and #header_value > 0 then
for _, sub_value in ipairs(header_value) do
headers[#headers + 1] = header_name .. ': ' .. sub_value .. '\r\n'
end
else
headers[#headers + 1] = header_name .. ': ' .. header_value .. '\r\n'
end
end

return headers
return table.concat(headers)
end

function Response:writeDefaultErrorMessage(statusCode)
Expand Down
16 changes: 11 additions & 5 deletions test/unit/request_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -59,17 +59,23 @@ describe('require', function()

test('headers', function()
local request = getInstance(
{ 'GET /Makefile?a=b&c=d HTTP/1.1', 'a: A', 'b: B', '', 'C=3', '' }
{ 'GET /Makefile?a=b&c=d&e=1&e=2 HTTP/1.1', 'a: A', 'b: B', 'c: X', 'c: Y', '', 'C=3', '' }
)

assert.are.same(
request:headers(),
{ ['a'] = 'A', ['b'] = 'B' }
request:headers(), {
a = 'A',
b = 'B',
c = { 'X', 'Y' },
}
)

assert.are.same(
request.querystring,
{ ['a'] = 'b', ['c'] = 'd' }
request.querystring, {
a = 'b',
c = 'd',
e = { '1', '2' },
}
)
end)

Expand Down
8 changes: 8 additions & 0 deletions test/unit/response_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,14 @@ describe('response', function()
assert.equal(headers['Age'], 15163)
assert.equal(headers['Connection'], 'keep-alive')
end)

it("should allow multi-value/duplicate headers", function()
local response = Response:new({})
response:addHeader('My-Header', { 'value 1', 'value 2' })
local expected = "My-Header: value 1" .. "\r\n"
.. "My-Header: value 2" .. "\r\n"
assert.equal(expected, response:_getHeaders())
end)
end)

describe('status code', function()
Expand Down

0 comments on commit 3b92059

Please sign in to comment.