Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions lib/http/headers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ class Headers
include Enumerable

# Matches HTTP header names when in "Canonical-Http-Format"
CANONICAL_NAME_RE = /^[A-Z][a-z]*(?:-[A-Z][a-z]*)*$/
CANONICAL_NAME_RE = /\A[A-Z][a-z]*(?:-[A-Z][a-z]*)*\z/

# Matches valid header field name according to RFC.
# @see http://tools.ietf.org/html/rfc7230#section-3.2
COMPLIANT_NAME_RE = /^[A-Za-z0-9!#\$%&'*+\-.^_`|~]+$/
COMPLIANT_NAME_RE = /\A[A-Za-z0-9!#\$%&'*+\-.^_`|~]+\z/

# Class constructor.
def initialize
Expand Down Expand Up @@ -50,7 +50,7 @@ def delete(name)
# @return [void]
def add(name, value)
name = normalize_header name.to_s
Array(value).each { |v| @pile << [name, v.to_s] }
Array(value).each { |v| @pile << [name, validate_value(v)] }
end

# Returns list of header values if any.
Expand Down Expand Up @@ -209,5 +209,16 @@ def normalize_header(name)

raise HeaderError, "Invalid HTTP header field name: #{name.inspect}"
end

# Ensures there is no new line character in the header value
#
# @param [String] value
# @raise [HeaderError] if value includes new line character
# @return [String] stringified header value
def validate_value(value)
v = value.to_s
return v unless v.include?("\n")
raise HeaderError, "Invalid HTTP header field value: #{v.inspect}"
end
end
end
38 changes: 28 additions & 10 deletions spec/lib/http/headers_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,15 @@
to raise_error HTTP::HeaderError
end

it "fails with invalid header name" do
expect { headers.set "foo bar", "baz" }.
["foo bar", "foo bar: ok\nfoo", "evil-header: evil-value\nfoo"].each do |name|
it "fails with invalid header name (#{name.inspect})" do
expect { headers.set name, "baz" }.
to raise_error HTTP::HeaderError
end
end

it "fails with invalid header value" do
expect { headers.set "foo", "bar\nEvil-Header: evil-value" }.
to raise_error HTTP::HeaderError
end
end
Expand Down Expand Up @@ -83,9 +90,11 @@
to raise_error HTTP::HeaderError
end

it "fails with invalid header name" do
expect { headers.delete "foo bar" }.
to raise_error HTTP::HeaderError
["foo bar", "foo bar: ok\nfoo"].each do |name|
it "fails with invalid header name (#{name.inspect})" do
expect { headers.delete name }.
to raise_error HTTP::HeaderError
end
end
end

Expand Down Expand Up @@ -117,8 +126,15 @@
to raise_error HTTP::HeaderError
end

it "fails with invalid header name" do
expect { headers.add "foo bar", "baz" }.
["foo bar", "foo bar: ok\nfoo"].each do |name|
it "fails with invalid header name (#{name.inspect})" do
expect { headers.add name, "baz" }.
to raise_error HTTP::HeaderError
end
end

it "fails with invalid header value" do
expect { headers.add "foo", "bar\nEvil-Header: evil-value" }.
to raise_error HTTP::HeaderError
end
end
Expand All @@ -145,9 +161,11 @@
to raise_error HTTP::HeaderError
end

it "fails with invalid header name" do
expect { headers.get("foo bar") }.
to raise_error HTTP::HeaderError
["foo bar", "foo bar: ok\nfoo"].each do |name|
it "fails with invalid header name (#{name.inspect})" do
expect { headers.get name }.
to raise_error HTTP::HeaderError
end
end
end

Expand Down