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

Rework Request#ip to handle empty forwarded_for. #1577

Merged
merged 1 commit into from Feb 8, 2020
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
24 changes: 17 additions & 7 deletions lib/rack/request.rb
Expand Up @@ -352,16 +352,26 @@ def ssl?
end

def ip
remote_addrs = split_header(get_header('REMOTE_ADDR'))
remote_addrs = reject_trusted_ip_addresses(remote_addrs)
remote_addresses = split_header(get_header('REMOTE_ADDR'))
external_addresses = reject_trusted_ip_addresses(remote_addresses)

if remote_addrs.any?
remote_addrs.first
else
forwarded_ips = self.forwarded_for
unless external_addresses.empty?
return external_addresses.first
end

reject_trusted_ip_addresses(forwarded_ips).last || forwarded_ips.first || get_header("REMOTE_ADDR")
if forwarded_for = self.forwarded_for
unless forwarded_for.empty?
# The forwarded for addresses are ordered: client, proxy1, proxy2.
# So we reject all the trusted addresses (proxy*) and return the
# last client. Or if we trust everyone, we just return the first
# address.
return reject_trusted_ip_addresses(forwarded_for).last || forwarded_for.first
end
end

# If all the addresses are trusted, and we aren't forwarded, just return
# the first remote address, which represents the source of the request.
remote_addresses.first
end

# The media type (type/subtype) portion of the CONTENT_TYPE header
Expand Down
6 changes: 6 additions & 0 deletions test/spec_request.rb
Expand Up @@ -1270,6 +1270,12 @@ def ip_app

res = mock.get '/', 'REMOTE_ADDR' => '1.2.3.4,3.4.5.6'
res.body.must_equal '1.2.3.4'

res = mock.get '/', 'REMOTE_ADDR' => '127.0.0.1'
res.body.must_equal '127.0.0.1'

res = mock.get '/', 'REMOTE_ADDR' => '127.0.0.1,127.0.0.1'
res.body.must_equal '127.0.0.1'
end

it 'deals with proxies' do
Expand Down