From 172800967c2d53251d7cb1015e3c957c5b065bb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Mon, 5 Dec 2022 17:22:09 +0100 Subject: Document Websocket subprotocol negotiation --- doc/src/manual/gun.asciidoc | 33 +++++++--- doc/src/manual/gun.ws_upgrade.asciidoc | 21 ++++++- doc/src/manual/gun_app.asciidoc | 1 + doc/src/manual/gun_ws_protocol.asciidoc | 108 ++++++++++++++++++++++++++++++++ 4 files changed, 152 insertions(+), 11 deletions(-) create mode 100644 doc/src/manual/gun_ws_protocol.asciidoc (limited to 'doc') diff --git a/doc/src/manual/gun.asciidoc b/doc/src/manual/gun.asciidoc index 9ad3e8e..40559fb 100644 --- a/doc/src/manual/gun.asciidoc +++ b/doc/src/manual/gun.asciidoc @@ -525,12 +525,14 @@ detail. [source,erlang] ---- ws_opts() :: #{ - closing_timeout => timeout(), - compress => boolean(), - flow => pos_integer(), - keepalive => timeout(), - protocols => [{binary(), module()}], - silence_pings => boolean() + closing_timeout => timeout(), + compress => boolean(), + default_protocol => module(), + flow => pos_integer(), + keepalive => timeout(), + protocols => [{binary(), module()}], + silence_pings => boolean(), + user_opts => any() } ---- @@ -550,6 +552,11 @@ Whether to enable permessage-deflate compression. This does not guarantee that compression will be used as it is the server that ultimately decides. Defaults to false. +default_protocol (gun_ws_h):: + +Default protocol module when no Websocket subprotocol is +negotiated. + flow - see below:: The initial flow control value for the Websocket connection. @@ -563,8 +570,10 @@ protocols ([]):: A non-empty list enables Websocket protocol negotiation. The list of protocols will be sent in the sec-websocket-protocol -request header. The handler module interface is currently -undocumented and must be set to `gun_ws_h`. +request header. The given module must follow the +link:man:gun_ws_protocol(3)[gun_ws_protocol(3)] interface. +Gun comes with a default interface in `gun_ws_h` that may +be reused for negotiated protocols. silence_pings (true):: @@ -572,10 +581,16 @@ Whether the ping and pong frames should be sent to the user. In all cases Gun will automatically send a pong frame back when receiving a ping. -// @todo Document default_protocol and user_opts. +user_opts - see below:: + +Additional options that are not in use by Gun unless a custom +Websocket subprotocol is configured and negotiated. +By default no user option is defined. == Changelog +* *2.0*: The `default_protocol` and `user_opts` Websocket + options were added. * *2.0*: The `stream_ref()` type was added. * *2.0*: The option `cookie_store` was added. It can be used to configure a cookie store that Gun will use diff --git a/doc/src/manual/gun.ws_upgrade.asciidoc b/doc/src/manual/gun.ws_upgrade.asciidoc index b553f3b..c6e3850 100644 --- a/doc/src/manual/gun.ws_upgrade.asciidoc +++ b/doc/src/manual/gun.ws_upgrade.asciidoc @@ -20,7 +20,7 @@ ws_upgrade(ConnPid, Path, Headers, WsOpts) ConnPid :: pid() Path :: iodata() Headers :: gun:req_headers() -WsOpts :: gun:ws_opts +WsOpts :: gun:ws_opts() StreamRef :: gun:stream_ref() ---- @@ -39,6 +39,11 @@ Gun does not currently support Websocket over HTTP/2. By default Gun will take the Websocket options from the connection's `ws_opts`. +Websocket subprotocol negotiation is enabled when +the `protocols` option is given. It takes a subprotocol +name and a module implementing the +link:man:gun_ws_protocol(3)[gun_ws_protocol(3)] behavior. + == Arguments ConnPid:: @@ -92,9 +97,21 @@ StreamRef = gun:ws_upgrade(ConnPid, "/ws", [], #{ }). ---- +.Upgrade to Websocket with protocol negotiation +[source,erlang] +---- +StreamRef = gun:ws_upgrade(ConnPid, "/ws", [], #{ + protocols => [ + {<<"mqtt">>, gun_ws_mqtt_h}, + {<<"v12.stomp">>, gun_ws_stomp_h} + ] +}). +---- + == See also link:man:gun(3)[gun(3)], link:man:gun:ws_send(3)[gun:ws_send(3)], link:man:gun_upgrade(3)[gun_upgrade(3)], -link:man:gun_ws(3)[gun_ws(3)] +link:man:gun_ws(3)[gun_ws(3)], +link:man:gun_ws_protocol(3)[gun_ws_protocol(3)] diff --git a/doc/src/manual/gun_app.asciidoc b/doc/src/manual/gun_app.asciidoc index 168d0e9..ca05594 100644 --- a/doc/src/manual/gun_app.asciidoc +++ b/doc/src/manual/gun_app.asciidoc @@ -19,6 +19,7 @@ to the server and reconnects automatically when necessary. * link:man:gun_cookies(3)[gun_cookies(3)] - Cookie store engine * link:man:gun_cookies_list(3)[gun_cookies_list(3)] - Cookie store backend: in-memory, per connection * link:man:gun_event(3)[gun_event(3)] - Events +* link:man:gun_ws_protocol(3)[gun_ws_protocol(3)] - Websocket subprotocols == Dependencies diff --git a/doc/src/manual/gun_ws_protocol.asciidoc b/doc/src/manual/gun_ws_protocol.asciidoc new file mode 100644 index 0000000..417ba94 --- /dev/null +++ b/doc/src/manual/gun_ws_protocol.asciidoc @@ -0,0 +1,108 @@ += gun_ws_protocol(3) + +== Name + +gun_ws_protocol - Websocket subprotocols + +== Description + +The `gun_ws_protocol` module provides the callback interface +and types for implementing Websocket subprotocols. + +== Callbacks + +Websocket subprotocols implement the following interface. + +=== init + +[source,erlang] +---- +init(ReplyTo, StreamRef, Headers, Opts) -> {ok, State} + +ReplyTo :: pid() +StreamRef :: reference() +Headers :: cow_http:headers() +Opts :: gun:ws_opts() +State :: protocol_state() +---- + +Initialize the Websocket protocol. + +ReplyTo:: + +The pid of the process that owns the stream and to +which messages will be sent to. + +StreamRef:: + +The reference for the stream. Must be sent in messages +to distinguish between different streams. + +Headers:: + +Headers that were sent in the response establishing +the Websocket connection. + +Opts:: + +Websocket options. Custom options can be provided in +the `user_opts` key. + +State:: + +State for the protocol. + +=== handle + +[source,erlang] +---- +handle(Frame, State) -> {ok, FlowDec, State} + +Frame :: cow_ws:frame() +State :: protocol_state() +FlowDec :: non_neg_integer() +---- + +Handle a Websocket frame. + +This callback may receive fragmented frames depending +on the protocol and may need to rebuild the full +frame to process it. + +Frame:: + +Websocket frame. + +State:: + +State for the protocol. + +FlowDec:: + +How many messages were sent. Used to update the flow +control state when the feature is enabled. + +== Types + +=== protocol_state() + +[source,erlang] +---- +protocol_state() :: any() +---- + +State for the protocol. + +As this part of the implementation of the protocol +the type may differ between different Websocket +protocol modules. + +== Changelog + +* *2.0*: Module introduced. + +== See also + +link:man:gun(7)[gun(7)], +link:man:gun(3)[gun(3)], +link:man:gun:ws_upgrade(3)[gun:ws_upgrade(3)] -- cgit v1.2.3