aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2016-03-13 11:18:27 +0100
committerLoïc Hoguin <[email protected]>2016-03-13 11:26:26 +0100
commit2620d65fdef81dc88916a2b76764a3cf700a7cc1 (patch)
treef4b590ff51e0aa9b0cea641481d16d0e0df31604 /src
parent4e6a4ee53f8453c900c5439100a249ebb278deda (diff)
downloadcowboy-2620d65fdef81dc88916a2b76764a3cf700a7cc1.tar.gz
cowboy-2620d65fdef81dc88916a2b76764a3cf700a7cc1.tar.bz2
cowboy-2620d65fdef81dc88916a2b76764a3cf700a7cc1.zip
Fix more HTTP/2 handshake test cases
Diffstat (limited to 'src')
-rw-r--r--src/cowboy_http.erl41
-rw-r--r--src/cowboy_http2.erl9
-rw-r--r--src/cowboy_req.erl1
3 files changed, 28 insertions, 23 deletions
diff --git a/src/cowboy_http.erl b/src/cowboy_http.erl
index 1582770..4608839 100644
--- a/src/cowboy_http.erl
+++ b/src/cowboy_http.erl
@@ -489,9 +489,13 @@ parse_hd_before_value(Buffer, State=#state{opts=Opts, in_state=PS}, H, N) ->
parse_hd_value(Buffer, State, H, N, <<>>)
end.
-parse_hd_value(<< $\r, $\n, Rest/bits >>, S, Headers, Name, SoFar) ->
- %% @todo What to do about duplicate header names.
- parse_header(Rest, S, Headers#{Name => clean_value_ws_end(SoFar, byte_size(SoFar) - 1)});
+parse_hd_value(<< $\r, $\n, Rest/bits >>, S, Headers0, Name, SoFar) ->
+ Value = clean_value_ws_end(SoFar, byte_size(SoFar) - 1),
+ Headers = case maps:get(Name, Headers0, undefined) of
+ undefined -> Headers0#{Name => Value};
+ Value0 -> Headers0#{Name => << Value0/binary, ", ", Value/binary >>}
+ end,
+ parse_header(Rest, S, Headers);
parse_hd_value(<< C, Rest/bits >>, S, H, N, SoFar) ->
parse_hd_value(Rest, S, H, N, << SoFar/binary, C >>).
@@ -641,8 +645,8 @@ request(Buffer, State0=#state{ref=Ref, transport=Transport, in_streamid=StreamID
set_request_timeout(State0#state{in_streamid=StreamID + 1, in_state=#ps_request_line{}})
end,
{request, Req, State, Buffer};
- {true, SettingsPayload} ->
- http2_upgrade(State0, Buffer, SettingsPayload, Req)
+ {true, HTTP2Settings} ->
+ http2_upgrade(State0, Buffer, HTTP2Settings, Req)
end.
%% HTTP/2 upgrade.
@@ -650,15 +654,12 @@ request(Buffer, State0=#state{ref=Ref, transport=Transport, in_streamid=StreamID
is_http2_upgrade(#{<<"connection">> := Conn, <<"upgrade">> := Upgrade,
<<"http2-settings">> := HTTP2Settings}, 'HTTP/1.1') ->
Conns = cow_http_hd:parse_connection(Conn),
- io:format(user, "CONNS ~p~n", [Conns]),
case {lists:member(<<"upgrade">>, Conns), lists:member(<<"http2-settings">>, Conns)} of
{true, true} ->
Protocols = cow_http_hd:parse_upgrade(Upgrade),
- io:format(user, "PROTOCOLS ~p~n", [Protocols]),
case lists:member(<<"h2c">>, Protocols) of
true ->
- SettingsPayload = cow_http_hd:parse_http2_settings(HTTP2Settings),
- {true, SettingsPayload};
+ {true, HTTP2Settings};
false ->
false
end;
@@ -683,20 +684,26 @@ http2_upgrade(State=#state{parent=Parent, ref=Ref, socket=Socket, transport=Tran
end.
http2_upgrade(State=#state{parent=Parent, ref=Ref, socket=Socket, transport=Transport,
- opts=Opts, handler=Handler}, Buffer, SettingsPayload, Req) ->
+ opts=Opts, handler=Handler}, Buffer, HTTP2Settings, Req) ->
%% @todo
%% However if the client sent a body, we need to read the body in full
%% and if we can't do that, return a 413 response. Some options are in order.
%% Always half-closed stream coming from this side.
- Transport:send(Socket, cow_http:response(101, 'HTTP/1.1', maps:to_list(#{
- <<"connection">> => <<"Upgrade">>,
- <<"upgrade">> => <<"h2c">>
- }))),
+ try cow_http_hd:parse_http2_settings(HTTP2Settings) of
+ Settings ->
+ Transport:send(Socket, cow_http:response(101, 'HTTP/1.1', maps:to_list(#{
+ <<"connection">> => <<"Upgrade">>,
+ <<"upgrade">> => <<"h2c">>
+ }))),
- %% @todo Possibly redirect the request if it was https.
- _ = cancel_request_timeout(State),
- cowboy_http2:init(Parent, Ref, Socket, Transport, Opts, Handler, Buffer, SettingsPayload, Req).
+ %% @todo Possibly redirect the request if it was https.
+ _ = cancel_request_timeout(State),
+ cowboy_http2:init(Parent, Ref, Socket, Transport, Opts, Handler, Buffer, Settings, Req)
+ catch _:_ ->
+ error_terminate(400, State, {connection_error, protocol_error,
+ 'The HTTP2-Settings header contains a base64 SETTINGS payload. (RFC7540 3.2, RFC7540 3.2.1)'})
+ end.
%% Request body parsing.
diff --git a/src/cowboy_http2.erl b/src/cowboy_http2.erl
index d73c879..77a27a9 100644
--- a/src/cowboy_http2.erl
+++ b/src/cowboy_http2.erl
@@ -96,11 +96,11 @@ init(Parent, Ref, Socket, Transport, Opts, Handler, Buffer) ->
%% @todo Add an argument for the request body.
-spec init(pid(), ranch:ref(), inet:socket(), module(), cowboy:opts(), module(),
binary(), binary() | undefined, cowboy_req:req()) -> ok.
-init(Parent, Ref, Socket, Transport, Opts, Handler, Buffer, SettingsPayload, Req) ->
+init(Parent, Ref, Socket, Transport, Opts, Handler, Buffer, _Settings, Req) ->
State0 = #state{parent=Parent, ref=Ref, socket=Socket,
transport=Transport, opts=Opts, handler=Handler},
preface(State0),
- %% @todo SettingsPayload.
+ %% @todo Apply settings.
%% StreamID from HTTP/1.1 Upgrade requests is always 1.
%% The stream is always in the half-closed (remote) state.
State = stream_handler_init(State0, 1, fin, Req),
@@ -247,9 +247,8 @@ frame(State, {priority, _StreamID, _IsExclusive, _DepStreamID, _Weight}) ->
frame(State, {rst_stream, StreamID, Reason}) ->
stream_reset(State, StreamID, {stream_error, Reason, 'Stream reset requested by client.'});
%% SETTINGS frame.
-frame(State=#state{socket=Socket, transport=Transport}, {settings, Settings}) ->
+frame(State=#state{socket=Socket, transport=Transport}, {settings, _Settings}) ->
%% @todo Apply SETTINGS.
- io:format("settings ~p~n", [Settings]),
Transport:send(Socket, cow_http2:settings_ack()),
State;
%% Ack for a previously sent SETTINGS frame.
@@ -381,7 +380,7 @@ commands(State, StreamID, [{upgrade, _Mod, _ModState}]) ->
commands(State, StreamID, [{upgrade, _Mod, _ModState}|Tail]) ->
%% @todo This is an error. Not sure what to do here yet.
commands(State, StreamID, Tail);
-commands(State, StreamID, [stop|Tail]) ->
+commands(State, StreamID, [stop|_Tail]) ->
%% @todo Do we want to run the commands after a stop?
stream_terminate(State, StreamID, stop).
diff --git a/src/cowboy_req.erl b/src/cowboy_req.erl
index 998c2fe..8fa9927 100644
--- a/src/cowboy_req.erl
+++ b/src/cowboy_req.erl
@@ -384,7 +384,6 @@ read_body(Req=#{pid := Pid, streamid := StreamID}, Opts) ->
end,
Ref = make_ref(),
Pid ! {{Pid, StreamID}, {read_body, Ref, Length}},
-% io:format("READ_BODY ~p ~p ~p ~p~n", [Pid, StreamID, Ref, Length]),
receive
{request_body, Ref, nofin, Body} ->
{more, Body, Req};