Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
benoitc authored Feb 20, 2025
2 parents 9262cf0 + 345a8b2 commit 9308343
Show file tree
Hide file tree
Showing 20 changed files with 323 additions and 146 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/erlang.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
runs-on: ${{matrix.os}}
strategy:
matrix:
otp: ["25.3", "26.1"]
otp: ["25.3", "26.2", "27.2"]
rebar3: ['3.22.1']
os: [ubuntu-22.04]
steps:
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
2012-2023 (c) Benoît Chesneau <[email protected]>
2012-2025 (c) Benoît Chesneau <[email protected]>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
15 changes: 15 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
# NEWS
1.21.0 - 2025-02-20
-------------------

- fix: remove SSL options incompatible with tls 1.3
- fix: url parsing handle "/" path correctly
- fix: simplify integration test suite
- fix: handle chunked response in redirect responses
- fix: handle http & https proxies separately
- fix: skip junk lines in 1.xx response

** security fixes ***

- fix URL parsing to prevent SSRF . (related to CVE-2025-1211)
- use latest SSL certificate bundle


1.20.1 - 2023-10-11
-------------------
Expand Down
2 changes: 1 addition & 1 deletion NOTICE
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
hackney
-------

2012-2023 (c) Benoît Chesneau <[email protected]>
2012-2025 (c) Benoît Chesneau <[email protected]>

hackney is released under the Apache 2 license. See the LICENSE file for
the complete license.
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

# hackney - HTTP client library in Erlang #

Copyright (c) 2012-2023 Benoît Chesneau.
Copyright (c) 2012-2025 Benoît Chesneau.

__Version:__ 1.20.1
__Version:__ 1.21.0

# hackney

Expand Down
8 changes: 1 addition & 7 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
# TODO

1.21.0
2.0.0
------

- Improve pool
- Improve proxying

2.0.0
-----
- Support Websockets
- Support HTTP 2
- Request / Response hooks
- Dynamic response behaviour.

2.1.0
-----
- Support HTTP 3
4 changes: 2 additions & 2 deletions doc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

# hackney - HTTP client library in Erlang #

Copyright (c) 2012-2023 Benoît Chesneau.
Copyright (c) 2012-2025 Benoît Chesneau.

__Version:__ 1.20.1
__Version:__ 1.21.0

# hackney

Expand Down
6 changes: 3 additions & 3 deletions doc/overview.edoc
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

%%==============================================================================
%% Copyright 2012-2021 Benoît Chesneau
%% Copyright 2012-2025 Benoît Chesneau
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
Expand All @@ -16,8 +16,8 @@
%%==============================================================================


@copyright 2012-2023 Benoît Chesneau.
@version 1.20.1
@copyright 2012-2025 Benoît Chesneau.
@version 1.21.0
@title hackney - HTTP client library in Erlang

@doc
Expand Down
3 changes: 2 additions & 1 deletion include/hackney.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,5 @@

-define(CONNECTIONS, hackney_connections).

-define(PROXY_ENV_VARS, ["http_proxy", "https_proxy", "HTTP_PROXY", "HTTPS_PROXY"]).
-define(HTTP_PROXY_ENV_VARS, ["http_proxy", "HTTP_PROXY", "all_proxy", "ALL_PROXY"]).
-define(HTTPS_PROXY_ENV_VARS, ["https_proxy", "HTTPS_PROXY", "all_proxy", "ALL_PROXY"]).
2 changes: 1 addition & 1 deletion rebar.config
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
{deps, [
{idna, "~>6.1.0"},
{mimerl, "~>1.1"},
{certifi, "~>2.12.0"},
{certifi, "~>2.14.0"},
{metrics, "~>1.0.0"},
{parse_trans, "3.4.1"},
{ssl_verify_fun, "~>1.1.0"},
Expand Down
12 changes: 6 additions & 6 deletions rebar.lock
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
{"1.2.0",
[{<<"certifi">>,{pkg,<<"certifi">>,<<"2.12.0">>},0},
[{<<"certifi">>,{pkg,<<"certifi">>,<<"2.14.0">>},0},
{<<"idna">>,{pkg,<<"idna">>,<<"6.1.1">>},0},
{<<"metrics">>,{pkg,<<"metrics">>,<<"1.0.1">>},0},
{<<"mimerl">>,{pkg,<<"mimerl">>,<<"1.2.0">>},0},
{<<"mimerl">>,{pkg,<<"mimerl">>,<<"1.3.0">>},0},
{<<"parse_trans">>,{pkg,<<"parse_trans">>,<<"3.4.1">>},0},
{<<"ssl_verify_fun">>,{pkg,<<"ssl_verify_fun">>,<<"1.1.7">>},0},
{<<"unicode_util_compat">>,{pkg,<<"unicode_util_compat">>,<<"0.7.0">>},0}]}.
[
{pkg_hash,[
{<<"certifi">>, <<"2D1CCA2EC95F59643862AF91F001478C9863C2AC9CB6E2F89780BFD8DE987329">>},
{<<"certifi">>, <<"ED3BEF654E69CDE5E6C022DF8070A579A79E8BA2368A00ACF3D75B82D9ACEEED">>},
{<<"idna">>, <<"8A63070E9F7D0C62EB9D9FCB360A7DE382448200FBBD1B106CC96D3D8099DF8D">>},
{<<"metrics">>, <<"25F094DEA2CDA98213CECC3AEFF09E940299D950904393B2A29D191C346A8486">>},
{<<"mimerl">>, <<"67E2D3F571088D5CFD3E550C383094B47159F3EEE8FFA08E64106CDF5E981BE3">>},
{<<"mimerl">>, <<"D0CD9FC04B9061F82490F6581E0128379830E78535E017F7780F37FEA7545726">>},
{<<"parse_trans">>, <<"6E6AA8167CB44CC8F39441D05193BE6E6F4E7C2946CB2759F015F8C56B76E5FF">>},
{<<"ssl_verify_fun">>, <<"354C321CF377240C7B8716899E182CE4890C5938111A1296ADD3EC74CF1715DF">>},
{<<"unicode_util_compat">>, <<"BC84380C9AB48177092F43AC89E4DFA2C6D62B40B8BD132B1059ECC7232F9A78">>}]},
{pkg_hash_ext,[
{<<"certifi">>, <<"EE68D85DF22E554040CDB4BE100F33873AC6051387BAF6A8F6CE82272340FF1C">>},
{<<"certifi">>, <<"EA59D87EF89DA429B8E905264FDEC3419F84F2215BB3D81E07A18AAC919026C3">>},
{<<"idna">>, <<"92376EB7894412ED19AC475E4A86F7B413C1B9FBB5BD16DCCD57934157944CEA">>},
{<<"metrics">>, <<"69B09ADDDC4F74A40716AE54D140F93BEB0FB8978D8636EADED0C31B6F099F16">>},
{<<"mimerl">>, <<"F278585650AA581986264638EBF698F8BB19DF297F66AD91B18910DFC6E19323">>},
{<<"mimerl">>, <<"A1E15A50D1887217DE95F0B9B0793E32853F7C258A5CD227650889B38839FE9D">>},
{<<"parse_trans">>, <<"620A406CE75DADA827B82E453C19CF06776BE266F5A67CFF34E1EF2CBB60E49A">>},
{<<"ssl_verify_fun">>, <<"FE4C190E8F37401D30167C8C405EDA19469F34577987C76DDE613E838BBC67F8">>},
{<<"unicode_util_compat">>, <<"25EEE6D67DF61960CF6A794239566599B09E17E668D3700247BC498638152521">>}]}
Expand Down
2 changes: 1 addition & 1 deletion src/hackney.app.src
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
{application, hackney,
[
{description, "simple HTTP client"},
{vsn, "1.20.1"},
{vsn, "1.21.0"},
{registered, [hackney_pool]},
{applications, [kernel,
stdlib,
Expand Down
21 changes: 12 additions & 9 deletions src/hackney.erl
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,8 @@ request(Method, #hackney_url{}=URL0, Headers0, Body, Options0) ->
host = Host,
port = Port,
user = User,
password = Password} = URL,
password = Password,
scheme = Scheme} = URL,

Options = case User of
<<>> ->
Expand All @@ -332,7 +333,7 @@ request(Method, #hackney_url{}=URL0, Headers0, Body, Options0) ->

Headers1 = hackney_headers_new:new(Headers0),

case maybe_proxy(Transport, Host, Port, Options) of
case maybe_proxy(Transport, Scheme, Host, Port, Options) of
{ok, Ref, AbsolutePath} ->
Request = make_request(
Method, URL, Headers1, Body, Options, AbsolutePath
Expand Down Expand Up @@ -615,7 +616,7 @@ make_request(Method, #hackney_url{}=URL, Headers, Body, _, _) ->
{Method, FinalPath, Headers1, Body}.


maybe_proxy(Transport, Host, Port, Options)
maybe_proxy(Transport, Scheme, Host, Port, Options)
when is_list(Host), is_integer(Port), is_list(Options) ->
case proplists:get_value(proxy, Options) of
Url when is_binary(Url) orelse is_list(Url) ->
Expand Down Expand Up @@ -671,14 +672,14 @@ maybe_proxy(Transport, Host, Port, Options)
NoProxyEnv = proplists:get_value(
no_proxy_env, Options, application:get_env(hackney, no_proxy_env, false)
),
maybe_proxy_from_env(Transport, Host, Port, Options, NoProxyEnv)
maybe_proxy_from_env(Transport, Scheme, Host, Port, Options, NoProxyEnv)
end.

maybe_proxy_from_env(Transport, Host, Port, Options, true) ->
maybe_proxy_from_env(Transport, _Scheme, Host, Port, Options, true) ->
?report_debug("request without proxy", []),
hackney_connect:connect(Transport, Host, Port, Options, true);
maybe_proxy_from_env(Transport, Host, Port, Options, _) ->
case get_proxy_env() of
maybe_proxy_from_env(Transport, Scheme, Host, Port, Options, _) ->
case get_proxy_env(Scheme) of
{ok, Url} ->
proxy_from_url(Url, Transport, Host, Port, Options);
false ->
Expand All @@ -704,8 +705,10 @@ proxy_from_url(Url, Transport, Host, Port, Options) ->
end
end.

get_proxy_env() ->
get_proxy_env(?PROXY_ENV_VARS).
get_proxy_env(https) ->
get_proxy_env(?HTTPS_PROXY_ENV_VARS);
get_proxy_env(S) when S =:= http; S =:= http_unix ->
get_proxy_env(?HTTP_PROXY_ENV_VARS);

get_proxy_env([Var | Rest]) ->
case os:getenv(Var) of
Expand Down
21 changes: 19 additions & 2 deletions src/hackney_http.erl
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,8 @@ execute(#hparser{state=Status, buffer=Buffer}=St, Bin) ->
on_first_line -> parse_first_line(NBuffer, St1, 0);
on_header -> parse_headers(St1);
on_body -> parse_body(St1);
on_trailers -> parse_trailers(St1)
on_trailers -> parse_trailers(St1);
on_junk -> skip_junks(St1)
end.

%% Empty lines must be using \r\n.
Expand Down Expand Up @@ -181,7 +182,13 @@ parse_first_line(Buffer, St=#hparser{type=Type,
{error, bad_request} -> parse_response_line(St)
end;
_ when Type =:= response ->
parse_response_line(St);
case parse_response_line(St) of
{error, bad_request} -> {error, bad_request};
{response, Version, StatusInt, Reason, NState} when StatusInt >= 200 ->
{response, Version, StatusInt, Reason, NState};
{response, _Version, _StatusInt, _Reason, _NState} ->
{more, St#hparser{empty_lines=Empty, state=on_junk}}
end;
_ when Type =:= request ->
parse_request_line(St)
end.
Expand Down Expand Up @@ -343,6 +350,16 @@ parse_header(Line, St) ->
parse_header_value(H) ->
hackney_bstr:trim(H).

skip_junks(#hparser{buffer=Buf}=St) ->
case binary:split(Buf, <<"\r\n">>) of
[<<>>, Rest] ->
{more, St#hparser{buffer=Rest, state=on_first_line}};
[_Line, Rest]->
skip_junks(St#hparser{buffer=Rest});
[Buf] ->
{more, St}
end.

parse_trailers(St) ->
case parse_trailers(St, []) of
{ok, _Trailers, #hparser{buffer=Rest1}} ->
Expand Down
4 changes: 1 addition & 3 deletions src/hackney_ssl.erl
Original file line number Diff line number Diff line change
Expand Up @@ -136,9 +136,7 @@ connect(Host, Port, Opts) ->

connect(Host, Port, Opts, Timeout) when is_list(Host), is_integer(Port),
(Timeout =:= infinity orelse is_integer(Timeout)) ->
BaseOpts = [binary, {active, false}, {packet, raw},
{secure_renegotiate, true},
{reuse_sessions, true}],
BaseOpts = [binary, {active, false}, {packet, raw}],
Opts1 = hackney_util:merge_opts(BaseOpts, Opts),
%% connect
ssl:connect(parse_address(Host), Port, Opts1, Timeout).
Expand Down
Loading

0 comments on commit 9308343

Please sign in to comment.