diff --git a/src/pegasus/request.lua b/src/pegasus/request.lua index d217908..3a9c828 100644 --- a/src/pegasus/request.lua +++ b/src/pegasus/request.lua @@ -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 @@ -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) diff --git a/src/pegasus/response.lua b/src/pegasus/response.lua index 67785f1..1a37f64 100644 --- a/src/pegasus/response.lua +++ b/src/pegasus/response.lua @@ -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) diff --git a/test/unit/request_spec.lua b/test/unit/request_spec.lua index 5685e99..0fa2d9c 100644 --- a/test/unit/request_spec.lua +++ b/test/unit/request_spec.lua @@ -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) diff --git a/test/unit/response_spec.lua b/test/unit/response_spec.lua index 2df4289..cbf598c 100644 --- a/test/unit/response_spec.lua +++ b/test/unit/response_spec.lua @@ -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()