Skip to content

Commit

Permalink
Better validation of incoming headers.
Browse files Browse the repository at this point in the history
  • Loading branch information
ioquatix committed Jun 17, 2019
1 parent 21f4eff commit 17c47b4
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 13 deletions.
3 changes: 2 additions & 1 deletion lib/async/http/protocol/http2/connection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ module HTTP2
STATUS = ':status'.freeze
PROTOCOL = ':protocol'.freeze

CONTENT_LENGTH = 'content-length'
CONTENT_LENGTH = 'content-length'.freeze
CONNECTION = 'connection'.freeze

module Connection
def initialize(*)
Expand Down
25 changes: 17 additions & 8 deletions lib/async/http/protocol/http2/request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,43 +48,52 @@ def create_push_promise_stream(headers)

def receive_headers(frame)
apply_headers(super, frame.end_stream?)
rescue ::Protocol::HTTP2::HeaderError => error
Async.logger.error(error)

send_reset_stream(error.code)
end

def apply_headers(headers, end_stream)
headers.each do |key, value|
if key == SCHEME
return send_failure(400, "Request scheme already specified") if @request.scheme
raise ::Protocol::HTTP2::HeaderError, "Request scheme already specified!" if @request.scheme

@request.scheme = value
elsif key == AUTHORITY
return send_failure(400, "Request authority already specified") if @request.authority
raise ::Protocol::HTTP2::HeaderError, "Request authority already specified!" if @request.authority

@request.authority = value
elsif key == METHOD
return send_failure(400, "Request method already specified") if @request.method
raise ::Protocol::HTTP2::HeaderError, "Request method already specified!" if @request.method

@request.method = value
elsif key == PATH
return send_failure(400, "Request path already specified") if @request.path
raise ::Protocol::HTTP2::HeaderError, "Request path is empty!" if value.empty?
raise ::Protocol::HTTP2::HeaderError, "Request path already specified!" if @request.path

@request.path = value
elsif key == PROTOCOL
return send_failure(400, "Request protocol already specified") if @request.protocol
raise ::Protocol::HTTP2::HeaderError, "Request protocol already specified!" if @request.protocol

@request.protocol = value
elsif key == CONTENT_LENGTH
return send_failure(400, "Request protocol already content length") if @length
raise ::Protocol::HTTP2::HeaderError, "Request content length already specified!" if @length

@length = Integer(value)
elsif key == CONNECTION
raise ::Protocol::HTTP2::HeaderError, "Connection header is not allowed!" if @length
elsif key.start_with? ':'
return send_failure(400, "Invalid pseudo-header #{key}")
raise ::Protocol::HTTP2::HeaderError, "Invalid pseudo-header #{key}!"
elsif key =~ /A-Z/
raise ::Protocol::HTTP2::HeaderError, "Invalid characters in header #{key}!"
else
@request.headers.add(key, value)
end
end

unless @request.valid?
send_reset_stream(::Protocol::HTTP2::Error::PROTOCOL_ERROR)
raise ::Protocol::HTTP2::HeaderError, "Request is missing required headers!"
else
# We only construct the input/body if data is coming.
unless end_stream
Expand Down
11 changes: 7 additions & 4 deletions lib/async/http/protocol/http2/response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -141,21 +141,24 @@ def build_request(headers)

headers.each do |key, value|
if key == SCHEME
return @stream.send_failure(400, "Request scheme already specified") if request.scheme
raise ::Protocol::HTTP2::HeaderError, "Request scheme already specified!" if request.scheme

request.scheme = value
elsif key == AUTHORITY
return @stream.send_failure(400, "Request authority already specified") if request.authority
raise ::Protocol::HTTP2::HeaderError, "Request authority already specified!" if request.authority

request.authority = value
elsif key == METHOD
return @stream.send_failure(400, "Request method already specified") if request.method
raise ::Protocol::HTTP2::HeaderError, "Request method already specified!" if request.method

request.method = value
elsif key == PATH
return @stream.send_failure(400, "Request path already specified") if request.path
raise ::Protocol::HTTP2::HeaderError, "Request path is empty!" if value.empty?
raise ::Protocol::HTTP2::HeaderError, "Request path already specified!" if request.path

request.path = value
elsif key.start_with? ':'
raise ::Protocol::HTTP2::HeaderError, "Invalid pseudo-header #{key}!"
else
request.headers[key] = value
end
Expand Down

0 comments on commit 17c47b4

Please sign in to comment.