View Source Sock behaviour (Sock v0.2.4)
The Sock
behaviour defines an interface for web servers to flexibly host WebSocket
applications.
The lifecycle of a WebSocket connection is codified in the structure of this behaviour, and proceeds as follows:
- First, a client will attempt to Upgrade an HTTP connection to a WebSocket
connection by passing a specific set of headers in an HTTP request. A
Sock
implementation is notified of this via a call tosock_negotiate/2
. The implementation can inspect the request, which is passed as aPlug.Conn
structure. It can then choose to accept or refuse the WebSocket upgrade request - Assuming the
Sock
implementation accepted the WebSocket connection, the HTTP connection is then upgraded to a WebSocket connection, andsock_handle_connection/2
is called to notify the implementation that the connection is now live - The
Sock
implementation will then be notified of client data by way ofsock_handle_text_frame/3
,sock_handle_binary_frame/3
,sock_handle_ping_frame/3
orsock_handle_pong_frame/3
as appropriate. - The
Sock
implementation is free to send data to the client via the passed inSocket
instance at any time - At any time,
sock_handle_close/3
,sock_handle_error/3
orsock_handle_timeout/2
may be called to indicate a close, error or timeout condition respectively - All of the above callbacks take and return a state value, in a manner similar to GenServers.
- The initial value of this state is that returned from the
sock_init/1
callback
Link to this section Summary
Types
Details about why connection is being closed
The result as returned from many sockhandle calls
The type of options returned from the sock_negotiate/2
callback. Possible values have the
following meanings
The result as returned from negotiate calls
A WebSocket status code
Callbacks
Called by the web server implementation when binary data is received from the client. The web server implementation will only call this function once a complete binary frame has been received (that is, once any continuation frames have been received).
Called by the web server implementation when a connection is being closed due to one of the following reasons
Called by the web server implementation after a WebSocket connection has been established (that
is, after sock_negotiate/2
has accepted the connection & the WebSocket handshake has been
successfully completed). Implementations can use this callback to eagerly send data to the
client, subscribe the client to any relevant subscriptions within the application, or any other
task which should be undertaken at the time the connection is established
Called by the web server implementation when a connection is being closed due to one of the following reasons
Called by the web server implementation when the socket process receives
a GenServer.handle_info/2
call which was not otherwise processed by the server
implementation.
Called by the web server implementation when a ping frame has been received from the client.
Note that Sock
implementation SHOULD NOT send a pong frame in response; this MUST be
automatically done by the web server before this callback has been called.
Called by the web server implementation when a pong frame has been received from the client.
Called by the web server implementation when text data is received from the client. The web server implementation will only call this function once a complete text frame has been received (that is, once any continuation frames have been received).
Called by the web server implementation when a connection has not received any client data for a period of time. The exact details of what this means and any particular timeout values are dependent on the underlying web server implementation. The socket connection will be open in this case.
Called by a web server implementation to provide initial state for all future connections. The
manner by which the user specifies the init_arg
value passed into this callback is
implementation dependent.
Called by the web server implementation when a client attempts to upgrade to a WebSocket
connection. At this point, the web server has validated that the upgrade request is technically
correct (that is, it meets all the requirements laid out in RFC6455§4.1), but this callback is
provided in case the Sock
implementation wishes to perform further checks before accepting the
connection (perhaps by considering the request path or various headers).
Link to this section Types
@type close_reason() :: {:local, status_code()} | {:remote, status_code()}
Details about why connection is being closed
The result as returned from many sockhandle calls
@type negotiate_opts() :: {:timeout, timeout()}
The type of options returned from the sock_negotiate/2
callback. Possible values have the
following meanings:
timeout
: Specifies a value to be used for timeout conditions on this connection
@type negotiate_result() :: {:accept, Plug.Conn.t(), state(), [negotiate_opts()]} | {:refuse, Plug.Conn.t(), state()}
The result as returned from negotiate calls
@type state() :: term()
The type of state passed into / returned from Sock
callbacks
@type status_code() :: non_neg_integer()
A WebSocket status code
Link to this section Callbacks
@callback sock_handle_binary_frame(binary(), Sock.Socket.t(), state()) :: handle_result()
Called by the web server implementation when binary data is received from the client. The web server implementation will only call this function once a complete binary frame has been received (that is, once any continuation frames have been received).
The return value from this callback is handled as described in sock_handle_connection/2
@callback sock_handle_close(close_reason(), Sock.Socket.t(), state()) :: any()
Called by the web server implementation when a connection is being closed due to one of the following reasons:
- A
Sock
callback for this connection returned a{:close, state()}
tuple. The reason will be{:local, 1000}
. The socket connection will still be open in this case - The hosting web server is being shut down. The reason will be
{:local, 1001}
. The socket connection will still be open in this case - The client send a connection close frame. The reason will be
{:remote, code}
, wherecode
is the status code sent by the client (or 1005 is no status code was sent). The socket connection will still be open in this case, although care should be taken of the fact that the client may not be listening any longer
The return value from this callback is ignored
@callback sock_handle_connection(Sock.Socket.t(), state()) :: handle_result()
Called by the web server implementation after a WebSocket connection has been established (that
is, after sock_negotiate/2
has accepted the connection & the WebSocket handshake has been
successfully completed). Implementations can use this callback to eagerly send data to the
client, subscribe the client to any relevant subscriptions within the application, or any other
task which should be undertaken at the time the connection is established
The return value from this callback is handled as follows:
{:continue, state()}
: The connection is kept open & its state is updated to the returned value{:close, state()}
: The connection is closed cleanly & its state is updated to the returned value.sock_handle_close/3
will be subsequently called a reason code of 1000 & the updated state{:error, term(), state()}
: The connection is closed abnormally & its state is updated to the returned value.sock_handle_error/3
will be subsequently called with the updated state
@callback sock_handle_error(term(), Sock.Socket.t(), state()) :: any()
Called by the web server implementation when a connection is being closed due to one of the following reasons:
- A
Sock
callback for this connection returned an{:error, reason, state()}
tuple. The socket connection will still be open in this case - The underlying TCP connection was closed unexpectedly. The socket connection will be closed in this case
- The underlying TCP connection connection encountered an error. The socket connection will be closed in this case
The return value from this callback is ignored
@callback sock_handle_info(term(), Sock.Socket.t(), state()) :: handle_result()
Called by the web server implementation when the socket process receives
a GenServer.handle_info/2
call which was not otherwise processed by the server
implementation.
The return value from this callback is handled as described in sock_handle_connection/2
@callback sock_handle_ping_frame(binary(), Sock.Socket.t(), state()) :: handle_result()
Called by the web server implementation when a ping frame has been received from the client.
Note that Sock
implementation SHOULD NOT send a pong frame in response; this MUST be
automatically done by the web server before this callback has been called.
The return value from this callback is handled as described in sock_handle_connection/2
@callback sock_handle_pong_frame(binary(), Sock.Socket.t(), state()) :: handle_result()
Called by the web server implementation when a pong frame has been received from the client.
The return value from this callback is handled as described in sock_handle_connection/2
@callback sock_handle_text_frame(binary(), Sock.Socket.t(), state()) :: handle_result()
Called by the web server implementation when text data is received from the client. The web server implementation will only call this function once a complete text frame has been received (that is, once any continuation frames have been received).
The return value from this callback is handled as described in sock_handle_connection/2
@callback sock_handle_timeout(Sock.Socket.t(), state()) :: any()
Called by the web server implementation when a connection has not received any client data for a period of time. The exact details of what this means and any particular timeout values are dependent on the underlying web server implementation. The socket connection will be open in this case.
The return value from this callback is ignored
Called by a web server implementation to provide initial state for all future connections. The
manner by which the user specifies the init_arg
value passed into this callback is
implementation dependent.
The result returned by sock_init/1
is used as the initial state of all connections using the Sock
implementation. Note that this callback may be called during compilation and as such it must not
return pids, ports or values that are specific to the runtime.
@callback sock_negotiate(conn :: Plug.Conn.t(), state()) :: negotiate_result()
Called by the web server implementation when a client attempts to upgrade to a WebSocket
connection. At this point, the web server has validated that the upgrade request is technically
correct (that is, it meets all the requirements laid out in RFC6455§4.1), but this callback is
provided in case the Sock
implementation wishes to perform further checks before accepting the
connection (perhaps by considering the request path or various headers).
This call is also the last time that the originating request is accessible by the Sock
implementation. Should values from the Plug.Conn
request be needed later on in the WebSocket
lifecycle, this callback should store such values in the returned connection state.
If the Sock
implementation wishes to accept this connection, it should return a {:accept, Plug.Conn.t(), state(), [opts()]}
tuple. The web server will then perform its half of the
connection handshake as outlined in RFC6455§4.2, and subsequently call sock_handle_connection/2
.
The Sock
implementation MUST NOT send any data on the Plug.Conn
connection in this case, or
else the handshake will not be able to complete.
Valid options to return in the final accept
tuple value are as described in the
t:negotiate_opts()
type.
If the Sock
implementation wishes to refuse this connection, it should:
- Create an HTTP response on the
Plug.Conn
connection describing the reason for refusal - Return a
{:refuse, Plug.Conn.t(), state()}
tuple with the updated conn as a second argument