Skip to content

Commit

Permalink
Added tests for RFC-7540 Section 3.5
Browse files Browse the repository at this point in the history
  • Loading branch information
joedevivo committed Mar 16, 2016
1 parent cbd5454 commit f5c1bfc
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 5 deletions.
27 changes: 22 additions & 5 deletions src/http2_connection.erl
Original file line number Diff line number Diff line change
Expand Up @@ -1206,8 +1206,9 @@ start_http2_server(
}=Conn) ->
lager:info("[server] StartHTTP2 settings: ~p",
[Http2Settings]),
case sock:recv(Socket, length(?PREFACE), 5000) of
{ok, <<?PREFACE>>} ->

case accept_preface(Socket) of
ok ->
ok = active_once(Socket),
NewState =
Conn#connection{
Expand All @@ -1219,9 +1220,25 @@ start_http2_server(
handshake,
send_settings(Http2Settings, NewState)
};
BadPreface ->
lager:debug("[server] Bad Preface: ~p", [BadPreface]),
go_away(?PROTOCOL_ERROR, Conn)
{error, invalid_preface} ->
lager:debug("[server] Invalid Preface"),
{next_state, closing, Conn}
end.

%% We're going to iterate through the preface string until we're done
%% or hit a mismatch
accept_preface(Socket) ->
accept_preface(Socket, <<?PREFACE>>).

accept_preface(_Socket, <<>>) ->
ok;
accept_preface(Socket, <<Char:8,Rem/binary>>) ->
case sock:recv(Socket, 1, 5000) of
{ok, <<Char>>} ->
accept_preface(Socket, Rem);
_E ->
sock:close(Socket),
{error, invalid_preface}
end.

%% Incoming data is a series of frames. With a passive socket we can just:
Expand Down
75 changes: 75 additions & 0 deletions test/http2_spec_3_5_SUITE.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
-module(http2_spec_3_5_SUITE).

-include("http2.hrl").
-include_lib("eunit/include/eunit.hrl").
-include_lib("common_test/include/ct.hrl").
-compile([export_all]).

all() ->
[
sends_invalid_connection_preface,
sends_incomplete_connection_preface
].

init_per_suite(Config) ->
application:ensure_started(crypto),
chatterbox_test_buddy:start(Config).

end_per_suite(Config) ->
chatterbox_test_buddy:stop(Config),
ok.

%% Inspired by https://github.com/summerwind/h2spec/blob/master/3_5.go
sends_invalid_connection_preface(Config) ->
%% Preface correct except for last character
send_invalid_connection_preface(<<"PRI * HTTP/2.0\r\n\r\nSM\r\n\rQ">>, Config),
%% Preface incorrect at first character
send_invalid_connection_preface(<<"QRI * HTTP/2.0\r\n\r\nSM\r\n\r\n">>, Config),
%% Just plain wrong
send_invalid_connection_preface(<<"INVALID CONNECTION PREFACE\r\n\r\n">>, Config),
ok.

send_invalid_connection_preface(Preface, _Config) ->
{ok, Port} = application:get_env(chatterbox, port),
ClientOptions = [
binary,
{packet, raw},
{active, false}
],
{ok, SSLOptions} = application:get_env(chatterbox, ssl_options),
Options = ClientOptions ++ SSLOptions ++ [{client_preferred_next_protocols, {client, [<<"h2">>]}}],

{ok, Socket} = ssl:connect("localhost", Port, Options),

ssl:send(Socket, Preface),

ssl:recv(Socket, 0, 1000),

{error, closed} = ssl:send(Socket, <<"something else">>),
{error, closed} = ssl:connection_information(Socket),
ok.

sends_incomplete_connection_preface(_Config) ->
{ok, Port} = application:get_env(chatterbox, port),
ClientOptions = [
binary,
{packet, raw},
{active, false}
],
{ok, SSLOptions} = application:get_env(chatterbox, ssl_options),
Options = ClientOptions ++ SSLOptions ++ [{client_preferred_next_protocols, {client, [<<"h2">>]}}],

{ok, Socket} = ssl:connect("localhost", Port, Options),

ssl:send(Socket, <<"PRI * HTTP/2.0">>),

ssl:recv(Socket, 0, 1000),

{ok, _ConnectionInfo} = ssl:connection_information(Socket),

%% There's a 5 second timeout before the socket will be closed
ssl:recv(Socket, 0, 5000),

{error, closed} = ssl:send(Socket, <<"something else">>),
{error, closed} = ssl:connection_information(Socket),
ok.

0 comments on commit f5c1bfc

Please sign in to comment.