Skip to content

Commit

Permalink
connect: handle empty lines during handshake
Browse files Browse the repository at this point in the history
fix #536
  • Loading branch information
benoitc committed Sep 28, 2018
1 parent a168a3d commit 4dc3547
Showing 1 changed file with 36 additions and 7 deletions.
43 changes: 36 additions & 7 deletions src/hackney_http_connect.erl
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,19 @@ connect(ProxyHost, ProxyPort, Opts) ->
connect(ProxyHost, ProxyPort, Opts, Timeout)
when is_list(ProxyHost), is_integer(ProxyPort),
(Timeout =:= infinity orelse is_integer(Timeout)) ->

%% get the host and port to connect from the options
Host = proplists:get_value(connect_host, Opts),
Port = proplists:get_value(connect_port, Opts),
Transport = proplists:get_value(connect_transport, Opts),

%% filter connection options
AcceptedOpts = [linger, nodelay, send_timeout,
send_timeout_close, raw, inet6],
BaseOpts = [binary, {active, false}, {packet, 0}, {keepalive, true},
{nodelay, true}],
ConnectOpts = hackney_util:filter_options(Opts, AcceptedOpts, BaseOpts),

%% connnect to the proxy, and upgrade the socket if needed.
case gen_tcp:connect(ProxyHost, ProxyPort, ConnectOpts) of
{ok, Socket} ->
Expand Down Expand Up @@ -153,7 +153,7 @@ do_handshake(Socket, Host, Port, Options) ->
ProxyUser = proplists:get_value(connect_user, Options),
ProxyPass = proplists:get_value(connect_pass, Options, <<>>),
ProxyPort = proplists:get_value(connect_port, Options),

%% set defaults headers
HostHdr = case ProxyPort of
80 ->
Expand All @@ -164,7 +164,7 @@ do_handshake(Socket, Host, Port, Options) ->
UA = hackney_request:default_ua(),
Headers0 = [<<"Host: ", HostHdr/binary>>,
<<"User-Agent: ", UA/binary >>],

Headers = case ProxyUser of
undefined ->
Headers0;
Expand All @@ -174,7 +174,7 @@ do_handshake(Socket, Host, Port, Options) ->
Headers0 ++ [<< "Proxy-Authorization: Basic ", Credentials/binary >>]
end,
Path = iolist_to_binary([Host, ":", integer_to_list(Port)]),

Payload = [<< "CONNECT ", Path/binary, " HTTP/1.1", "\r\n" >>,
hackney_bstr:join(lists:reverse(Headers), <<"\r\n">>),
<<"\r\n\r\n">>],
Expand All @@ -186,13 +186,35 @@ do_handshake(Socket, Host, Port, Options) ->
end.

check_response(Socket) ->
check_response(<<>>, Socket, 10).

check_response(_Buffer, _Socket, 0) ->
{error, bad_request};

check_response(Buffer, Socket, N) ->
case gen_tcp:recv(Socket, 0, ?TIMEOUT) of
{ok, Data} ->
check_status(Data);
NBuffer = << Data/binary, Buffer/binary >>,
parse_first_line(Buffer, Socket, N);
Error ->
Error
end.

parse_first_line(Buffer, Socket, 0) ->
{error, line_too_long};
parse_first_line(Buffer, Socket, N) ->
case match_eol(Buffer, 0) of
nomatch when byte_size(Buffer) > 4096 ->
{error, line_too_long};
nomatch ->
check_response(Buffer, Socket, N);
1 ->
<< _:16, Rest/binary >> = Buffer,
parse_first_line(Rest, Socket, N - 1);
_ ->
check_status(Buffer)
end.

check_status(<< "HTTP/1.1 200", _/bits >>) ->
ok;
check_status(<< "HTTP/1.1 201", _/bits >>) ->
Expand All @@ -204,3 +226,10 @@ check_status(<< "HTTP/1.0 201", _/bits >>) ->
check_status(Else) ->
error_logger:error_msg("proxy error: ~w~n", [Else]),
{error, proxy_error}.

match_eol(<< $\n, _/bits >>, N) ->
N;
match_eol(<< _, Rest/bits >>, N) ->
match_eol(Rest, N + 1);
match_eol(_, _) ->
nomatch.

0 comments on commit 4dc3547

Please sign in to comment.