1 -module(sockjs_cowboy_handler).
2 -behaviour(cowboy_http_handler).
3 -behaviour(cowboy_http_websocket_handler).
5 %% Cowboy http callbacks
6 -export([init/3, handle/2, terminate/2]).
9 -export([websocket_init/3, websocket_handle/3,
10 websocket_info/3, websocket_terminate/3]).
12 -include("sockjs_internal.hrl").
14 %% --------------------------------------------------------------------------
16 init({_Any, http}, Req, Service) ->
17 case sockjs_handler:is_valid_ws(Service, {cowboy, Req}) of
18 {true, {cowboy, _Req1}, _Reason} ->
19 {upgrade, protocol, cowboy_http_websocket};
20 {false, {cowboy, Req1}, _Reason} ->
24 handle(Req, Service) ->
25 {cowboy, Req3} = sockjs_handler:handle_req(Service, {cowboy, Req}),
28 terminate(_Req, _Service) ->
31 %% --------------------------------------------------------------------------
33 websocket_init(_TransportName, Req,
34 Service = #service{logger = Logger,
35 subproto_pref = SubProtocolPref}) ->
36 Req3 = case cowboy_http_req:header(<<"Sec-Websocket-Protocol">>, Req) of
39 {SubProtocols, Req1} ->
41 choose_subprotocol_bin(SubProtocols, SubProtocolPref),
42 {ok, Req2} = cowboy_http_req:set_resp_header(
43 <<"Sec-Websocket-Protocol">>,
44 SelectedSubProtocol, Req1),
48 Req4 = Logger(Service, {cowboy, Req3}, websocket),
50 Service1 = Service#service{disconnect_delay = 5*60*1000},
52 {Info, Req5} = sockjs_handler:extract_info(Req4),
53 SessionPid = sockjs_session:maybe_create(undefined, Service1, Info),
54 {RawWebsocket, {cowboy, Req7}} =
55 case sockjs_handler:get_action(Service, Req5) of
56 {{match, WS}, Req6} when WS =:= websocket orelse
57 WS =:= rawwebsocket ->
61 {ok, Req7, {RawWebsocket, SessionPid}}.
63 websocket_handle({text, Data}, Req, {RawWebsocket, SessionPid} = S) ->
64 case sockjs_ws_handler:received(RawWebsocket, SessionPid, Data) of
66 shutdown -> {shutdown, Req, S}
68 websocket_handle(_Unknown, Req, S) ->
71 websocket_info(go, Req, {RawWebsocket, SessionPid} = S) ->
72 case sockjs_ws_handler:reply(RawWebsocket, SessionPid) of
74 {ok, Data} -> self() ! go,
75 {reply, {text, Data}, Req, S};
76 {close, <<>>} -> {shutdown, Req, S};
77 {close, Data} -> self() ! shutdown,
78 {reply, {text, Data}, Req, S}
80 websocket_info(shutdown, Req, S) ->
83 websocket_terminate(_Reason, _Req, {RawWebsocket, SessionPid}) ->
84 sockjs_ws_handler:close(RawWebsocket, SessionPid),
87 %% --------------------------------------------------------------------------
89 choose_subprotocol_bin(SubProtocols, Pref) ->
90 choose_subprotocol(re:split(SubProtocols, ", *"), Pref).
91 choose_subprotocol(SubProtocols, undefined) ->
92 erlang:hd(lists:reverse(lists:sort(SubProtocols)));
93 choose_subprotocol(SubProtocols, Pref) ->
94 case lists:filter(fun (E) -> lists:member(E, SubProtocols) end, Pref) of
96 [] -> choose_subprotocol(SubProtocols, undefined)