aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2015-04-10 16:34:21 +0300
committerLoïc Hoguin <[email protected]>2015-04-10 16:34:21 +0300
commitcff0a87d3cbdcf67a9049cdc2784d459711e2867 (patch)
tree6eabc302b146843e8d00bd761be41b32d8f478d3
parentc46991067a53c81316a69c1df7c7dc590f3ca308 (diff)
downloadgun-cff0a87d3cbdcf67a9049cdc2784d459711e2867.tar.gz
gun-cff0a87d3cbdcf67a9049cdc2784d459711e2867.tar.bz2
gun-cff0a87d3cbdcf67a9049cdc2784d459711e2867.zip
Add Websocket options
Allow passing Websocket options through either open or ws_upgrade. Document ws_upgrade/4.
-rw-r--r--doc/src/guide/websocket.asciidoc8
-rw-r--r--doc/src/manual/gun.asciidoc18
-rw-r--r--src/gun.erl32
-rw-r--r--src/gun_ws.erl11
4 files changed, 54 insertions, 15 deletions
diff --git a/doc/src/guide/websocket.asciidoc b/doc/src/guide/websocket.asciidoc
index 23c5030..83a8384 100644
--- a/doc/src/guide/websocket.asciidoc
+++ b/doc/src/guide/websocket.asciidoc
@@ -14,7 +14,7 @@ HTTP/1.1 connections can be upgraded to Websocket, so you might
need to restrict the protocol to HTTP/1.1 if you are planning
to use Websocket over TLS.
-You must use the `gun_ws:upgrade/{2,3}` function to upgrade
+You must use the `gun_ws:upgrade/{2,3,4}` function to upgrade
to Websocket. This function can be called anytime after connection,
so you can send HTTP requests before upgrading to Websocket.
@@ -34,6 +34,12 @@ gun:ws_upgrade(ConnPid, "/websocket", [
{<<"sec-websocket-protocol">>, "mychat"}
]).
+You can pass the Websocket options as part of the `gun:open/{2,3}`
+call when opening the connection, or using the `gun:ws_upgrade/4`.
+The fourth argument is those same options. This function call
+will crash if the options are incorrect, unlike when passing
+them through `gun:open/{2,3}`.
+
The success or failure of this operation will be sent as a
message.
diff --git a/doc/src/manual/gun.asciidoc b/doc/src/manual/gun.asciidoc
index fb457a4..7c12fc3 100644
--- a/doc/src/manual/gun.asciidoc
+++ b/doc/src/manual/gun.asciidoc
@@ -18,7 +18,7 @@ Configuration for the connection.
The following keys are defined:
-http_opts => gun:http_opts()::
+http_opts => http_opts()::
Options specific to the HTTP protocol. See below.
protocols => [http | spdy]::
Ordered list of preferred protocols. When the transport is tcp,
@@ -33,7 +33,7 @@ retry => non_neg_integer()::
Defaults to 5.
retry_timeout => pos_integer()::
Time between retries in milliseconds. Defaults to 5000.
-spdy_opts => gun:spdy_opts()::
+spdy_opts => spdy_opts()::
Options specific to the SPDY protocol. See below.
trace => boolean()::
Whether to enable `dbg` tracing of the connection process. Should
@@ -44,6 +44,8 @@ transport => tcp | ssl::
transport_opts => proplists:proplist()::
Transport options. They are TCP options or SSL options depending on
the selected transport.
+ws_opts => ws_opts()::
+ Options specific to the Websocket protocol. See below.
=== http_opts() = map()
@@ -640,18 +642,20 @@ SPDY streams can however be cancelled at any time.
=== ws_upgrade(ConnPid, Path) -> ws_upgrade(ConnPid, Path, [], #{})
-Alias of `gun:ws_upgrade/4`.
+Alias of `gun:ws_upgrade/3`.
-=== ws_upgrade(ConnPid, Path, Headers) -> ws_upgrade(ConnPid, Path, Headers, #{})
+=== ws_upgrade(ConnPid, Path, Headers) -> ok
-Alias of `gun:ws_upgrade/4`.
+Similar to `gun:ws_upgrade/4`, except `WsOpts` is taken from
+the options given in the `gun:open/{2,3}` call when opening
+the connection.
-=== ws_upgrade(ConnPid, Path, Headers, Opts) -> ok
+=== ws_upgrade(ConnPid, Path, Headers, WsOpts) -> ok
ConnPid = pid():: The pid of the Gun connection process.
Path = iodata():: Path to the resource.
Headers = [{binary(), iodata()}]:: Additional request headers.
-Opts = map():: Options for the Websocket connection.
+WsOpts = map():: Options for the Websocket connection.
Request the connection to be upgraded to the Websocket protocol.
diff --git a/src/gun.erl b/src/gun.erl
index 5d564a5..ae30494 100644
--- a/src/gun.erl
+++ b/src/gun.erl
@@ -169,6 +169,13 @@ check_options([{transport, T}|Opts]) when T =:= tcp; T =:= ssl ->
check_options(Opts);
check_options([{transport_opts, L}|Opts]) when is_list(L) ->
check_options(Opts);
+check_options([{ws_opts, ProtoOpts}|Opts]) when is_map(ProtoOpts) ->
+ case gun_ws:check_options(ProtoOpts) of
+ ok ->
+ check_options(Opts);
+ Error ->
+ Error
+ end;
check_options([Opt|_]) ->
{error, {options, Opt}}.
@@ -421,14 +428,17 @@ cancel(ServerPid, StreamRef) ->
-spec ws_upgrade(pid(), iodata()) -> reference().
ws_upgrade(ServerPid, Path) ->
- ws_upgrade(ServerPid, Path, [], #{}).
+ ws_upgrade(ServerPid, Path, []).
-spec ws_upgrade(pid(), iodata(), headers()) -> reference().
ws_upgrade(ServerPid, Path, Headers) ->
- ws_upgrade(ServerPid, Path, Headers, #{}).
+ StreamRef = make_ref(),
+ _ = ServerPid ! {ws_upgrade, self(), StreamRef, Path, Headers},
+ StreamRef.
-spec ws_upgrade(pid(), iodata(), headers(), ws_opts()) -> reference().
ws_upgrade(ServerPid, Path, Headers, Opts) ->
+ ok = gun_ws:check_options(Opts),
StreamRef = make_ref(),
_ = ServerPid ! {ws_upgrade, self(), StreamRef, Path, Headers, Opts},
StreamRef.
@@ -545,7 +555,7 @@ before_loop(State=#state{opts=Opts, protocol=Protocol}) ->
KeepaliveRef = erlang:send_after(Keepalive, self(), keepalive),
loop(State#state{keepalive_ref=KeepaliveRef}).
-loop(State=#state{parent=Parent, owner=Owner, host=Host, port=Port,
+loop(State=#state{parent=Parent, owner=Owner, host=Host, port=Port, opts=Opts,
socket=Socket, transport=Transport, protocol=Protocol, protocol_state=ProtoState}) ->
{OK, Closed, Error} = Transport:messages(),
Transport:setopts(Socket, [{active, once}]),
@@ -592,6 +602,10 @@ loop(State=#state{parent=Parent, owner=Owner, host=Host, port=Port,
{cancel, Owner, StreamRef} ->
ProtoState2 = Protocol:cancel(ProtoState, StreamRef),
loop(State#state{protocol_state=ProtoState2});
+ {ws_upgrade, Owner, StreamRef, Path, Headers} when Protocol =/= gun_spdy ->
+ WsOpts = maps:get(ws_opts, Opts, #{}),
+ ProtoState2 = Protocol:ws_upgrade(ProtoState, StreamRef, Host, Port, Path, Headers, WsOpts),
+ loop(State#state{protocol_state=ProtoState2});
{ws_upgrade, Owner, StreamRef, Path, Headers, WsOpts} when Protocol =/= gun_spdy ->
ProtoState2 = Protocol:ws_upgrade(ProtoState, StreamRef, Host, Port, Path, Headers, WsOpts),
loop(State#state{protocol_state=ProtoState2});
@@ -605,19 +619,23 @@ loop(State=#state{parent=Parent, owner=Owner, host=Host, port=Port,
{dbg_send_raw, Owner, Data} ->
Transport:send(Socket, Data),
loop(State);
- Any when is_tuple(Any), is_pid(element(2, Any)) ->
- element(2, Any) ! {gun_error, self(), {notowner,
- "Operations are restricted to the owner of the connection."}},
- loop(State);
{ws_upgrade, _, StreamRef, _, _} ->
Owner ! {gun_error, self(), StreamRef, {badstate,
"Websocket is only supported over HTTP/1.1."}},
loop(State);
+ {ws_upgrade, _, StreamRef, _, _, _} ->
+ Owner ! {gun_error, self(), StreamRef, {badstate,
+ "Websocket is only supported over HTTP/1.1."}},
+ loop(State);
{ws_send, _, _} ->
Owner ! {gun_error, self(), {badstate,
"Connection needs to be upgraded to Websocket "
"before the gun:ws_send/1 function can be used."}},
loop(State);
+ Any when is_tuple(Any), is_pid(element(2, Any)) ->
+ element(2, Any) ! {gun_error, self(), {notowner,
+ "Operations are restricted to the owner of the connection."}},
+ loop(State);
Any ->
error_logger:error_msg("Unexpected message: ~w~n", [Any]),
loop(State)
diff --git a/src/gun_ws.erl b/src/gun_ws.erl
index 9e35fa6..66d0fa2 100644
--- a/src/gun_ws.erl
+++ b/src/gun_ws.erl
@@ -14,6 +14,7 @@
-module(gun_ws).
+-export([check_options/1]).
-export([name/0]).
-export([init/5]).
-export([handle/2]).
@@ -42,6 +43,16 @@
extensions = #{} :: cow_ws:extensions()
}).
+check_options(Opts) ->
+ do_check_options(maps:to_list(Opts)).
+
+do_check_options([]) ->
+ ok;
+do_check_options([{compress, B}|Opts]) when B =:= true; B =:= false ->
+ do_check_options(Opts);
+do_check_options([Opt|_]) ->
+ {error, {options, {spdy, Opt}}}.
+
name() -> ws.
%% @todo Protocols