0
Fork 0
mirror of https://github.com/ninenines/cowboy.git synced 2025-07-14 12:20:24 +00:00

Fallback to host header if authority is missing

This commit is contained in:
Fredrik Enestad 2019-01-22 17:50:40 +01:00 committed by Loïc Hoguin
parent 705fa9755f
commit 7ff9e963b8
No known key found for this signature in database
GPG key ID: 8A9DF795F6FED764
2 changed files with 38 additions and 4 deletions

View file

@ -315,9 +315,20 @@ headers_frame(State, StreamID, IsFin, Headers,
PseudoHeaders=#{method := <<"TRACE">>}, _) -> PseudoHeaders=#{method := <<"TRACE">>}, _) ->
early_error(State, StreamID, IsFin, Headers, PseudoHeaders, 501, early_error(State, StreamID, IsFin, Headers, PseudoHeaders, 501,
'The TRACE method is currently not implemented. (RFC7231 4.3.8)'); 'The TRACE method is currently not implemented. (RFC7231 4.3.8)');
headers_frame(State=#state{ref=Ref, peer=Peer, sock=Sock, cert=Cert, proxy_header=ProxyHeader}, headers_frame(State, StreamID, IsFin, Headers, PseudoHeaders=#{authority := Authority}, BodyLen) ->
StreamID, IsFin, Headers, PseudoHeaders=#{method := Method, scheme := Scheme, headers_frame_parse_host(State, StreamID, IsFin, Headers, PseudoHeaders, BodyLen, Authority);
authority := Authority, path := PathWithQs}, BodyLen) -> headers_frame(State, StreamID, IsFin, Headers, PseudoHeaders, BodyLen) ->
case lists:keyfind(<<"host">>, 1, Headers) of
{_, Authority} ->
headers_frame_parse_host(State, StreamID, IsFin, Headers, PseudoHeaders, BodyLen, Authority);
_ ->
reset_stream(State, StreamID, {stream_error, protocol_error,
'Requests translated from HTTP/1.1 must include a host header. (RFC7540 8.1.2.3, RFC7230 5.4)'})
end.
headers_frame_parse_host(State=#state{ref=Ref, peer=Peer, sock=Sock, cert=Cert, proxy_header=ProxyHeader},
StreamID, IsFin, Headers, PseudoHeaders=#{method := Method, scheme := Scheme, path := PathWithQs},
BodyLen, Authority) ->
try cow_http_hd:parse_host(Authority) of try cow_http_hd:parse_host(Authority) of
{Host, Port0} -> {Host, Port0} ->
Port = ensure_port(Scheme, Port0), Port = ensure_port(Scheme, Port0),

View file

@ -3746,7 +3746,7 @@ reject_many_pseudo_header_scheme(Config) ->
ok. ok.
reject_missing_pseudo_header_authority(Config) -> reject_missing_pseudo_header_authority(Config) ->
doc("A request without an authority component must be rejected " doc("A request without an authority or host component must be rejected "
"with a PROTOCOL_ERROR stream error. (RFC7540 8.1.2.3, RFC7540 8.1.2.6)"), "with a PROTOCOL_ERROR stream error. (RFC7540 8.1.2.3, RFC7540 8.1.2.6)"),
{ok, Socket} = do_handshake(Config), {ok, Socket} = do_handshake(Config),
%% Send a HEADERS frame without an :authority pseudo-header. %% Send a HEADERS frame without an :authority pseudo-header.
@ -3760,6 +3760,29 @@ reject_missing_pseudo_header_authority(Config) ->
{ok, << _:24, 3:8, _:8, 1:32, 1:32 >>} = gen_tcp:recv(Socket, 13, 6000), {ok, << _:24, 3:8, _:8, 1:32, 1:32 >>} = gen_tcp:recv(Socket, 13, 6000),
ok. ok.
accept_host_header_on_missing_pseudo_header_authority(Config) ->
doc("A request without an authority but with a host header must be accepted. "
"(RFC7540 8.1.2.3, RFC7540 8.1.3)"),
{ok, Socket} = do_handshake(Config),
%% Send a HEADERS frame with host header and without an :authority pseudo-header.
{HeadersBlock, _} = cow_hpack:encode([
{<<":method">>, <<"GET">>},
{<<":scheme">>, <<"http">>},
{<<":path">>, <<"/">>},
{<<"host">>, <<"localhost">>}
]),
ok = gen_tcp:send(Socket, cow_http2:headers(1, fin, HeadersBlock)),
%% Receive a 200 response.
{ok, << Len:24, 1:8, _:8, _:32 >>} = gen_tcp:recv(Socket, 9, 6000),
{ok, RespHeadersBlock} = gen_tcp:recv(Socket, Len, 6000),
{RespHeaders, _} = cow_hpack:decode(RespHeadersBlock),
{_, <<"200">>} = lists:keyfind(<<":status">>, 1, RespHeaders),
ok.
%% When both :authority and host headers are received, the current behavior
%% is to favor :authority and ignore the host header. The specification does
%% not describe the correct behavior to follow in that case.
reject_many_pseudo_header_authority(Config) -> reject_many_pseudo_header_authority(Config) ->
doc("A request containing more than one authority component must be rejected " doc("A request containing more than one authority component must be rejected "
"with a PROTOCOL_ERROR stream error. (RFC7540 8.1.2.3, RFC7540 8.1.2.6)"), "with a PROTOCOL_ERROR stream error. (RFC7540 8.1.2.3, RFC7540 8.1.2.6)"),