Return-Path: X-Original-To: apmail-couchdb-commits-archive@www.apache.org Delivered-To: apmail-couchdb-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id DF36C18FF5 for ; Tue, 24 Nov 2015 20:16:18 +0000 (UTC) Received: (qmail 22962 invoked by uid 500); 24 Nov 2015 20:16:18 -0000 Delivered-To: apmail-couchdb-commits-archive@couchdb.apache.org Received: (qmail 22889 invoked by uid 500); 24 Nov 2015 20:16:18 -0000 Mailing-List: contact commits-help@couchdb.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@couchdb.apache.org Delivered-To: mailing list commits@couchdb.apache.org Received: (qmail 22867 invoked by uid 99); 24 Nov 2015 20:16:18 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 24 Nov 2015 20:16:18 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 97B0AE009E; Tue, 24 Nov 2015 20:16:18 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: kxepal@apache.org To: commits@couchdb.apache.org Date: Tue, 24 Nov 2015 20:16:18 -0000 Message-Id: <73557111301f4b958fcda4f90cb81cc7@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [1/4] chttpd commit: updated refs/heads/master to 7dcf127 Repository: couchdb-chttpd Updated Branches: refs/heads/master ddba20778 -> 7dcf1279b Handle errors from before_request/after_request This refactoring fixes the handling of errors from before_request. Unify how we deal with errors among before_request and handle_request. Project: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/repo Commit: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/commit/6a1858f8 Tree: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/tree/6a1858f8 Diff: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/diff/6a1858f8 Branch: refs/heads/master Commit: 6a1858f8b2604c4af96b7ca4d423ebacd2f98603 Parents: ddba207 Author: ILYA Khlopotov Authored: Wed Nov 18 08:25:39 2015 -0800 Committer: ILYA Khlopotov Committed: Wed Nov 18 08:32:50 2015 -0800 ---------------------------------------------------------------------- src/chttpd.erl | 138 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 84 insertions(+), 54 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/6a1858f8/src/chttpd.erl ---------------------------------------------------------------------- diff --git a/src/chttpd.erl b/src/chttpd.erl index d3bc4e7..0e93728 100644 --- a/src/chttpd.erl +++ b/src/chttpd.erl @@ -157,11 +157,6 @@ handle_request_int(MochiReq) -> {"/" ++ Path, _, _} = mochiweb_util:urlsplit_path(RawUri), Peer = MochiReq:get(peer), - LogForClosedSocket = io_lib:format("mochiweb_recv_error for ~s - ~p ~s", [ - Peer, - MochiReq:get(method), - RawUri - ]), Method1 = case MochiReq:get(method) of @@ -209,21 +204,58 @@ handle_request_int(MochiReq) -> || Part <- string:tokens(Path, "/")] }, - {ok, HttpReq} = chttpd_plugin:before_request(HttpReq0), + % put small token on heap to keep requests synced to backend calls + erlang:put(nonce, Nonce), + + % suppress duplicate log + erlang:put(dont_log_request, true), + + Result0 = case before_request(HttpReq0) of + {ok, HttpReq1} -> + process_request(HttpReq1); + {error, Response} -> + {HttpReq0, Response} + end, + + {HttpReq3, HttpResp0} = result(Result0, HttpReq0), + + case after_request(HttpReq3, HttpResp0) of + #httpd_resp{status = ok, response = Resp} -> + {ok, Resp}; + #httpd_resp{status = aborted, reason = Reason} -> + couch_log:error("Response abnormally terminated: ~p", [Reason]), + exit(normal) + end. + +before_request(HttpReq) -> + try + chttpd_plugin:before_request(HttpReq) + catch Tag:Error -> + {error, catch_error(HttpReq, Tag, Error)} + end. + +after_request(HttpReq, HttpResp0) -> + {ok, HttpResp1} = + try + chttpd_plugin:after_request(HttpReq, HttpResp0) + catch _Tag:Error -> + Stack = erlang:get_stacktrace(), + send_error(HttpReq, {Error, nil, Stack}), + {ok, HttpResp0#httpd_resp{status = aborted}} + end, + HttpResp2 = update_stats(HttpReq, HttpResp1), + maybe_log(HttpReq, HttpResp2), + HttpResp2. +process_request(#httpd{mochi_req = MochiReq} = HttpReq) -> HandlerKey = case HttpReq#httpd.path_parts of [] -> <<>>; [Key|_] -> ?l2b(quote(Key)) end, - % put small token on heap to keep requests synced to backend calls - erlang:put(nonce, Nonce), - - % suppress duplicate log - erlang:put(dont_log_request, true), + RawUri = MochiReq:get(raw_path), - Result0 = try couch_httpd:validate_host(HttpReq), check_request_uri_length(RawUri), @@ -242,49 +274,47 @@ handle_request_int(MochiReq) -> Response -> Response end - catch - throw:{http_head_abort, Resp0} -> - {ok, Resp0}; - throw:{http_abort, Resp0, Reason0} -> - {aborted, Resp0, Reason0}; - throw:{invalid_json, _} -> - send_error(HttpReq, {bad_request, "invalid UTF-8 JSON"}); - exit:{mochiweb_recv_error, E} -> - couch_log:notice(LogForClosedSocket ++ " - ~p", [E]), - exit(normal); - exit:{uri_too_long, _} -> - send_error(HttpReq, request_uri_too_long); - exit:{body_too_large, _} -> - send_error(HttpReq, request_entity_too_large); - throw:Error -> - send_error(HttpReq, Error); - error:database_does_not_exist -> - send_error(HttpReq, database_does_not_exist); - Tag:Error -> - Stack = erlang:get_stacktrace(), - % TODO improve logging and metrics collection for client disconnects - case {Tag, Error, Stack} of - {exit, normal, [{mochiweb_request, send, _, _} | _]} -> - exit(normal); % Client disconnect (R15+) - {exit, normal, [{mochiweb_request, send, _} | _]} -> - exit(normal); % Client disconnect (R14) - _Else -> - send_error(HttpReq, {Error, nil, Stack}) - end - end, - - {HttpReq1, HttpResp0} = result(Result0, HttpReq), - {ok, HttpResp1} = chttpd_plugin:after_request(HttpReq1, HttpResp0), - - HttpResp2 = update_stats(HttpReq1, HttpResp1), - maybe_log(HttpReq1, HttpResp2), + catch Tag:Error -> + catch_error(HttpReq, Tag, Error) + end. - case HttpResp2 of - #httpd_resp{status = ok, response = Resp} -> - {ok, Resp}; - #httpd_resp{status = aborted, reason = Reason} -> - couch_log:error("Response abnormally terminated: ~p", [Reason]), - exit(normal) +catch_error(_HttpReq, throw, {http_head_abort, Resp}) -> + {ok, Resp}; +catch_error(_HttpReq, throw, {http_abort, Resp, Reason}) -> + {aborted, Resp, Reason}; +catch_error(HttpReq, throw, {invalid_json, _}) -> + send_error(HttpReq, {bad_request, "invalid UTF-8 JSON"}); +catch_error(HttpReq, exit, {mochiweb_recv_error, E}) -> + #httpd{ + mochi_req = MochiReq, + peer = Peer, + original_method = Method + } = HttpReq, + LogForClosedSocket = io_lib:format("mochiweb_recv_error for ~s - ~p ~s", [ + Peer, + Method, + MochiReq:get(raw_path) + ]), + couch_log:notice(LogForClosedSocket ++ " - ~p", [E]), + exit(normal); +catch_error(HttpReq, exit, {uri_too_long, _}) -> + send_error(HttpReq, request_uri_too_long); +catch_error(HttpReq, exit, {body_too_large, _}) -> + send_error(HttpReq, request_entity_too_large); +catch_error(HttpReq, throw, Error) -> + send_error(HttpReq, Error); +catch_error(HttpReq, error, database_does_not_exist) -> + send_error(HttpReq, database_does_not_exist); +catch_error(HttpReq, Tag, Error) -> + Stack = erlang:get_stacktrace(), + % TODO improve logging and metrics collection for client disconnects + case {Tag, Error, Stack} of + {exit, normal, [{mochiweb_request, send, _, _} | _]} -> + exit(normal); % Client disconnect (R15+) + {exit, normal, [{mochiweb_request, send, _} | _]} -> + exit(normal); % Client disconnect (R14) + _Else -> + send_error(HttpReq, {Error, nil, Stack}) end. result({#httpd{} = Req, Result}, _) ->