aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2020-11-12 14:00:41 +0100
committerLoïc Hoguin <[email protected]>2020-11-12 14:00:41 +0100
commit4a58077d5162325fa5723690e58e7364adbcb18c (patch)
tree6f088a7a9b9d1f6b0eacdeb98de1eb5b8032b647
parent1ebad8acf803eb797a6c61f6522ebc3b79f104a1 (diff)
downloadgun-4a58077d5162325fa5723690e58e7364adbcb18c.tar.gz
gun-4a58077d5162325fa5723690e58e7364adbcb18c.tar.bz2
gun-4a58077d5162325fa5723690e58e7364adbcb18c.zip
Replace gun:ws_send/2 with gun:ws_send/3
Switching from /2 to /3 should be easy enough. Also update the documentation about HTTP/2 Websocket support.
-rw-r--r--doc/src/guide/migrating_from_1.3.asciidoc6
-rw-r--r--doc/src/guide/protocols.asciidoc17
-rw-r--r--doc/src/guide/websocket.asciidoc8
-rw-r--r--doc/src/manual/gun.ws_send.asciidoc25
-rw-r--r--src/gun.erl18
-rw-r--r--src/gun_ws.erl2
-rw-r--r--test/flow_SUITE.erl12
-rw-r--r--test/shutdown_SUITE.erl6
-rw-r--r--test/ws_autobahn_SUITE.erl6
9 files changed, 43 insertions, 57 deletions
diff --git a/doc/src/guide/migrating_from_1.3.asciidoc b/doc/src/guide/migrating_from_1.3.asciidoc
index aa7d26b..0afd19e 100644
--- a/doc/src/guide/migrating_from_1.3.asciidoc
+++ b/doc/src/guide/migrating_from_1.3.asciidoc
@@ -104,7 +104,7 @@ Gun 2.0 requires Erlang/OTP 22.0 or greater.
example.
* It is now possible to send many Websocket frames in
- a single `gun:ws_send/2` call.
+ a single `gun:ws_send/3` call.
* Gun may now send Websocket ping frames automatically
at intervals determined by the `keepalive` option. It
@@ -186,6 +186,10 @@ Gun 2.0 requires Erlang/OTP 22.0 or greater.
cleaner separation between requests that are followed by
a body and those that don't.
+* The function `gun:ws_send/2` has been replaced with the
+ function `gun:ws_send/3`. The stream reference for the
+ corresponding Websocket upgrade request must now be given.
+
=== Messages added
* The `gun_tunnel_up` message has been added.
diff --git a/doc/src/guide/protocols.asciidoc b/doc/src/guide/protocols.asciidoc
index d2529e3..cd6de2c 100644
--- a/doc/src/guide/protocols.asciidoc
+++ b/doc/src/guide/protocols.asciidoc
@@ -65,10 +65,6 @@ cancellation mechanism which allows Gun to inform the
server to stop sending a response for this particular
request, saving resources.
-It is not currently possible to upgrade an HTTP/2 connection
-to Websocket. Support for this will be added in a future
-release.
-
=== Websocket
Websocket is a binary protocol built on top of HTTP that
@@ -76,12 +72,9 @@ allows asynchronous concurrent communication between the
client and the server. A Websocket server can push data to
the client at any time.
-Websocket is only available as a connection upgrade over
-an HTTP/1.1 connection.
-
-Once the Websocket connection is established, the only
-operation available on this connection is sending Websocket
-frames using `gun:ws_send/2`.
+Once the Websocket connection is established over an HTTP/1.1
+connection, the only operation available on this connection
+is sending Websocket frames using `gun:ws_send/3`.
Gun will send a `gun_ws` message for every frame received.
@@ -108,7 +101,7 @@ current protocol.
| await_body | yes | yes | no
| flush | yes | yes | no
| cancel | yes | yes | no
-| ws_upgrade | yes | no | no
+| ws_upgrade | yes | yes | no
| ws_send | no | no | yes
|===
@@ -122,6 +115,6 @@ current protocol.
| gun_data | yes | yes | no
| gun_trailers | yes | yes | no
| gun_error | yes | yes | yes
-| gun_upgrade | yes | no | no
+| gun_upgrade | yes | yes | no
| gun_ws | no | no | yes
|===
diff --git a/doc/src/guide/websocket.asciidoc b/doc/src/guide/websocket.asciidoc
index 287b3f7..ba06e2c 100644
--- a/doc/src/guide/websocket.asciidoc
+++ b/doc/src/guide/websocket.asciidoc
@@ -49,7 +49,7 @@ undocumented and must be set to `gun_ws_h`.
.Upgrade to Websocket with protocol negotiation
[source,erlang]
----
-gun:ws_upgrade(ConnPid, "/websocket", []
+StreamRef = gun:ws_upgrade(ConnPid, "/websocket", []
#{protocols => [{<<"xmpp">>, gun_ws_h}]}).
----
@@ -88,18 +88,18 @@ Once the Websocket upgrade has completed successfully, you no
longer have access to functions for performing requests. You
can only send and receive Websocket messages.
-Use `gun:ws_send/2` to send messages to the server.
+Use `gun:ws_send/3` to send messages to the server.
.Send a text frame
[source,erlang]
----
-gun:ws_send(ConnPid, {text, "Hello!"}).
+gun:ws_send(ConnPid, StreamRef, {text, "Hello!"}).
----
.Send a text frame, a binary frame and then close the connection
[source,erlang]
----
-gun:ws_send(ConnPid, [
+gun:ws_send(ConnPid, StreamRef, [
{text, "Hello!"},
{binary, BinaryValue},
close
diff --git a/doc/src/manual/gun.ws_send.asciidoc b/doc/src/manual/gun.ws_send.asciidoc
index b39f3f0..224472e 100644
--- a/doc/src/manual/gun.ws_send.asciidoc
+++ b/doc/src/manual/gun.ws_send.asciidoc
@@ -8,13 +8,14 @@ gun:ws_send - Send Websocket frames
[source,erlang]
----
-ws_send(ConnPid, Frames) -> ok
-
-ConnPid :: pid()
-Frames :: Frame | [Frame]
-Frame :: close | ping | pong
- | {text | binary | close | ping | pong, iodata()}
- | {close, non_neg_integer(), iodata()}
+ws_send(ConnPid, StreamRef, Frames) -> ok
+
+ConnPid :: pid()
+StreamRef :: gun:stream_ref()
+Frames :: Frame | [Frame]
+Frame :: close | ping | pong
+ | {text | binary | close | ping | pong, iodata()}
+ | {close, non_neg_integer(), iodata()}
----
Send Websocket frames.
@@ -28,6 +29,10 @@ ConnPid::
The pid of the Gun connection process.
+StreamRef::
+
+Identifier of the stream that was upgraded to Websocket.
+
Frames::
One or more Websocket frame(s).
@@ -38,6 +43,8 @@ The atom `ok` is returned.
== Changelog
+* *2.0*: The mandatory `StreamRef` argument was added.
+* *2.0*: It is now possible to send multiple frames at once.
* *1.0*: Function introduced.
== Examples
@@ -45,13 +52,13 @@ The atom `ok` is returned.
.Send a single frame
[source,erlang]
----
-gun:ws_send(ConnPid, {text, <<"Hello world!">>}).
+gun:ws_send(ConnPid, StreamRef, {text, <<"Hello world!">>}).
----
.Send many frames including a close frame
[source,erlang]
----
-gun:ws_send(ConnPid, [
+gun:ws_send(ConnPid, StreamRef, [
{text, <<"See you later, world!">>},
close
]).
diff --git a/src/gun.erl b/src/gun.erl
index 97cd3c9..2966910 100644
--- a/src/gun.erl
+++ b/src/gun.erl
@@ -92,7 +92,6 @@
-export([ws_upgrade/2]).
-export([ws_upgrade/3]).
-export([ws_upgrade/4]).
--export([ws_send/2]).
-export([ws_send/3]).
%% Internals.
@@ -930,12 +929,6 @@ ws_upgrade(ServerPid, Path, Headers, Opts0) ->
gen_statem:cast(ServerPid, {ws_upgrade, ReplyTo, StreamRef, Path, normalize_headers(Headers), Opts}),
StreamRef.
-%% @todo ws_send/2 will need to be deprecated in favor of a variant with StreamRef.
-%% But it can be kept for the time being since it can still work for HTTP/1.1 (connected_ws_only).
--spec ws_send(pid(), ws_frame() | [ws_frame()]) -> ok.
-ws_send(ServerPid, Frames) ->
- gen_statem:cast(ServerPid, {ws_send, self(), Frames}).
-
-spec ws_send(pid(), stream_ref(), ws_frame() | [ws_frame()]) -> ok.
ws_send(ServerPid, StreamRef, Frames) ->
gen_statem:cast(ServerPid, {ws_send, self(), StreamRef, Frames}).
@@ -1219,11 +1212,6 @@ connected_ws_only(cast, {ws_send, ReplyTo, StreamRef, Frames}, State=#state{
ProtoState, dereference_stream_ref(StreamRef, State),
ReplyTo, EvHandler, EvHandlerState0),
commands(Commands, State#state{event_handler_state=EvHandlerState});
-connected_ws_only(cast, {ws_send, ReplyTo, Frames}, State=#state{
- protocol=Protocol=gun_ws, protocol_state=ProtoState,
- event_handler=EvHandler, event_handler_state=EvHandlerState0}) ->
- {Commands, EvHandlerState} = Protocol:ws_send(Frames, ProtoState, ReplyTo, EvHandler, EvHandlerState0),
- commands(Commands, State#state{event_handler_state=EvHandlerState});
connected_ws_only(cast, Msg, _)
when element(1, Msg) =:= headers; element(1, Msg) =:= request; element(1, Msg) =:= data;
element(1, Msg) =:= connect; element(1, Msg) =:= ws_upgrade ->
@@ -1309,12 +1297,6 @@ connected(cast, {ws_send, ReplyTo, StreamRef, Frames}, State=#state{
ProtoState, dereference_stream_ref(StreamRef, State),
ReplyTo, EvHandler, EvHandlerState0),
commands(Commands, State#state{event_handler_state=EvHandlerState});
-%% Catch-all for the StreamRef-free variant.
-connected(cast, {ws_send, ReplyTo, _}, _) ->
- ReplyTo ! {gun_error, self(), {badstate,
- "Connection needs to be upgraded to Websocket "
- "before the gun:ws_send/1 function can be used."}},
- keep_state_and_data;
connected(Type, Event, State) ->
handle_common_connected(Type, Event, ?FUNCTION_NAME, State).
diff --git a/src/gun_ws.erl b/src/gun_ws.erl
index a1fdfae..73c0fd7 100644
--- a/src/gun_ws.erl
+++ b/src/gun_ws.erl
@@ -28,7 +28,6 @@
-export([closing/4]).
-export([close/4]).
-export([keepalive/3]).
--export([ws_send/5]).
-export([ws_send/6]).
-export([down/1]).
@@ -343,6 +342,7 @@ ws_send([Frame|Tail], State, ReplyTo, EvHandler, EvHandlerState0) ->
Other
end.
+%% @todo We should probably check the _StreamRef value.
ws_send(Frames, State, _StreamRef, ReplyTo, EvHandler, EvHandlerState) ->
ws_send(Frames, State, ReplyTo, EvHandler, EvHandlerState).
diff --git a/test/flow_SUITE.erl b/test/flow_SUITE.erl
index feb5b2e..9425ed3 100644
--- a/test/flow_SUITE.erl
+++ b/test/flow_SUITE.erl
@@ -183,9 +183,9 @@ flow_ws(_) ->
%% We send 2 frames with some time in between to make sure that
%% Gun handles them in separate Protocol:handle calls.
Frame = {text, <<"Hello!">>},
- gun:ws_send(ConnPid, Frame),
+ gun:ws_send(ConnPid, StreamRef, Frame),
timer:sleep(500),
- gun:ws_send(ConnPid, Frame),
+ gun:ws_send(ConnPid, StreamRef, Frame),
%% We set the flow to 1 therefore we will receive 1 data message,
%% and then nothing because Gun doesn't read from the socket.
{ws, _} = gun:await(ConnPid, StreamRef),
@@ -193,9 +193,9 @@ flow_ws(_) ->
%% We then update the flow, send 2 frames with some time in between
%% and get 2 more data messages but no more.
gun:update_flow(ConnPid, StreamRef, 2),
- gun:ws_send(ConnPid, Frame),
+ gun:ws_send(ConnPid, StreamRef, Frame),
timer:sleep(500),
- gun:ws_send(ConnPid, Frame),
+ gun:ws_send(ConnPid, StreamRef, Frame),
{ws, _} = gun:await(ConnPid, StreamRef),
{ws, _} = gun:await(ConnPid, StreamRef),
{error, timeout} = gun:await(ConnPid, StreamRef, 1000),
@@ -259,9 +259,9 @@ no_flow_ws(_) ->
{upgrade, [<<"websocket">>], _} = gun:await(ConnPid, StreamRef),
gun:update_flow(ConnPid, StreamRef, 2),
Frame = {text, <<"Hello!">>},
- gun:ws_send(ConnPid, Frame),
+ gun:ws_send(ConnPid, StreamRef, Frame),
timer:sleep(100),
- gun:ws_send(ConnPid, Frame),
+ gun:ws_send(ConnPid, StreamRef, Frame),
{ws, _} = gun:await(ConnPid, StreamRef),
{ws, _} = gun:await(ConnPid, StreamRef),
gun:close(ConnPid)
diff --git a/test/shutdown_SUITE.erl b/test/shutdown_SUITE.erl
index 27e9f4b..3b3ddf2 100644
--- a/test/shutdown_SUITE.erl
+++ b/test/shutdown_SUITE.erl
@@ -534,7 +534,7 @@ ws_gun_send_close_frame(Config) ->
%% We send a close frame. We expect the same frame back
%% before the connection is closed.
Frame = {close, 3333, <<>>},
- gun:ws_send(ConnPid, Frame),
+ gun:ws_send(ConnPid, StreamRef, Frame),
{ws, Frame} = gun:await(ConnPid, StreamRef),
gun_is_down(ConnPid, ConnRef, normal).
@@ -563,7 +563,7 @@ closing_gun_shutdown(Config) ->
%% We send a close frame then immediately call gun:shutdown/1.
%% We expect Gun to go down without retrying to reconnect.
Frame = {close, 3333, <<>>},
- gun:ws_send(ConnPid, Frame),
+ gun:ws_send(ConnPid, StreamRef, Frame),
gun:shutdown(ConnPid),
{ws, Frame} = gun:await(ConnPid, StreamRef),
gun_is_down(ConnPid, ConnRef, shutdown).
@@ -586,7 +586,7 @@ do_closing_owner_down(Config, ExitReason, DownReason) ->
{ok, http} = gun:await_up(ConnPid),
StreamRef = gun:ws_upgrade(ConnPid, "/ws_frozen", []),
{upgrade, [<<"websocket">>], _} = gun:await(ConnPid, StreamRef),
- gun:ws_send(ConnPid, {close, 3333, <<>>}),
+ gun:ws_send(ConnPid, StreamRef, {close, 3333, <<>>}),
timer:sleep(100),
exit(ExitReason)
end),
diff --git a/test/ws_autobahn_SUITE.erl b/test/ws_autobahn_SUITE.erl
index 0caf108..69894d7 100644
--- a/test/ws_autobahn_SUITE.erl
+++ b/test/ws_autobahn_SUITE.erl
@@ -115,13 +115,13 @@ run_cases(N, Total) ->
loop(Pid, MRef, StreamRef) ->
receive
{gun_ws, Pid, StreamRef, close} ->
- gun:ws_send(Pid, close),
+ gun:ws_send(Pid, StreamRef, close),
loop(Pid, MRef, StreamRef);
{gun_ws, Pid, StreamRef, {close, Code, _}} ->
- gun:ws_send(Pid, {close, Code, <<>>}),
+ gun:ws_send(Pid, StreamRef, {close, Code, <<>>}),
loop(Pid, MRef, StreamRef);
{gun_ws, Pid, StreamRef, Frame} ->
- gun:ws_send(Pid, Frame),
+ gun:ws_send(Pid, StreamRef, Frame),
loop(Pid, MRef, StreamRef);
{gun_down, Pid, ws, _, _} ->
close(Pid, MRef);