diff --git a/src/hackney_http_connect.erl b/src/hackney_http_connect.erl index 52fe9c32..22982ecc 100644 --- a/src/hackney_http_connect.erl +++ b/src/hackney_http_connect.erl @@ -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} -> @@ -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 -> @@ -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; @@ -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">>], @@ -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 >>) -> @@ -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.