Skip to content

Commit

Permalink
Attempt to normalize forwarded hosts generally.
Browse files Browse the repository at this point in the history
  • Loading branch information
ioquatix committed Feb 5, 2020
1 parent 8dc86a1 commit 6bc2a70
Showing 1 changed file with 22 additions and 34 deletions.
56 changes: 22 additions & 34 deletions lib/rack/request.rb
Expand Up @@ -217,24 +217,28 @@ def server_port
end
end

def forwarded_authority
if forwarded_host = get_header(HTTP_X_FORWARDED_HOST)
# IPv6 host should start with square brackets. But in some cases it's borked. So we compensate for it here:
if !forwarded_host.start_with?('[') && forwarded_host.include?('::')
forwarded_host = "[#{forwarded_host}]"
def forwarded_hosts
get_header(HTTP_X_FORWARDED_HOST)&.split(/,\s*/)&.map do |authority|
if !authority.start_with?('[') && authority.count(':') > 1
"[#{authority}]"
else
authority
end
end || []
end

authority = forwarded_host.split(/,\s*/).last
def forwarded_authority
# X-Forwarded-Host only contains the host.
# X-Forwarded-Port only contains the port.
if authority = forwarded_hosts&.first
host, address, port = split_authority(authority)

if forwarded_ssl = get_header(HTTP_X_FORWARDED_SSL)
port = 443
elsif forwarded_port = get_header(HTTP_X_FORWARDED_PORT)
if forwarded_port = get_header(HTTP_X_FORWARDED_PORT)
port = forwarded_port.split(/,\s*/).last
elsif forwarded_ssl = get_header(HTTP_X_FORWARDED_SSL)
port = 443
elsif forwarded_proto = get_header(HTTP_X_FORWARDED_PROTO)
port = DEFAULT_PORTS[extract_proto_header(forwarded_proto)]
else
port ||= self.server_port
end

if port
Expand Down Expand Up @@ -289,10 +293,11 @@ def hostname
end

def port
if port = extract_port(self.authority)
port.to_i
if authority = self.authority
host, address, port = split_authority(self.authority)
return port || DEFAULT_PORTS[scheme]
else
get_header(SERVER_PORT).to_i
return get_header(SERVER_PORT).to_i
end
end

Expand Down Expand Up @@ -327,8 +332,9 @@ def ip

return remote_addrs.first if remote_addrs.any?

forwarded_ips = split_ip_addresses(get_header('HTTP_X_FORWARDED_FOR'))
.map { |ip| strip_port(ip) }
forwarded_ips = forwarded_hosts.map do |authority|
split_authority(authority)[1]
end

return reject_trusted_ip_addresses(forwarded_ips).last || forwarded_ips.first || get_header("REMOTE_ADDR")
end
Expand Down Expand Up @@ -587,24 +593,6 @@ def extract_proto_header(header)
end
end
end

def extract_port(uri)
# IPv6 format with optional port: "[2001:db8:cafe::17]:47011"
# change `uri` to ":47011"
sep_start = uri.index('[')
sep_end = uri.index(']')
if (sep_start && sep_end)
uri = uri[sep_end + 1, uri.length]
end

# IPv4 format with optional port: "192.0.2.43:47011"
# or ":47011" from IPv6 above
# returns: "47011"
sep = uri.index(':')
if (sep && uri.count(':') == 1)
return uri[sep + 1, uri.length]
end
end
end

include Env
Expand Down

0 comments on commit 6bc2a70

Please sign in to comment.