Skip to content

Commit 43bcf10

Browse files
committed
Better error handling.
1 parent 25b9e48 commit 43bcf10

File tree

3 files changed

+45
-4
lines changed

3 files changed

+45
-4
lines changed

lib/protocol/http1/connection.rb

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -349,18 +349,25 @@ def read(length)
349349

350350
# Read a line from the connection.
351351
#
352-
# @returns [String | Nil] the line read, or nil if the connection is closed.
353-
# @raises [EOFError] if the connection is closed.
352+
# @returns [String | Nil] the line read, or nil if the connection is gracefully closed.
354353
# @raises [LineLengthError] if the line is too long.
354+
# @raises [ProtocolError] if the line is not terminated properly.
355355
def read_line?
356356
if line = @stream.gets(CRLF, @maximum_line_length)
357357
unless line.chomp!(CRLF)
358-
# This basically means that the request line, response line, header, or chunked length line is too long.
359-
raise LineLengthError, "Line too long!"
358+
if line.bytesize == @maximum_line_length
359+
# This basically means that the request line, response line, header, or chunked length line is too long:
360+
raise LineLengthError, "Line too long!"
361+
else
362+
# This means the line was not terminated properly, which is a protocol violation:
363+
raise ProtocolError, "Line not terminated properly!"
364+
end
360365
end
361366
end
362367

363368
return line
369+
370+
# I considered rescuing Errno::ECONNRESET here, but it seems like that would be ignoring a potentially serious error.
364371
end
365372

366373
# Read a line from the connection.

releases.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Releases
22

3+
## Unreleased
4+
5+
- Tidy up implementation of `read_line?` to handle line length errors and protocol violations more clearly.
6+
37
## v0.35.0
48

59
- Add traces provider for `Protocol::HTTP1::Connection`.

test/protocol/http1/connection.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,36 @@
1515
describe Protocol::HTTP1::Connection do
1616
include_context ConnectionContext
1717

18+
with "#read_line?" do
19+
it "reads a line from the stream" do
20+
client.stream.write "GET / HTTP/1.1\r\nHost: localhost\r\n\r\n"
21+
client.stream.close
22+
23+
expect(server.read_line?).to be == "GET / HTTP/1.1"
24+
expect(server.read_line?).to be == "Host: localhost"
25+
expect(server.read_line?).to be == ""
26+
expect(server.read_line?).to be_nil
27+
end
28+
29+
it "raises LineLengthError if line is too long" do
30+
client.stream.write "GET / HTTP/1.#{"1" * 10000}"
31+
client.stream.close
32+
33+
expect do
34+
server.read_line?
35+
end.to raise_exception(Protocol::HTTP1::LineLengthError)
36+
end
37+
38+
it "raises ProtocolError if line is not terminated properly" do
39+
client.stream.write "GET / HTTP/1.1\r"
40+
client.stream.close
41+
42+
expect do
43+
server.read_line?
44+
end.to raise_exception(Protocol::HTTP1::ProtocolError)
45+
end
46+
end
47+
1848
with "#read_request" do
1949
it "reads request without body" do
2050
client.stream.write "GET / HTTP/1.1\r\nHost: localhost\r\nContent-Length: 0\r\n\r\n"

0 commit comments

Comments
 (0)