mirror of
https://github.com/processone/ejabberd.git
synced 2024-07-06 23:22:36 +02:00
[TECH-1511] clean support for websockets.
Added handlers in configuration file
This commit is contained in:
parent
c41bdea1f1
commit
35a0e27d04
|
@ -65,7 +65,8 @@
|
||||||
request_tp,
|
request_tp,
|
||||||
request_headers = [],
|
request_headers = [],
|
||||||
end_of_request = false,
|
end_of_request = false,
|
||||||
trail = ""
|
trail = "",
|
||||||
|
websocket_handlers = []
|
||||||
}).
|
}).
|
||||||
|
|
||||||
|
|
||||||
|
@ -134,11 +135,16 @@ init({SockMod, Socket}, Opts) ->
|
||||||
false -> []
|
false -> []
|
||||||
end,
|
end,
|
||||||
?DEBUG("S: ~p~n", [RequestHandlers]),
|
?DEBUG("S: ~p~n", [RequestHandlers]),
|
||||||
|
WebSocketHandlers = case lists:keysearch(websocket_handlers, 1, Opts) of
|
||||||
|
{value, {websocket_handlers, WH}} -> WH;
|
||||||
|
false -> []
|
||||||
|
end,
|
||||||
|
?DEBUG("WS: ~p~n", [WebSocketHandlers]),
|
||||||
?INFO_MSG("started: ~p", [{SockMod1, Socket1}]),
|
?INFO_MSG("started: ~p", [{SockMod1, Socket1}]),
|
||||||
State = #state{sockmod = SockMod1,
|
State = #state{sockmod = SockMod1,
|
||||||
socket = Socket1,
|
socket = Socket1,
|
||||||
request_handlers = RequestHandlers},
|
request_handlers = RequestHandlers,
|
||||||
|
websocket_handlers = WebSocketHandlers},
|
||||||
receive_headers(State).
|
receive_headers(State).
|
||||||
|
|
||||||
|
|
||||||
|
@ -148,6 +154,9 @@ become_controller(_Pid) ->
|
||||||
socket_type() ->
|
socket_type() ->
|
||||||
raw.
|
raw.
|
||||||
|
|
||||||
|
|
||||||
|
send_text(State, none) ->
|
||||||
|
exit(normal);
|
||||||
send_text(State, Text) ->
|
send_text(State, Text) ->
|
||||||
case catch (State#state.sockmod):send(State#state.socket, Text) of
|
case catch (State#state.sockmod):send(State#state.socket, Text) of
|
||||||
ok -> ok;
|
ok -> ok;
|
||||||
|
@ -315,6 +324,23 @@ get_transfer_protocol(SockMod, HostPort) ->
|
||||||
%% found, answer with HTTP 404.
|
%% found, answer with HTTP 404.
|
||||||
process([], _) ->
|
process([], _) ->
|
||||||
ejabberd_web:error(not_found);
|
ejabberd_web:error(not_found);
|
||||||
|
process(Handlers, #ws{} = Ws)->
|
||||||
|
[{HandlerPathPrefix, HandlerModule} | HandlersLeft] = Handlers,
|
||||||
|
case (lists:prefix(HandlerPathPrefix, Ws#ws.path) or
|
||||||
|
(HandlerPathPrefix==Ws#ws.path)) of
|
||||||
|
true ->
|
||||||
|
?DEBUG("~p matches ~p", [Ws#ws.path, HandlerPathPrefix]),
|
||||||
|
%% LocalPath is the path "local to the handler", i.e. if
|
||||||
|
%% the handler was registered to handle "/test/" and the
|
||||||
|
%% requested path is "/test/foo/bar", the local path is
|
||||||
|
%% ["foo", "bar"]
|
||||||
|
LocalPath = lists:nthtail(length(HandlerPathPrefix), Ws#ws.path),
|
||||||
|
ejabberd_hooks:run(ws_debug, [{LocalPath, Ws}]),
|
||||||
|
ejabberd_websocket:connect(Ws#ws{local_path = LocalPath}, HandlerModule);
|
||||||
|
false ->
|
||||||
|
?DEBUG("HandlersLeft : ~p ", [HandlersLeft]),
|
||||||
|
process(HandlersLeft, Ws)
|
||||||
|
end;
|
||||||
process(Handlers, Request) ->
|
process(Handlers, Request) ->
|
||||||
[{HandlerPathPrefix, HandlerModule} | HandlersLeft] = Handlers,
|
[{HandlerPathPrefix, HandlerModule} | HandlersLeft] = Handlers,
|
||||||
|
|
||||||
|
@ -344,6 +370,7 @@ process_request(#state{request_method = Method,
|
||||||
request_tp = TP,
|
request_tp = TP,
|
||||||
request_headers = RequestHeaders,
|
request_headers = RequestHeaders,
|
||||||
sockmod = SockMod,
|
sockmod = SockMod,
|
||||||
|
websocket_handlers = WebSocketHandlers,
|
||||||
socket = Socket} = State)
|
socket = Socket} = State)
|
||||||
when Method=:='GET' orelse Method=:='HEAD' orelse Method=:='DELETE' orelse Method=:='OPTIONS' ->
|
when Method=:='GET' orelse Method=:='HEAD' orelse Method=:='DELETE' orelse Method=:='OPTIONS' ->
|
||||||
case (catch url_decode_q_split(Path)) of
|
case (catch url_decode_q_split(Path)) of
|
||||||
|
@ -375,17 +402,17 @@ process_request(#state{request_method = Method,
|
||||||
Ws = #ws{socket = Socket,
|
Ws = #ws{socket = Socket,
|
||||||
sockmod = SockMod,
|
sockmod = SockMod,
|
||||||
ws_autoexit = true,
|
ws_autoexit = true,
|
||||||
path = Path,
|
path = LPath,
|
||||||
vsn = VSN,
|
vsn = VSN,
|
||||||
host = Host,
|
host = Host,
|
||||||
|
port = Port,
|
||||||
origin = Origin,
|
origin = Origin,
|
||||||
headers = RequestHeaders
|
headers = RequestHeaders
|
||||||
},
|
},
|
||||||
|
?DEBUG("WS: ~p/~p~n", [WebSocketHandlers, Path]),
|
||||||
|
|
||||||
|
|
||||||
?DEBUG("It is a websocket version : ~p",[VSN]),
|
?DEBUG("It is a websocket version : ~p",[VSN]),
|
||||||
ejabberd_websocket:connect(Ws, websocket_test);
|
process(WebSocketHandlers, Ws),
|
||||||
|
none;
|
||||||
false ->
|
false ->
|
||||||
Request = #request{method = Method,
|
Request = #request{method = Method,
|
||||||
path = LPath,
|
path = LPath,
|
||||||
|
|
|
@ -45,6 +45,8 @@
|
||||||
vsn, % {Maj,Min} | {'draft-hixie', Ver}
|
vsn, % {Maj,Min} | {'draft-hixie', Ver}
|
||||||
origin, % the originator
|
origin, % the originator
|
||||||
host, % the host
|
host, % the host
|
||||||
|
port,
|
||||||
path, % the websocket GET request path
|
path, % the websocket GET request path
|
||||||
headers % [{Tag, Val}]
|
headers, % [{Tag, Val}]
|
||||||
|
local_path
|
||||||
}).
|
}).
|
|
@ -41,7 +41,7 @@
|
||||||
-compile(export_all).
|
-compile(export_all).
|
||||||
-include("ejabberd.hrl").
|
-include("ejabberd.hrl").
|
||||||
-include("jlib.hrl").
|
-include("jlib.hrl").
|
||||||
-include ("ejabberd_http.hrl").
|
-include("ejabberd_http.hrl").
|
||||||
|
|
||||||
check(_Path, Headers)->
|
check(_Path, Headers)->
|
||||||
?DEBUG("testing for a websocket request path: ~p headers: ~p", [_Path, Headers]),
|
?DEBUG("testing for a websocket request path: ~p headers: ~p", [_Path, Headers]),
|
||||||
|
@ -51,9 +51,9 @@ check(_Path, Headers)->
|
||||||
check_websockets(VsnSupported, Headers).
|
check_websockets(VsnSupported, Headers).
|
||||||
|
|
||||||
% Connect and handshake with Websocket.
|
% Connect and handshake with Websocket.
|
||||||
connect(#ws{vsn = Vsn, socket = Socket, origin=Origin, host=Host,sockmod = SockMod, path = Path, headers = Headers, ws_autoexit = WsAutoExit} = Ws, WsLoop) ->
|
connect(#ws{vsn = Vsn, socket = Socket, origin=Origin, host=Host, port=Port, sockmod = SockMod, path = Path, headers = Headers, ws_autoexit = WsAutoExit} = Ws, WsLoop) ->
|
||||||
% build handshake
|
% build handshake
|
||||||
HandshakeServer = handshake(Vsn, Socket,SockMod, Headers, {Path, Origin, Host}),
|
HandshakeServer = handshake(Vsn, Socket,SockMod, Headers, {Path, Origin, Host, Port}),
|
||||||
% send handshake back
|
% send handshake back
|
||||||
?DEBUG("building handshake response : ~p", [HandshakeServer]),
|
?DEBUG("building handshake response : ~p", [HandshakeServer]),
|
||||||
SockMod:send(Socket, HandshakeServer),
|
SockMod:send(Socket, HandshakeServer),
|
||||||
|
@ -136,7 +136,7 @@ check_headers(Headers, RequiredHeaders) ->
|
||||||
|
|
||||||
% Function: List
|
% Function: List
|
||||||
% Description: Builds the server handshake response.
|
% Description: Builds the server handshake response.
|
||||||
handshake({'draft-hixie', 76}, Sock,SocketMod, Headers, {Path, Origin, Host}) ->
|
handshake({'draft-hixie', 76}, Sock,SocketMod, Headers, {Path, Origin, Host, Port}) ->
|
||||||
% build data
|
% build data
|
||||||
{_, Key1} = lists:keyfind("Sec-Websocket-Key1",1, Headers),
|
{_, Key1} = lists:keyfind("Sec-Websocket-Key1",1, Headers),
|
||||||
{_, Key2} = lists:keyfind("Sec-Websocket-Key2",1, Headers),
|
{_, Key2} = lists:keyfind("Sec-Websocket-Key2",1, Headers),
|
||||||
|
@ -156,22 +156,26 @@ handshake({'draft-hixie', 76}, Sock,SocketMod, Headers, {Path, Origin, Host}) ->
|
||||||
?ERROR_MSG("tcp error treating data: ~p", [_Other]),
|
?ERROR_MSG("tcp error treating data: ~p", [_Other]),
|
||||||
<<>>
|
<<>>
|
||||||
end,
|
end,
|
||||||
?DEBUG("got content in body of websocket request: ~p", [Body]),
|
?DEBUG("got content in body of websocket request: ~p, ~p", [Body,string:join([Host, Path],"/")]),
|
||||||
% prepare handhsake response
|
% prepare handhsake response
|
||||||
["HTTP/1.1 101 WebSocket Protocol Handshake\r\n",
|
["HTTP/1.1 101 WebSocket Protocol Handshake\r\n",
|
||||||
"Upgrade: WebSocket\r\n",
|
"Upgrade: WebSocket\r\n",
|
||||||
"Connection: Upgrade\r\n",
|
"Connection: Upgrade\r\n",
|
||||||
"Sec-WebSocket-Origin: ", Origin, "\r\n",
|
"Sec-WebSocket-Origin: ", Origin, "\r\n",
|
||||||
"Sec-WebSocket-Location: ws://", Host, ":5280",Path, "\r\n\r\n",
|
"Sec-WebSocket-Location: ws://",
|
||||||
|
string:join([Host, integer_to_list(Port)],":"),
|
||||||
|
"/",string:join(Path,"/") , "\r\n\r\n",
|
||||||
build_challenge({'draft-hixie', 76}, {Key1, Key2, Body})
|
build_challenge({'draft-hixie', 76}, {Key1, Key2, Body})
|
||||||
];
|
];
|
||||||
handshake({'draft-hixie', 68}, _Sock,_SocketMod, _Headers, {Path, Origin, Host}) ->
|
handshake({'draft-hixie', 68}, _Sock,_SocketMod, _Headers, {Path, Origin, Host, Port}) ->
|
||||||
% prepare handhsake response
|
% prepare handhsake response
|
||||||
["HTTP/1.1 101 Web Socket Protocol Handshake\r\n",
|
["HTTP/1.1 101 Web Socket Protocol Handshake\r\n",
|
||||||
"Upgrade: WebSocket\r\n",
|
"Upgrade: WebSocket\r\n",
|
||||||
"Connection: Upgrade\r\n",
|
"Connection: Upgrade\r\n",
|
||||||
"WebSocket-Origin: ", Origin , "\r\n",
|
"WebSocket-Origin: ", Origin , "\r\n",
|
||||||
"WebSocket-Location: ws://", lists:concat([Host, Path]), "\r\n\r\n"
|
"WebSocket-Location: ws://",
|
||||||
|
lists:concat([Host, integer_to_list(Port)]),
|
||||||
|
"/",string:join(Path,"/"), "\r\n\r\n"
|
||||||
].
|
].
|
||||||
|
|
||||||
% Function: List
|
% Function: List
|
||||||
|
|
Loading…
Reference in New Issue
Block a user