Skip to content

Commit

Permalink
Add limits to HTTP request parsing (#4428)
Browse files Browse the repository at this point in the history
  • Loading branch information
RX14 authored and Martin Verzilli committed Jun 2, 2017
1 parent 66ac243 commit 2c8fead
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 3 deletions.
10 changes: 10 additions & 0 deletions spec/std/http/client/response_spec.cr
Expand Up @@ -123,6 +123,16 @@ class HTTP::Client
response.body.should eq("")
end

it "parses long request lines" do
request = Response.from_io?(IO::Memory.new("HTTP/1.1 200 #{"OK" * 16000}\r\n\r\n"))
request.should eq(nil)
end

it "parses long headers" do
request = Response.from_io?(IO::Memory.new("HTTP/1.1 200 OK\r\n#{"X-Test-Header: A pretty log header value\r\n" * 1000}\r\n"))
request.should eq(nil)
end

it "doesn't sets content length for 1xx, 204 or 304" do
[100, 101, 204, 304].each do |status|
response = Response.new(status)
Expand Down
10 changes: 10 additions & 0 deletions spec/std/http/request_spec.cr
Expand Up @@ -176,6 +176,16 @@ module HTTP
request.should be_a(Request::BadRequest)
end

it "handles long request lines" do
request = Request.from_io(IO::Memory.new("GET /#{"a" * 4096} HTTP/1.1\r\n\r\n"))
request.should be_a(Request::BadRequest)
end

it "handles long headers" do
request = Request.from_io(IO::Memory.new("GET / HTTP/1.1\r\n#{"X-Test-Header: A pretty log header value\r\n" * 1000}\r\n"))
request.should be_a(Request::BadRequest)
end

describe "keep-alive" do
it "is false by default in HTTP/1.0" do
request = Request.new "GET", "/", version: "HTTP/1.0"
Expand Down
2 changes: 1 addition & 1 deletion src/http/client/response.cr
Expand Up @@ -116,7 +116,7 @@ class HTTP::Client::Response
# it to the block. Might yield `nil` if there's no data in the `IO`,
# which probably means that the connection was closed.
def self.from_io?(io, ignore_body = false, decompress = true, &block)
line = io.gets
line = io.gets(4096, chomp: true)
return yield nil unless line

pieces = line.split(3)
Expand Down
6 changes: 5 additions & 1 deletion src/http/common.cr
Expand Up @@ -17,7 +17,11 @@ module HTTP
def self.parse_headers_and_body(io, body_type : BodyType = BodyType::OnDemand, decompress = true)
headers = Headers.new

while line = io.gets
headers_size = 0
while line = io.gets(16_384, chomp: true)
headers_size += line.bytesize
break if headers_size > 16_384

if line.empty?
body = nil
if body_type.prohibited?
Expand Down
2 changes: 1 addition & 1 deletion src/http/request.cr
Expand Up @@ -87,7 +87,7 @@ class HTTP::Request

# Returns a `HTTP::Request` instance if successfully parsed, returns `nil` on EOF, or returns `BadRequest`.
def self.from_io(io)
request_line = io.gets
request_line = io.gets(4096, chomp: true)
return unless request_line

parts = request_line.split
Expand Down

0 comments on commit 2c8fead

Please sign in to comment.