diff options
author | Loïc Hoguin <[email protected]> | 2015-04-10 16:34:21 +0300 |
---|---|---|
committer | Loïc Hoguin <[email protected]> | 2015-04-10 16:34:21 +0300 |
commit | cff0a87d3cbdcf67a9049cdc2784d459711e2867 (patch) | |
tree | 6eabc302b146843e8d00bd761be41b32d8f478d3 | |
parent | c46991067a53c81316a69c1df7c7dc590f3ca308 (diff) | |
download | gun-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.asciidoc | 8 | ||||
-rw-r--r-- | doc/src/manual/gun.asciidoc | 18 | ||||
-rw-r--r-- | src/gun.erl | 32 | ||||
-rw-r--r-- | src/gun_ws.erl | 11 |
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 |