diff options
author | Loïc Hoguin <[email protected]> | 2025-03-28 14:29:06 +0100 |
---|---|---|
committer | Loïc Hoguin <[email protected]> | 2025-03-28 14:29:06 +0100 |
commit | 694fed991b4611147f2da73a183d3b8768f4b45d (patch) | |
tree | 9d99228500aee90925bb1733e0791d9c6e2d7bb3 | |
parent | e10c8f9762ada26457c03a7c3a391ef8e4745d15 (diff) | |
download | gun-694fed991b4611147f2da73a183d3b8768f4b45d.tar.gz gun-694fed991b4611147f2da73a183d3b8768f4b45d.tar.bz2 gun-694fed991b4611147f2da73a183d3b8768f4b45d.zip |
Reject Websocket frames sent over HTTP
-rw-r--r-- | src/gun_http.erl | 14 | ||||
-rw-r--r-- | test/gun_SUITE.erl | 12 |
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, _} -> |