diff --git a/lib/webrick/httputils.rb b/lib/webrick/httputils.rb index e2c2a40..40ba32f 100644 --- a/lib/webrick/httputils.rb +++ b/lib/webrick/httputils.rb @@ -176,10 +176,19 @@ def parse_header(raw) when /^([A-Za-z0-9!\#$%&'*+\-.^_`|~]+):([^\r\n\0]*?)\r\n\z/om field, value = $1, $2 field.downcase! - header[field] = HEADER_CLASSES[field].new unless header.has_key?(field) + if header.has_key?(field) + if field == "transfer-encoding" + raise HTTPStatus::BadRequest, "duplicate 'transfer-encoding' header." + end + else + header[field] = HEADER_CLASSES[field].new + end header[field] << value when /^[ \t]+([^\r\n\0]*?)\r\n/om - unless field + case field + when "transfer-encoding" + raise HTTPStatus::BadRequest, "'transfer-encoding' header with obsolete line folding." + when nil raise HTTPStatus::BadRequest, "bad header '#{line}'." end value = line diff --git a/test/webrick/test_httprequest.rb b/test/webrick/test_httprequest.rb index 3d02573..655df11 100644 --- a/test/webrick/test_httprequest.rb +++ b/test/webrick/test_httprequest.rb @@ -237,6 +237,36 @@ def test_content_length_and_transfer_encoding_headers_smuggling } end + def test_multiple_transfer_encoding_headers + msg = <<~HTTP.gsub("\n", "\r\n") + POST /user HTTP/1.1 + Transfer-Encoding: chunked + Transfer-Encoding: identity + + 0 + + HTTP + req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP) + assert_raise(WEBrick::HTTPStatus::BadRequest){ + req.parse(StringIO.new(msg)) + } + end + + def test_transfer_encoding_header_with_obs + msg = <<~HTTP.gsub("\n", "\r\n") + POST /user HTTP/1.1 + Transfer-Encoding: chunked + identity + + 0 + + HTTP + req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP) + assert_raise(WEBrick::HTTPStatus::BadRequest){ + req.parse(StringIO.new(msg)) + } + end + def test_parse_headers msg = <<~HTTP.gsub("\n", "\r\n") GET /path HTTP/1.1