aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2025-03-28 14:29:06 +0100
committerLoïc Hoguin <[email protected]>2025-03-28 14:29:06 +0100
commit694fed991b4611147f2da73a183d3b8768f4b45d (patch)
tree9d99228500aee90925bb1733e0791d9c6e2d7bb3
parente10c8f9762ada26457c03a7c3a391ef8e4745d15 (diff)
downloadgun-694fed991b4611147f2da73a183d3b8768f4b45d.tar.gz
gun-694fed991b4611147f2da73a183d3b8768f4b45d.tar.bz2
gun-694fed991b4611147f2da73a183d3b8768f4b45d.zip
Reject Websocket frames sent over HTTP
-rw-r--r--src/gun_http.erl14
-rw-r--r--test/gun_SUITE.erl12
2 files changed, 26 insertions, 0 deletions
diff --git a/src/gun_http.erl b/src/gun_http.erl
index d28600b..29cfa9c 100644
--- a/src/gun_http.erl
+++ b/src/gun_http.erl
@@ -35,6 +35,7 @@
-export([stream_info/2]).
-export([down/1]).
-export([ws_upgrade/11]).
+-export([ws_send/6]).
%% Functions shared with gun_http2 and gun_pool.
-export([host_header/3]).
@@ -1051,3 +1052,16 @@ ws_handshake_end(Buffer, State=#http_state{streams=[#stream{flow=InitialFlow}|_]
handler => Handler,
opts => Opts
}}, ReplyTo, Buffer}.
+
+%% Reject attempts to send Websocket frames on HTTP.
+%% This can happen either because the user explicitly
+%% called ws_send on an HTTP connection, or because
+%% the connection was dropped and automatically
+%% reconnected. Automatic reconnection doesn't perform
+%% a Websocket upgrade automatically.
+ws_send(_, _, _, ReplyTo, _, EvHandlerState) ->
+ gun:reply(ReplyTo, {gun_error, self(), {badstate,
+ "This connection does not currently accept Websocket frames. "
+ "The Websocket upgrade was not performed. "
+ "This may happen as a result of automatic reconnect."}}),
+ {[], EvHandlerState}.
diff --git a/test/gun_SUITE.erl b/test/gun_SUITE.erl
index 1c9ba23..766b1e7 100644
--- a/test/gun_SUITE.erl
+++ b/test/gun_SUITE.erl
@@ -730,6 +730,18 @@ transform_header_name(_) ->
1 = length(HostLines),
gun:close(Pid).
+ws_send_http(_) ->
+ {ok, ListenSocket} = gen_tcp:listen(0, [binary, {active, false}]),
+ {ok, {_, Port}} = inet:sockname(ListenSocket),
+ {ok, ConnPid} = gun:open("localhost", Port, #{
+ protocols => [http]
+ }),
+ {ok, _ClientSocket} = gen_tcp:accept(ListenSocket, 5000),
+ {ok, http} = gun:await_up(ConnPid),
+ gun:ws_send(ConnPid, make_ref(), ping),
+ {error, {connection_error, {badstate, _}}} = gun:await(ConnPid, undefined),
+ gun:close(ConnPid).
+
unix_socket_connect(_) ->
case os:type() of
{win32, _} ->