aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gun.erl44
-rw-r--r--src/gun_http.erl31
2 files changed, 52 insertions, 23 deletions
diff --git a/src/gun.erl b/src/gun.erl
index af576fb..9c92281 100644
--- a/src/gun.erl
+++ b/src/gun.erl
@@ -120,7 +120,8 @@
port := inet:port_number(),
username => iodata(),
password => iodata(),
- protocol => http | http2,
+ protocol => http | http2, %% @todo Remove in Gun 2.0.
+ protocols => [http | http2],
transport => tcp | tls,
tls_opts => [ssl:connect_option()],
tls_handshake_timeout => timeout()
@@ -652,14 +653,9 @@ default_transport(443) -> tls;
default_transport(_) -> tcp.
transport_connect(State=#state{host=Host, port=Port, opts=Opts, transport=Transport=gun_tls}, Retries) ->
- Protocols = [case P of
- http -> <<"http/1.1">>;
- http2 -> <<"h2">>
- end || P <- maps:get(protocols, Opts, [http2, http])],
- TransportOpts = [binary, {active, false},
- {alpn_advertised_protocols, Protocols},
- {client_preferred_next_protocols, {client, Protocols, <<"http/1.1">>}}
- |maps:get(transport_opts, Opts, [])],
+ TransportOpts = [binary, {active, false}|ensure_alpn(
+ maps:get(protocols, Opts, [http2, http]),
+ maps:get(transport_opts, Opts, []))],
case Transport:connect(Host, Port, TransportOpts, maps:get(connect_timeout, Opts, infinity)) of
{ok, Socket} ->
{Protocol, ProtoOptsKey} = case ssl:negotiated_protocol(Socket) of
@@ -684,6 +680,16 @@ transport_connect(State=#state{host=Host, port=Port, opts=Opts, transport=Transp
retry(State#state{last_error=Reason}, Retries)
end.
+ensure_alpn(Protocols0, TransportOpts) ->
+ Protocols = [case P of
+ http -> <<"http/1.1">>;
+ http2 -> <<"h2">>
+ end || P <- Protocols0],
+ [
+ {alpn_advertised_protocols, Protocols},
+ {client_preferred_next_protocols, {client, Protocols, <<"http/1.1">>}}
+ |TransportOpts].
+
up(State=#state{owner=Owner, opts=Opts, transport=Transport}, Socket, Protocol, ProtoOptsKey) ->
ProtoOpts = maps:get(ProtoOptsKey, Opts, #{}),
ProtoState = Protocol:init(Owner, Socket, Transport, ProtoOpts),
@@ -778,7 +784,25 @@ loop(State=#state{parent=Parent, owner=Owner, owner_ref=OwnerRef,
ProtoState2 = Protocol:data(ProtoState,
StreamRef, ReplyTo, IsFin, Data),
loop(State#state{protocol_state=ProtoState2});
- {connect, ReplyTo, StreamRef, Destination, Headers} ->
+ {connect, ReplyTo, StreamRef, Destination0, Headers} ->
+ %% The protocol option has been deprecated in favor of the protocols option.
+ %% Nobody probably ended up using it, but let's not break the interface.
+ Destination1 = case Destination0 of
+ #{protocols := _} ->
+ Destination0;
+ #{protocol := DestProto} ->
+ Destination0#{protocols => [DestProto]};
+ _ ->
+ Destination0
+ end,
+ Destination = case Destination1 of
+ #{transport := tls} ->
+ Destination1#{tls_opts => ensure_alpn(
+ maps:get(protocols, Destination1, [http]),
+ maps:get(tls_opts, Destination1, []))};
+ _ ->
+ Destination1
+ end,
ProtoState2 = Protocol:connect(ProtoState, StreamRef, ReplyTo, Destination, Headers),
loop(State#state{protocol_state=ProtoState2});
{cancel, ReplyTo, StreamRef} ->
diff --git a/src/gun_http.erl b/src/gun_http.erl
index ee9d04f..c2b0ed6 100644
--- a/src/gun_http.erl
+++ b/src/gun_http.erl
@@ -221,29 +221,34 @@ handle_head(Data, State=#http_state{socket=Socket, version=ClientVersion,
State2 = end_stream(State#http_state{streams=[Stream|Tail]}),
NewHost = maps:get(host, Destination),
NewPort = maps:get(port, Destination),
- DestProtocol = maps:get(protocol, Destination, http),
case Destination of
#{transport := tls} ->
TLSOpts = maps:get(tls_opts, Destination, []),
TLSTimeout = maps:get(tls_handshake_timeout, Destination, infinity),
case gun_tls:connect(Socket, TLSOpts, TLSTimeout) of
- {ok, TLSSocket} when DestProtocol =:= http2 ->
- [{switch_transport, gun_tls, TLSSocket},
- {switch_protocol, gun_http2, State2},
- {origin, <<"https">>, NewHost, NewPort}];
{ok, TLSSocket} ->
- [{state, State2#http_state{socket=TLSSocket, transport=gun_tls}},
- {switch_transport, gun_tls, TLSSocket},
- {origin, <<"https">>, NewHost, NewPort}];
+ case ssl:negotiated_protocol(TLSSocket) of
+ {ok, <<"h2">>} ->
+ [{switch_transport, gun_tls, TLSSocket},
+ {switch_protocol, gun_http2, State2},
+ {origin, <<"https">>, NewHost, NewPort}];
+ _ ->
+ [{state, State2#http_state{socket=TLSSocket, transport=gun_tls}},
+ {switch_transport, gun_tls, TLSSocket},
+ {origin, <<"https">>, NewHost, NewPort}]
+ end;
Error ->
Error
end;
- _ when DestProtocol =:= http2 ->
- [{switch_protocol, gun_http2, State2},
- {origin, <<"http">>, NewHost, NewPort}];
_ ->
- [{state, State2},
- {origin, <<"http">>, NewHost, NewPort}]
+ case maps:get(protocols, Destination, [http]) of
+ [http] ->
+ [{state, State2},
+ {origin, <<"http">>, NewHost, NewPort}];
+ [http2] ->
+ [{switch_protocol, gun_http2, State2},
+ {origin, <<"http">>, NewHost, NewPort}]
+ end
end;
{_, _} when Status >= 100, Status =< 199 ->
ReplyTo ! {gun_inform, self(), stream_ref(StreamRef), Status, Headers},