Skip to content
Open
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
7 changes: 5 additions & 2 deletions lib/protocol/rack/adapter/generic.rb
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,11 @@ def unwrap_request(request, env)
env[RACK_HIJACK] = proc{request.hijack!.io}
end

# HTTP/2 prefers `:authority` over `host`, so we do this for backwards compatibility.
env[CGI::HTTP_HOST] ||= request.authority
# HTTP/2 prefers `:authority` over `host`:
if authority = request.authority
# Note that we also already have SERVER_NAME and SERVER_PORT which are based on the authority.
env[CGI::HTTP_HOST] = authority
end

if peer = request.peer
env[CGI::REMOTE_ADDR] = peer.ip_address
Expand Down
21 changes: 21 additions & 0 deletions test/protocol/rack/request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,25 @@
)
end
end

with "incoming request with both host header and authority" do
let(:headers) {Protocol::HTTP::Headers[{"host" => "header.example.com"}]}
let(:request) {Protocol::HTTP::Request.new("https", "authority.example.com", "GET", "/", "HTTP/1.1", headers, body)}

it "correctly sets HTTP_HOST to the authority instead of host header" do
# According to HTTP/2 semantics, :authority should take precedence over the host header when both are present:
expect(env).to have_keys(
"HTTP_HOST" => be == "authority.example.com"
)
end
end

with "incoming request with trailing host header" do
let(:headers) {Protocol::HTTP::Headers.new([["host", "header.example.com"]], 0)}
let(:request) {Protocol::HTTP::Request.new("https", nil, "GET", "/", "HTTP/1.1", headers, body)}

it "rejects the request" do
expect(env).not.to have_keys("HTTP_HOST")
end
end
end
Loading