anchor.diff:  %%%----------------------------------------------------------------------
   %%% File    : yaws_websockets.erl
   %%% Author  : Davide Marques <nesrait@gmail.com>
  -%%% Purpose :
  -%%% Created :  18 Dec 2009 by Davide Marques <nesrait@gmail.com>
  -%%% Modified:
  +%%% Purpose : support for WebSockets
  +%%% Created : 18 Dec 2009 by Davide Marques <nesrait@gmail.com>
  +%%% Modified: extensively revamped in 2011 by J.D. Bothma <jbothma@gmail.com>
   %%%----------------------------------------------------------------------
   
   -module(yaws_websockets).
   -author('nesrait@gmail.com').
  +-author('jbothma@gmail.com').
  +-behaviour(gen_server).
   
   -include("../include/yaws.hrl").
   -include("../include/yaws_api.hrl").
  
positive.code:                                 {advanced, InitialState} ->
                                      InitialState
                              end,
              loop(CallbackMod, WSState, CallbackState, CallbackType)
      end.
  
  origin_check(_Origin, {origin, any}) ->
      ok;
  
negative.code: %% RFC 6455 section 7.4.1: status code 1000 means "normal"
  -define(NORMAL_WS_STATUS, 1000).
  
  -record(state, {
            arg,
            sconf,
            cbmod,
            opts,
            wsstate,
            cbstate,
            cbtype
           }).
  
  -export([start/3, send/2]).
  -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
           terminate/2, code_change/3]).
  %%
  %% API
  %%
  start(Arg, CallbackMod, Opts) ->
      SC = get(sc),
      CliSock = Arg#arg.clisock,
      PrepdOpts = preprocess_opts(Opts),
      {ok, OwnerPid} = gen_server:start(?MODULE, [Arg, SC, CallbackMod, PrepdOpts], []),
      CliSock = Arg#arg.clisock,
      TakeOverResult = case SC#sconf.ssl of
                           undefined ->
                               inet:setopts(CliSock, [{packet, raw}, {active, once}]),
                               gen_tcp:controlling_process(CliSock, OwnerPid);
                           _ ->
                               ssl:setopts(CliSock, [{packet, raw}, {active, once}]),
                               ssl:controlling_process(CliSock, OwnerPid)
                       end,
      case TakeOverResult of
          ok ->
              gen_server:cast(OwnerPid, ok),
              exit(normal);
          {error, Reason}=Error ->
              gen_server:cast(OwnerPid, Error),
              exit({websocket, Reason})
      end.
  
  send(Pid, {Type, Data}) ->
      gen_server:cast(Pid, {send, {Type, Data}}).
  
  %%
  %% gen_server functions
  %%
  init([Arg, SC, CallbackMod, Opts]) ->
      {ok, #state{arg=Arg, sconf=SC, cbmod=CallbackMod, opts=Opts}}.
  
  handle_call(_Req, _From, State) ->
      {reply, ok, State}.
  
  handle_cast(ok, #state{arg=Arg, sconf=SC, opts=Opts}=State) ->
      CliSock = Arg#arg.clisock,
      OriginOpt = lists:keyfind(origin, 1, Opts),
      Origin = get_origin_header(Arg#arg.headers),
      case origin_check(Origin, OriginOpt) of
          {error, Error} ->
              error_logger:error_msg(Error),
              {stop, {error, Error}, State};
          ok ->
              ProtocolVersion = ws_version(Arg#arg.headers),
              Protocol = get_protocol_header(Arg#arg.headers),
  