<erl>
out(A) ->
    {ssi, "TAB.inc", "%%",[{"websockets", "choosen"}]}.
</erl>

<div id="entry">
  <h1>WebSockets in Yaws</h1>

  <p>
    WebSockets! The new kid in town! Joe
    <a href="http://armstrongonsoftware.blogspot.com/2009/12/comet-is-dead-long-live-websockets.html">loves it</a>,
    maybe you should too?
  </p>

  <p>
    WebSockets allow for *real* two-way communication between the browser and
    Yaws without the overhead and latency that come with polling/long-polling
    solutions. That should be enough for an introduction. Now... how to use it?
  </p>

  <h3>A simple example</h3>

  <p>
    First of all, here is a simple example. It shows how to upgrade connections
    from HTTP to WebSocket.
  </p>
  <div class="box">
<pre>
<erl>
out(A) ->
    {ssi, "websockets_example_endpoint.yaws",[],[]}.
</erl>
</pre>
  </div>
  <p>
    The above code can be executed <a href="websockets_example.yaws">Here</a>.
  </p>

  <h3>Establish a WebSocket connection</h3>

  <p>
    To establish a WebSocket connection, a client must send a valid HTTP
    Upgrade request. Then, from the server side, the Yaws script (or the appmod
    or whatever) should return:
  </p>
  <div class="box">
<pre>
{websocket, CallbackMod, Options}
</pre>
  </div>

  <p>
    where <code>CallbackMod</code> is an atom identifying the WebSocket callback
    module, and <code>Options</code> is a (possibly empty) list (see below for
    details).
  </p>

  <p>
    From here, Yaws spawns an Erlang process to manage the WebSocket
    connection. Once the handshake response is returned by Yaws, the connection
    is established and the handling process is ready to send or receive data. If
    something goes wrong during this step, Yaws returns an HTTP error (400, 403
    or 500 depending of the error type).
  </p>

  <h4>Supported Options</h4>

  <p>
    The following options are available:
    <ul>
      <li>
        <code>{callback, CallbackType}</code>
        <p>
          Specify the type of the callback module. <code>CallbackType</code> can
          be either of the following:
          <ul>
            <li style="margin-bottom: 10px;">
              <code>basic</code> - Same as <code>{basic, []}</code>. This is the
              default.
            </li>
            <li style="margin-bottom: 10px;">
              <code>{basic, InitialState}</code> - Indicate your callback module
              is a basic callback module. <code>InitialState</code> is the
              callback's initial state for handling this client.
            </li>
            <li style="margin-bottom: 10px;">
              <code>{advanced, InitialState}</code> - Same as above but for an
              advanced callback module.
            </li>
          </ul>
        </p>
      </li>
      <li>
        <code>{origin, Origin}</code>
        <p>
          Specify the <code>Origin</code> URL from which messages will be
          accepted. This is useful for protecting against cross-site attack. The
          option defaults to <code>any</code>, meaning calls will be accepted
          from any origin.
        </p>
      </li>
      <li>
        <code>{keepalive, KeepAliveBoolean}</code>
        <p>
          If true, Yaws will automatically send a ping message
          every <code>keepAliveTimeout</code> milliseconds. By default keepalive
          pings are disabled.
        </p>
      </li>
      <li>
        <code>{keepalive_timeout, keepAliveTimeout}</code>
        <p>
          Specify the interval in milliseconds to send keepalive pings, by
          default 30000. Ignored if <code>KeepAliveBoolean</code> is false.
        </p>
      </li>
      <li>
        <code>{keepalive_grace_period, KeepAliveGracePeriod}</code>
        <p>
          Specify the amount of time, in milliseconds, to wait after sending a
          keepalive ping. If no message is received
          within <code>KeepAliveGracePeriod</code> milliseconds, a timeout will
          occur. Depending on the <code>DropBoolean</code> value, a close frame
          is sent with the status code 1006 (if <code>DropBoolean</code> is
          true) or the callback module is notified
          (see <code>Module:handle_info/2</code> below). <br/> By
          default, <code>KeepAliveGracePeriod</code> is set to 2000. Ignored
          if <code>KeepAliveBoolean</code> is false.
        </p>
      </li>
      <li>
        <code>{drop_on_timeout, DropBoolean}</code>
        <p>
          If true, a close frame is sent with the status code 1006 when a
          timeout occurs after a keepalive ping has been sent
          (see <code>KeepAliveGracePeriod</code>). Disabled by default. Ignored
          if <code>KeepAliveBoolean</code> is false.
        </p>
      </li>
      <li>
        <code>{close_timeout, CloseTimeout}</code>
        <p>
          After sending a close frame to a client, Yaws will wait for the client
          acknowledgement for <code>CloseTimeout</code> milliseconds. Then it
          will close the underlying TCP connection. By
          default <code>CloseTimeout</code> is set to 5000.
        </p>
      </li>
      <li>
        <code>{close_if_unmasked, CloseUnmaskedBoolean}</code>
        <p>
          If true, Yaws will reject any unmasked incoming frame by sending a
          close frame with the status code 1002. Disabled by default.<br/>
          Note: According to RFC 6455, a client must mask all frames that it
          sends to the server
          (See <a href="https://tools.ietf.org/html/rfc6455#section-5.1">RFC
          6455 - Section 5.1</a>).
        </p>
      </li>
      <li>
        <code>{max_frame_size, MaxFrameSize}</code>
        <p>
          Specify the maximum allowed size, in bytes, for received frames. By
          default 16MB. It is also the maximum size for unfragmented
          messages.<br/> This limit is checked for all types of callback module.
        </p>
      </li>
      <li>
        <code>{max_message_size, MaxMsgSize}</code>
        <p>
          Specify the maximum allowed message size in bytes, by default
          16MB.<br/> This limit is checked only for basic callback modules.
        </p>
      </li>
      <li>
        <code>{auto_fragment_message, AutoFragBoolean}</code>
        <p>
          If true, outgoing messages will be automatically fragmented if their
          payload exceeds <code>OutFragSize</code> bytes. This flag is set to
          false by default.
        </p>
      </li>
      <li>
        <code>{auto_fragment_threshold, OutFragSize}</code>
        <p>
          Specify the maximum payload size of each fragment
          if <code>AutoFragBoolean</code> is true. <code>OutFragSize</code> is
          set to 1MB by default. Ignored is <code>AutoFragBoolean</code> is
          false.
        </p>
      </li>
    </ul>
  </p>

  <h3>WebSocket callback modules</h3>

  <p>
    All frames received on a WebSocket connection are passed to the callback
    modules specified during the connection establishment by
    calling <code>Module:handle_message/1</code>
    or <code>Module:handle_message/2</code>, depending on whether it’s a basic
    or an advanced callback module.
  </p>

  <h4>Basic callback modules</h4>

  <p>
    When a basic callback module is used, the messages defragmentation is
    handled by Yaws. From the callback module point of view, all incoming
    messages are unfragmented. This implies that fragmented frames will be
    accumulated, thus basic callback modules does not support data streaming.
  </p>

  <p>
    A basic callback module <strong>MUST</strong> define the stateless
    function <code>Module:handle_message/1</code>:
  </p>
  <blockquote>
    <strong>Module:handle_message(Message) -> Result</strong>
<pre>
    Message :: {Type, Data} | {close, Status, Reason}
    Result  :: noreply | {reply, Reply} | {close, CloseReason}
      Type        :: text | binary
      Data        :: binary()
      Reply       :: {Type, Data} | #ws_frame{} |
                     [{Type, Data}] | [#ws_frame{}]
      CloseReason :: Status | {Status, Reason}
      Status      :: integer() %% RFC 6455 Status Code
      Reason      :: binary()
</pre>
    <p>
      This function is called when a message is received. <code>{text,
      Data}</code> (or <code>{binary, Data}</code>) is the unfragmented text (or
      binary) message. When the client closes the connection, the callback
      module is notified with the message <code>{close, Status, Reason}</code>,
      where <code>Status</code> is the numerical status code sent by the client
      or the value 1000
      (see <a href="http://tools.ietf.org/html/rfc6455#section-7.4.1">RFC 6455 -
      Section 7.4.1</a>) if the client sent no status code. For an abnormal
      client closure, the status code is 1006 (as specified
      by <a href="http://tools.ietf.org/html/rfc6455#section-7.1.5">RFC 6455 -
      Section 7.1.5</a>). <code>Reason</code> is a binary containing any text
      the client sent to indicate the reason for closing the socket; this binary
      may be empty.
    </p>
    <p>
      If the function returns <code>{reply, Reply}</code>, <code>Reply</code> is
      sent to the client. It is possible to send one or more unfragmentated
      messages by returning <code>{Type, Data}</code> or <code>[{Type,
      Data}]</code>. It is also possible to send one or more frames
      using the <code>#ws_frame{}</code> record instead, defined
      in <code>include/yaws_api.hrl</code> (useful to fragment messages by
      hand).
    </p>
    <p>
      If the function returns <code>noreply</code>, nothing happens.
    </p>
    <p>
      If the function returns <code>{close, CloseReason}</code>, the handling
      process closes the connection sending a close control frame to the
      client. <code>CloseReason</code> is used to set the status code and the
      (optional) close reason of the close control frame. Then the handling
      process terminates calling <code>Module:terminate(CloseReason,
      State)</code> (if defined, see below).
    </p>
  </blockquote>

  <p>
    Because just handling messages is not enough for real applications, a basic
    callback module can define optional functions, mainly to manage a callback
    state. It can define one, some or all of the following functions:
  </p>
  <blockquote>
    <strong>Module:init(Args) -> Result</strong>
<pre>
    Args   :: [ReqArg, InitialState]
    Result :: {ok, State} | {ok, State, Timeout} | {error, Reason}
      ReqArg       :: #arg{}
      InitialState :: term()
      State        :: term()
      Timeout      :: integer() >= 0 | infinity
      Reason       :: term()
</pre>
    <p>
      If defined, this function is called to initialize the internal state of
      the callback module.
    </p>
    <p>
      <code>ReqArg</code> is the #arg{} record supplied to
      the <code>out/1</code> function and <code>InitialState</code> is the term
      associated to the <code>CallbackType</code> described above.
    </p>
    <p>
      If an integer timeout value is provided, it will overload the next
      keepalive timeout (see <code>keepalive_timeout</code> option above). The
      atom <code>infinity</code> can be used to wait indefinitely. If no value
      is specified, the default keepalive timeout is used.
    </p>
    <p>
      If something goes wrong during initialization, the function should
      return <code>{error, Reason}</code>, where <code>Reason</code> is any
      term.
    </p>
  </blockquote>

  <blockquote>
    <strong>Module:handle_open(WSState, State) -> Result</strong>
<pre>
    WSState :: #ws_state{}
    State   :: term()
    Result  :: {ok, NewState} {error, Reason}
      NewState :: term()
      Reason   :: term()
</pre>
    <p>
      If defined, this function is called when the connection is upgraded from
      HTTP to WebSocket.
    </p>
    <p>
      <code>WSState</code> is the state of the WebSocket connection. It can be
      used to send messages to the client
      using <code>yaws_api:websocket_send(WSState, Message)</code>.
    </p>
    <p>
      <code>State</code> is the internal state of the callback module.
    </p>
    <p>
      If the function returns <code>{ok, NewState}</code>, the handling process
      will continue executing with the possibly updated internal
      state <code>NewState</code>.
    </p>
    <p>
      If the function returns <code>{error, Reason}</code>, the handling
      process closes the connection and terminates
      calling <code>Module:terminate({error, Reason}, State)</code> (if defined,
      see below).
    </p>
  </blockquote>

  <blockquote>
    <strong>Module:handle_message(Message, State) -> Result</strong>
<pre>
    Message :: see Module:handle_message/1
    State   :: term()
    Result  :: {noreply, NewState} | {noreply, NewState, Timeout} |
               {reply, Reply} | {reply, Reply, NewState} |
               {reply, Reply, NewState, Timeout} |
               {close, CloseReason, NewState} |
               {close, CloseReason, Reply, NewState}
      NewState    :: term()
      Timeout     :: integer() >= 0 | infinity
      Reply       :: see Module:handle_message/1
      CloseReason :: see Module:handle_message/1
</pre>
    <p>
      If defined, this function is called in place
      of <code>Module:handle_message/1</code>. The main difference with the
      previous version is that this one handles the internal state of the
      callback module.
    </p>
    <p>
      <code>State</code> is internal state of the callback module.
    </p>
    <p>
      See <code>Module:handle_message/1</code> for a description of the other
      arguments and possible return values.
    </p>
  </blockquote>

  <blockquote>
    <strong>Module:handle_info(Info, State) -> Result</strong>
<pre>
    Info   :: timeout | term()
    State  :: term()
    Result :: {noreply, NewState} | {noreply, NewState, Timeout} |
              {reply, Reply} | {reply, Reply, NewState} |
              {reply, Reply, NewState, Timeout} |
              {close, CloseReason, NewState} |
              {close, CloseReason, Reply, NewState}
      NewState    :: term()
      Timeout     :: integer() >= 0 | infinity
      Reply       :: see Module:handle_message/1
      CloseReason :: see Module:handle_message/1
</pre>
    <p>
      If defined, this function is called when a timeout occurs
      (see <code>drop_on_timeout</code> option above) or when the handling
      process receives any unknown message.
    </p>
    <p>
      <code>Info</code> is either the atom <code>timeout</code>, if a timeout
      has occurred, or the received message.
    </p>
    <p>
      See <code>Module:handle_message/1</code> for a description of the other
      arguments and possible return values.
    </p>
  </blockquote>

  <blockquote>
    <strong>Module:terminate(Reason, State) -> ok</strong>
<pre>
    Reason :: Status | {Status, Text} | {error, Error}
    State  :: term()
      Status :: integer() %% RFC 6455 status code
      Text   :: binary()
      Error  :: term()
</pre>
    <p>
      If defined, this function is called when the handling process is about to
      terminate. it should be the opposite of <code>Module:init/1</code> and do
      any necessary cleaning up.
    </p>
    <p>
      <code>Reason</code> is a term denoting the stop reason
      and <code>State</code> is the internal state of the callback module.
    </p>
  </blockquote>

  <h4>Advanced callback modules</h4>

  <p>
    Advanced callback modules should be used when automatic messages
    defragmentation done by Yaws is not desirable or acceptable. One could be
    used for example to handle data streaming over WebSockets. So, such modules
    should be prepared to handle frames directly (fragmented or not).
  </p>
  <p>
    Unlike basic callback modules, Advanced ones <strong>MUST</strong> manage an
    internal state. So it <strong>MUST</strong> define the stateful
    function <code>Module:handle_message/2</code> :
  </p>
  <blockquote>
    <strong>Module:handle_message(Frame, State) -> Result</strong>
<pre>
    Frame   :: #ws_frame_info{} | {fail_connection, Status, Reason}
    State   :: term()
    Result  :: {noreply, NewState} | {noreply, NewState, Timeout} |
               {reply, Reply} | {reply, Reply, NewState} |
               {reply, Reply, NewState, Timeout} |
               {close, CloseReason, NewState} |
               {close, CloseReason, Reply, NewState}
      Status      :: integer() %% RFC 6455 status code
      Reason      :: binary()
      NewState    :: term()
      Timeout     :: integer() >= 0 | infinity
      Reply       :: see Module:handle_message/1
      CloseReason :: see Module:handle_message/1
</pre>
    <p>
      This function is called when a frame is
      received. The <code>#ws_frame_info{}</code> record, defined
      in <code>include/yaws_api.hrl</code>, provides all details about this
      frame. <code>State</code> it the internal state of the callback module.
    </p>
    <p>
      If an error occurs during the frame parsing, the
      term <code>{fail_connection, Status, Reason}</code> is passed,
      where <code>Status</code> is the numerical status code corresponding to
      the error
      (see <a href="http://tools.ietf.org/html/rfc6455#section-7.4.1">RFC 6455 -
      Section 7.4.1</a>) and <code>Reason</code> the binary containing optional
      information about it.
    </p>
    <p>
      This function returns the same values as specified for the basic callback
      module's <code>Module:handle_message/2</code>. See above for details.
    </p>
  </blockquote>

  <p>
    Advanced callback modules can also define the same optional functions as
    basic callback modules (except <code>Module:handle_messages/2</code> which
    is mandatory here, of course). See above for details.
  </p>


  <h3>Record definitions</h3>

  <p>
    Here is the definition of records used in callback modules, defined
    in <code>include/yaws_api.hrl</code>:
  </p>
  <div class="box">
<pre>
%% Corresponds to the frame sections as in
%% http://tools.ietf.org/html/rfc6455#section-5.2
%% plus 'data' and 'ws_state'. Used for incoming frames.
-record(ws_frame_info, {
          fin,
          rsv,
          opcode,
          masked,
          masking_key,
          length,
          payload,
          data,        % The unmasked payload. Makes payload redundant.
          ws_state     % The ws_state after unframing this frame.
                       % This is useful for the endpoint to know what type of
                       % fragment a potentially fragmented message is.
         }).

%% Used for outgoing frames. No checks are done on the validity of a frame. This
%% is the application's responsability to send valid frames.
-record(ws_frame, {
          fin = true,
          rsv = 0,
          opcode,
          payload = &lt;&lt;&gt;&gt;
         }).

%%----------------------------------------------------------------------
%% The state of a WebSocket connection.
%% This is held by the ws owner process and passed in calls to yaws_api.
%%----------------------------------------------------------------------
-type frag_type() :: text
                   | binary
                   | none.  % The WebSocket is not expecting continuation
                            % of any fragmented message.
-record(ws_state, {
          vsn :: integer(),                     % WebSocket version number
          sock,                                 % gen_tcp or gen_ssl socket
          frag_type :: frag_type()
         }).
</pre>
  </div>

<erl>
out(A) ->
    {ssi, "END2",[],[]}.
</erl>
