24
1
mirror of https://github.com/processone/ejabberd.git synced 2024-07-19 00:11:01 +02:00

[TECH-1151] websockets are properly detected.

This commit is contained in:
Eric Cestari 2010-09-10 15:04:19 +02:00
parent 77136bccdf
commit cccbf7de12
2 changed files with 33 additions and 26 deletions

View File

@ -378,17 +378,24 @@ process_request(#state{request_method = Method,
%% ejabberd_web:process_get, now passes it to a local %% ejabberd_web:process_get, now passes it to a local
%% procedure (process) that handles dispatching based on %% procedure (process) that handles dispatching based on
%% URL path prefix. %% URL path prefix.
case process(RequestHandlers, Request) of case ejabberd_websocket:check(Path, RequestHeaders) of
El when element(1, El) == xmlelement -> {true, _VSN} ->
make_xhtml_output(State, 200, [], El); ?DEBUG("It is a websocket version : ~p",[_VSN]);
{Status, Headers, El} when
element(1, El) == xmlelement -> false ->
make_xhtml_output(State, Status, Headers, El); ?DEBUG("It is not a websocket.",[]),
Output when is_list(Output) or is_binary(Output) -> case process(RequestHandlers, Request) of
make_text_output(State, 200, [], Output); El when element(1, El) == xmlelement ->
{Status, Headers, Output} when is_list(Output) or is_binary(Output) -> make_xhtml_output(State, 200, [], El);
make_text_output(State, Status, Headers, Output) {Status, Headers, El} when
end element(1, El) == xmlelement ->
make_xhtml_output(State, Status, Headers, El);
Output when is_list(Output) or is_binary(Output) ->
make_text_output(State, 200, [], Output);
{Status, Headers, Output} when is_list(Output) or is_binary(Output) ->
make_text_output(State, Status, Headers, Output)
end
end
end; end;
process_request(#state{request_method = Method, process_request(#state{request_method = Method,

View File

@ -39,11 +39,11 @@
-module (ejabberd_websocket). -module (ejabberd_websocket).
-author('ecestari@process-one.net'). -author('ecestari@process-one.net').
-compile(export_all). -compile(export_all).
-include("ejabberd.hrl").
-include("jlib.hrl").
-include ("ejabberd_http.hrl"). -include ("ejabberd_http.hrl").
-include ("ejabberd.hrl").
check(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]),
% set supported websocket protocols, order does matter % set supported websocket protocols, order does matter
VsnSupported = [{'draft-hixie', 76}, {'draft-hixie', 68}], VsnSupported = [{'draft-hixie', 76}, {'draft-hixie', 68}],
@ -63,8 +63,8 @@ check_websocket({'draft-hixie', 76} = Vsn, Headers) ->
?DEBUG("testing for websocket protocol ~p", [Vsn]), ?DEBUG("testing for websocket protocol ~p", [Vsn]),
% set required headers % set required headers
RequiredHeaders = [ RequiredHeaders = [
{'Upgrade', "WebSocket"}, {'Connection', "Upgrade"}, {'Host', ignore}, {'Origin', ignore}, {'Upgrade', "WebSocket"}, {'Connection', "Upgrade"}, {'Host', ignore}, {"Origin", ignore},
{'Sec-WebSocket-Key1', ignore}, {'Sec-WebSocket-Key2', ignore} {"Sec-WebSocket-Key1", ignore}, {"Sec-WebSocket-Key2", ignore}
], ],
% check for headers existance % check for headers existance
case check_headers(Headers, RequiredHeaders) of case check_headers(Headers, RequiredHeaders) of
@ -72,20 +72,20 @@ check_websocket({'draft-hixie', 76} = Vsn, Headers) ->
% return % return
{true, Vsn}; {true, Vsn};
_RemainingHeaders -> _RemainingHeaders ->
?LOG_DEBUG("not protocol ~p, remaining headers: ~p", [Vsn, _RemainingHeaders]), ?DEBUG("not protocol ~p, remaining headers: ~p", [Vsn, _RemainingHeaders]),
false false
end; end;
check_websocket({'draft-hixie', 68} = Vsn, Headers) -> check_websocket({'draft-hixie', 68} = Vsn, Headers) ->
?DEBUG("testing for websocket protocol ~p", [Vsn]), ?DEBUG("testing for websocket protocol ~p", [Vsn]),
% set required headers % set required headers
RequiredHeaders = [ RequiredHeaders = [
{'Upgrade', "WebSocket"}, {'Connection', "Upgrade"}, {'Host', ignore}, {'Origin', ignore} {'Upgrade', "WebSocket"}, {'Connection', "Upgrade"}, {'Host', ignore}, {"Origin", ignore}
], ],
% check for headers existance % check for headers existance
case check_headers(Headers, RequiredHeaders) of case check_headers(Headers, RequiredHeaders) of
true -> {true, Vsn}; true -> {true, Vsn};
_RemainingHeaders -> _RemainingHeaders ->
?LOG_DEBUG("not protocol ~p, remaining headers: ~p", [Vsn, _RemainingHeaders]), ?DEBUG("not protocol ~p, remaining headers: ~p", [Vsn, _RemainingHeaders]),
false false
end; end;
check_websocket(_Vsn, _Headers) -> false. % not implemented check_websocket(_Vsn, _Headers) -> false. % not implemented
@ -97,7 +97,7 @@ check_headers(Headers, RequiredHeaders) ->
% see if the required Tag is in the Headers % see if the required Tag is in the Headers
case lists:keysearch(Tag, 1, Headers) of case lists:keysearch(Tag, 1, Headers) of
false -> true; % header not found, keep in list false -> true; % header not found, keep in list
HVal -> {value, {Tag, HVal}} ->
case Val of case Val of
ignore -> false; % ignore value -> ok, remove from list ignore -> false; % ignore value -> ok, remove from list
HVal -> false; % expected val -> ok, remove from list HVal -> false; % expected val -> ok, remove from list
@ -112,13 +112,13 @@ check_headers(Headers, RequiredHeaders) ->
% Function: List % Function: List
% Description: Builds the server handshake response. % Description: Builds the server handshake response.
handshake({'draft-hixie', 76}, #req{socket = Sock, socket_mode = SocketMode}, Headers, {Path, Origin, Host}) -> handshake({'draft-hixie', 76}, Sock,SocketMod, Headers, {Path, Origin, Host}) ->
% build data % build data
Key1 = lists:keysearch('Sec-WebSocket-Key1',1, Headers), Key1 = lists:keysearch("Sec-WebSocket-Key1",1, Headers),
Key2 = lists:keysearch('Sec-WebSocket-Key2',1, Headers), Key2 = lists:keysearch("Sec-WebSocket-Key2",1, Headers),
% handshake needs body of the request, still need to read it [TODO: default recv timeout hard set, will be exported when WS protocol is final] % handshake needs body of the request, still need to read it [TODO: default recv timeout hard set, will be exported when WS protocol is final]
misultin_socket:setopts(Sock, [{packet, raw}, {active, false}], SocketMode), SocketMod:setopts(Sock, [{packet, raw}, {active, false}]),
Body = case misultin_socket:recv(Sock, 8, 30*1000, SocketMode) of Body = case SocketMod:recv(Sock, 8, 30*1000) of
{ok, Bin} -> Bin; {ok, Bin} -> Bin;
{error, timeout} -> {error, timeout} ->
?WARNING_MSG("timeout in reading websocket body", []), ?WARNING_MSG("timeout in reading websocket body", []),
@ -136,7 +136,7 @@ handshake({'draft-hixie', 76}, #req{socket = Sock, socket_mode = SocketMode}, He
"Sec-WebSocket-Location: ws://", lists:concat([Host, Path]), "\r\n\r\n", "Sec-WebSocket-Location: ws://", lists:concat([Host, 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}, _Req, _Headers, {Path, Origin, Host}) -> handshake({'draft-hixie', 68}, _Sock,_SocketMod, _Headers, {Path, Origin, Host}) ->
% 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",