From ff4f052bb169d479dd02f4fa268dbe15fdad329e Mon Sep 17 00:00:00 2001 From: Eric Cestari Date: Fri, 17 Sep 2010 14:23:34 +0200 Subject: [PATCH] [TECH-1151] Origin and Protocol parameters are configurable and set. --- src/web/ejabberd_http.erl | 28 +++++++++++++++++++++++++--- src/web/ejabberd_http.hrl | 4 +++- src/web/ejabberd_websocket.erl | 22 +++++++++++++++++++++- 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/src/web/ejabberd_http.erl b/src/web/ejabberd_http.erl index 9bfb3bd62..5e8b62c70 100644 --- a/src/web/ejabberd_http.erl +++ b/src/web/ejabberd_http.erl @@ -155,7 +155,7 @@ socket_type() -> raw. -send_text(State, none) -> +send_text(_State, none) -> exit(normal); send_text(State, Text) -> case catch (State#state.sockmod):send(State#state.socket, Text) of @@ -298,6 +298,11 @@ process_header(State, Data) -> add_header(Name, Value, State) -> [{Name, Value} | State#state.request_headers]. +-define(GETOPT(Param, Opts), + case lists:keysearch(Param, 1, Opts) of + {value, {Param, V}} -> V; + false -> undefined + end). %% @spec (SockMod, HostPort) -> {Host::string(), Port::integer(), TP} %% where %% SockMod = gen_tcp | tls @@ -322,17 +327,34 @@ get_transfer_protocol(SockMod, HostPort) -> %% XXX bard: search through request handlers looking for one that %% matches the requested URL path, and pass control to it. If none is %% found, answer with HTTP 404. + process([], _) -> ejabberd_web:error(not_found); process(Handlers, #ws{} = Ws)-> - [{HandlerPathPrefix, HandlerModule} | HandlersLeft] = Handlers, + [{HandlerPathPrefix, HandlerModule, HandlerOpts} | 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 = lists:nthtail(length(HandlerPathPrefix), Ws#ws.path), ejabberd_hooks:run(ws_debug, [{LocalPath, Ws}]), - ejabberd_websocket:connect(Ws#ws{local_path = LocalPath}, HandlerModule); + Protocol = case lists:keysearch(protocol, 1, HandlerOpts) of + {value, {protocol, P}} -> P; + false -> undefined + end, + Origins = case lists:keysearch(origins, 1, HandlerOpts) of + {value, {origins, O}} -> O; + false -> [] + end, + WS2 = Ws#ws{local_path = LocalPath, + protocol=Protocol, + acceptable_origins=Origins}, + case ejabberd_websocket:is_acceptable(WS2) of + true -> + ejabberd_websocket:connect(WS2, HandlerModule); + false -> + process(HandlersLeft, Ws) + end; false -> ?DEBUG("HandlersLeft : ~p ", [HandlersLeft]), process(HandlersLeft, Ws) diff --git a/src/web/ejabberd_http.hrl b/src/web/ejabberd_http.hrl index 5a163b799..c303ac8ae 100644 --- a/src/web/ejabberd_http.hrl +++ b/src/web/ejabberd_http.hrl @@ -48,5 +48,7 @@ port, path, % the websocket GET request path headers, % [{Tag, Val}] - local_path + local_path, + protocol, + acceptable_origins }). \ No newline at end of file diff --git a/src/web/ejabberd_websocket.erl b/src/web/ejabberd_websocket.erl index b579c057e..e7869508a 100644 --- a/src/web/ejabberd_websocket.erl +++ b/src/web/ejabberd_websocket.erl @@ -38,7 +38,7 @@ -module (ejabberd_websocket). -author('ecestari@process-one.net'). --compile(export_all). +-export([connect/2, check/2, is_acceptable/1]). -include("ejabberd.hrl"). -include("jlib.hrl"). -include("ejabberd_http.hrl"). @@ -49,6 +49,26 @@ check(_Path, Headers)-> % checks check_websockets(VsnSupported, Headers). +% Checks if websocket can be access by client +% If origins are set in configuration, check if it belongs +% If origins not set, access is open. +is_acceptable(#ws{origin=Origin, protocol=Protocol, + headers = Headers, acceptable_origins = Origins})-> + ClientProtocol = lists:keyfind("Sec-WebSocket-Protocol",1, Headers), + case {Origin == [] or lists:member(Origin, Origins), ClientProtocol, Protocol } of + {false, _, _} -> + ?DEBUG("client does not come from authorized origin", []), + false; + {_, false, _} -> + ?DEBUG("Client did not ask for protocol", []), + true; + {_, {_, P}, P} -> + ?DEBUG("Protocoles are matching", []), + true; + _ -> false + end. + + % Connect and handshake with Websocket. 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