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

Validate headers (fix name validation and ensure there is no new line character in the header value) #530

Merged
merged 2 commits into from Feb 13, 2019
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 14 additions & 3 deletions lib/http/headers.rb
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
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