aboutsummaryrefslogtreecommitdiff
path: root/src/ejabberd_http.erl
diff options
context:
space:
mode:
Diffstat (limited to 'src/ejabberd_http.erl')
-rw-r--r--src/ejabberd_http.erl235
1 files changed, 112 insertions, 123 deletions
diff --git a/src/ejabberd_http.erl b/src/ejabberd_http.erl
index 3c91c3c58..ce5c8aa09 100644
--- a/src/ejabberd_http.erl
+++ b/src/ejabberd_http.erl
@@ -345,48 +345,93 @@ 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, Request) ->
- %% Only the first element in the path prefix is checked
- [{HandlerPathPrefix, HandlerModule} | HandlersLeft] =
- Handlers,
- case lists:prefix(HandlerPathPrefix,
- Request#request.path)
- or (HandlerPathPrefix == Request#request.path)
- of
- true ->
- ?DEBUG("~p matches ~p",
- [Request#request.path, HandlerPathPrefix]),
- LocalPath = lists:nthtail(length(HandlerPathPrefix),
- Request#request.path),
- ?DEBUG("~p", [Request#request.headers]),
- R = HandlerModule:process(LocalPath, Request),
- ejabberd_hooks:run(http_request_debug,
- [{LocalPath, Request}]),
- R;
- false -> process(HandlersLeft, Request)
+
+process([], _, _, _, _) -> ejabberd_web:error(not_found);
+process(Handlers, Request, Socket, SockMod, Trail) ->
+ {HandlerPathPrefix, HandlerModule, HandlerOpts, HandlersLeft} =
+ case Handlers of
+ [{Pfx, Mod} | Tail] ->
+ {Pfx, Mod, [], Tail};
+ [{Pfx, Mod, Opts} | Tail] ->
+ {Pfx, Mod, Opts, Tail}
+ end,
+
+ case (lists:prefix(HandlerPathPrefix, Request#request.path) or
+ (HandlerPathPrefix==Request#request.path)) of
+ true ->
+ ?DEBUG("~p matches ~p", [Request#request.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), Request#request.path),
+ R = try
+ HandlerModule:socket_handoff(
+ LocalPath, Request, Socket, SockMod, Trail, HandlerOpts)
+ catch error:undef ->
+ HandlerModule:process(LocalPath, Request)
+ end,
+ ejabberd_hooks:run(http_request_debug, [{LocalPath, Request}]),
+ R;
+ false ->
+ process(HandlersLeft, Request, Socket, SockMod, Trail)
end.
-process_request(#state{request_method = Method, options = Options,
- request_path = {abs_path, Path}, request_auth = Auth,
- request_lang = Lang, request_handlers = RequestHandlers,
- request_host = Host, request_port = Port,
- request_tp = TP, request_headers = RequestHeaders,
- sockmod = SockMod,
- socket = Socket} = State)
- when Method=:='GET' orelse Method=:='HEAD' orelse Method=:='DELETE' orelse Method=:='OPTIONS' ->
- case (catch url_decode_q_split(Path)) of
- {'EXIT', _} ->
+extract_path_query(#state{request_method = Method,
+ request_path = {abs_path, Path}})
+ when Method =:= 'GET' orelse
+ Method =:= 'HEAD' orelse
+ Method =:= 'DELETE' orelse Method =:= 'OPTIONS' ->
+ case catch url_decode_q_split(Path) of
+ {'EXIT', _} -> false;
+ {NPath, Query} ->
+ LPath = normalize_path([NPE
+ || NPE <- str:tokens(path_decode(NPath), <<"/">>)]),
+ LQuery = case catch parse_urlencoded(Query) of
+ {'EXIT', _Reason} -> [];
+ LQ -> LQ
+ end,
+ {LPath, LQuery, <<"">>}
+ end;
+extract_path_query(#state{request_method = Method,
+ request_path = {abs_path, Path},
+ request_content_length = Len,
+ sockmod = _SockMod,
+ socket = _Socket} = State)
+ when (Method =:= 'POST' orelse Method =:= 'PUT') andalso
+ is_integer(Len) ->
+ Data = recv_data(State, Len),
+ ?DEBUG("client data: ~p~n", [Data]),
+ case catch url_decode_q_split(Path) of
+ {'EXIT', _} -> false;
+ {NPath, _Query} ->
+ LPath = normalize_path([NPE
+ || NPE <- str:tokens(path_decode(NPath), <<"/">>)]),
+ LQuery = case catch parse_urlencoded(Data) of
+ {'EXIT', _Reason} -> [];
+ LQ -> LQ
+ end,
+ {LPath, LQuery, Data}
+ end;
+extract_path_query(_State) ->
+ false.
+
+process_request(#state{request_method = Method,
+ request_auth = Auth,
+ request_lang = Lang,
+ sockmod = SockMod,
+ socket = Socket,
+ options = Options,
+ request_host = Host,
+ request_port = Port,
+ request_tp = TP,
+ request_headers = RequestHeaders,
+ request_handlers = RequestHandlers,
+ trail = Trail} = State) ->
+ case extract_path_query(State) of
+ false ->
make_bad_request(State);
- {NPath, Query} ->
- LPath = normalize_path([NPE || NPE <- str:tokens(path_decode(NPath), <<"/">>)]),
- LQuery = case (catch parse_urlencoded(Query)) of
- {'EXIT', _Reason} ->
- [];
- LQ ->
- LQ
- end,
+ {LPath, LQuery, Data} ->
{ok, IPHere} =
case SockMod of
gen_tcp ->
@@ -396,92 +441,36 @@ process_request(#state{request_method = Method, options = Options,
end,
XFF = proplists:get_value('X-Forwarded-For', RequestHeaders, []),
IP = analyze_ip_xff(IPHere, XFF, Host),
- Request = #request{method = Method,
- path = LPath,
+ Request = #request{method = Method,
+ path = LPath,
+ q = LQuery,
+ auth = Auth,
+ data = Data,
+ lang = Lang,
+ host = Host,
+ port = Port,
+ tp = TP,
opts = Options,
- q = LQuery,
- auth = Auth,
- lang = Lang,
- host = Host,
- port = Port,
- tp = TP,
- headers = RequestHeaders,
- ip = IP},
- %% XXX bard: This previously passed control to
- %% ejabberd_web:process_get, now passes it to a local
- %% procedure (process) that handles dispatching based on
- %% URL path prefix.
- case process(RequestHandlers, Request) of
- El when element(1, El) == xmlel ->
- make_xhtml_output(State, 200, [], El);
- {Status, Headers, El} when
- element(1, El) == xmlel ->
- 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)
+ headers = RequestHeaders,
+ ip = IP},
+ case process(RequestHandlers, Request, Socket, SockMod, Trail) of
+ El when is_record(El, xmlel) ->
+ make_xhtml_output(State, 200, [], El);
+ {Status, Headers, El}
+ when is_record(El, xmlel) ->
+ make_xhtml_output(State, Status, Headers, El);
+ Output when is_binary(Output) or is_list(Output) ->
+ make_text_output(State, 200, [], Output);
+ {Status, Headers, Output}
+ when is_binary(Output) or is_list(Output) ->
+ make_text_output(State, Status, Headers, Output);
+ {Status, Reason, Headers, Output}
+ when is_binary(Output) or is_list(Output) ->
+ make_text_output(State, Status, Reason, Headers, Output);
+ _ ->
+ none
end
- end;
-process_request(#state{request_method = Method, options = Options,
- request_path = {abs_path, Path}, request_auth = Auth,
- request_content_length = Len, request_lang = Lang,
- sockmod = SockMod, socket = Socket, request_host = Host,
- request_port = Port, request_tp = TP,
- request_headers = RequestHeaders,
- request_handlers = RequestHandlers} =
- State)
- when (Method =:= 'POST' orelse Method =:= 'PUT') andalso
- is_integer(Len) ->
- {ok, IPHere} = case SockMod of
- gen_tcp -> inet:peername(Socket);
- _ -> SockMod:peername(Socket)
- end,
- XFF = proplists:get_value('X-Forwarded-For',
- RequestHeaders, []),
- IP = analyze_ip_xff(IPHere, XFF, Host),
- case SockMod of
- gen_tcp -> inet:setopts(Socket, [{packet, 0}]);
- _ -> ok
- end,
- Data = recv_data(State, Len),
- ?DEBUG("client data: ~p~n", [Data]),
- case (catch url_decode_q_split(Path)) of
- {'EXIT', _} ->
- make_bad_request(State);
- {NPath, _Query} ->
- LPath = normalize_path([NPE || NPE <- str:tokens(path_decode(NPath), <<"/">>)]),
- LQuery = case (catch parse_urlencoded(Data)) of
- {'EXIT', _Reason} ->
- [];
- LQ ->
- LQ
- end,
- Request = #request{method = Method,
- path = LPath,
- q = LQuery,
- opts = Options,
- auth = Auth,
- data = Data,
- lang = Lang,
- host = Host,
- port = Port,
- tp = TP,
- headers = RequestHeaders,
- ip = IP},
- case process(RequestHandlers, Request) of
- El when element(1, El) == xmlel ->
- make_xhtml_output(State, 200, [], El);
- {Status, Headers, El} when
- element(1, El) == xmlel ->
- 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;
-process_request(State) -> make_bad_request(State).
+ end.
make_bad_request(State) ->
%% Support for X-Forwarded-From