Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[bugfix] insure proper handling of multiple Content-Length headers in http #4705

Merged
merged 1 commit into from Oct 14, 2017

Conversation

bmmcginty
Copy link
Contributor

When multiple Content-Length headers are received, error out if all received values do not match.
Return a single Content-Length header value.

This seems kind of an odd case, but it was the first thing that happened when adding Crystal to my stack today.
Multiple Content-Length headers, each of the same value, were added.
I've added a spec which fails using the earlier behavior.

Copy link
Contributor

@RX14 RX14 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From RFC7230

If a message is received that has multiple Content-Length header fields with field-values consisting of the same decimal value, or a single Content-Length header field with a field value containing a list of identical decimal values (e.g., "Content-Length: 42, 42"), indicating that duplicate Content-Length header fields have been generated or combined by an upstream message processor, then the recipient MUST either reject the message as invalid or replace the duplicated field-values with a single valid Content-Length field containing that decimal value prior to determining the message body length or forwarding the message.

The behaviour in this PR looks to be exactly what the spec suggests.

headers["Content-Length"]?.try &.to_u64?
length_header = headers.get? "Content-Length"
return nil unless length_header
if length_header.size > 1 && length_header.uniq.size != 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a faster implementation would be

length_headers = headers.get? "Content-Length"
return nil unless length_headers

first_header = length_headers[0]
if length_headers.size > 1 && length_headers.any? { |header| header != first_header }
  raise ArgumentError.new("Multiple Content-Length headers received did not match: #{length_headers}")
end
first_header.to_u64

length_header = headers.get? "Content-Length"
return nil unless length_header
if length_header.size > 1 && length_header.uniq.size != 1
raise ArgumentError.new("Multiple different values found for content-length #{length_header}")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps "Multiple Content-Length headers received did not match: #{length_headers}" would be a better message?

@@ -345,5 +345,16 @@ module HTTP
request.host_with_port.should eq("host.example.org:3000")
end
end

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest adding spec for a throwing case when values do not match.

@RX14
Copy link
Contributor

RX14 commented Jul 12, 2017

Oh, and by the way it's "ensure" not "insure" :)

@@ -345,5 +345,29 @@ module HTTP
request.host_with_port.should eq("host.example.org:3000")
end
end

it "doesn't raise on request with multiple Content_length headers" do
io = IO::Memory.new %(GET / HTTP/1.1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use heredoc with indentation (easier to read), like:

io = IO::Memory.new <<-REQ
       Host: host
       etc.
       REQ

@sdogruyol
Copy link
Member

Up 👍

@asterite
Copy link
Member

"asterite requested changes" :-)

When multiple Content-Length headers are received, error out if all received values do not match.
Return a single Content-Length header value.
@RX14
Copy link
Contributor

RX14 commented Oct 14, 2017

Pushed fixes for this, because it stalled.

@RX14 RX14 added this to the Next milestone Oct 14, 2017
@RX14 RX14 merged commit e8d9019 into crystal-lang:master Oct 14, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants