You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by rn...@apache.org on 2015/08/12 17:54:25 UTC

[01/11] chttpd commit: updated refs/heads/master to 238b8c4

Repository: couchdb-chttpd
Updated Branches:
  refs/heads/master a66b901e6 -> 238b8c482


Introduce `chttpd_auth:authenticate` hook


Project: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/commit/90f1aa75
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/tree/90f1aa75
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/diff/90f1aa75

Branch: refs/heads/master
Commit: 90f1aa751147f35f823cb33bb53495788c497e05
Parents: a66b901
Author: ILYA Khlopotov <ii...@ca.ibm.com>
Authored: Wed Jul 29 09:40:23 2015 -0700
Committer: ILYA Khlopotov <ii...@ca.ibm.com>
Committed: Tue Aug 11 08:27:51 2015 -0700

----------------------------------------------------------------------
 src/chttpd.erl      | 44 +++++++++++++++++++++--------------------
 src/chttpd_auth.erl | 51 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/chttpd_sup.erl  | 10 +++++++++-
 3 files changed, 83 insertions(+), 22 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/90f1aa75/src/chttpd.erl
----------------------------------------------------------------------
diff --git a/src/chttpd.erl b/src/chttpd.erl
index 22d0656..b6b30de 100644
--- a/src/chttpd.erl
+++ b/src/chttpd.erl
@@ -27,6 +27,8 @@
     send_method_not_allowed/2, send_error/2, send_error/4, send_redirect/2,
     send_chunked_error/2, send_json/2,send_json/3,send_json/4]).
 
+-export([authenticate_request/3]).
+
 -export([start_delayed_json_response/2, start_delayed_json_response/3,
     start_delayed_json_response/4,
     start_delayed_chunked_response/3, start_delayed_chunked_response/4,
@@ -143,11 +145,6 @@ handle_request_int(MochiReq) ->
         ok = mochiweb_socket:setopts(MochiReq:get(socket), SocketOpts)
     end,
 
-    AuthenticationFuns = [
-        fun chttpd_auth:cookie_authentication_handler/1,
-        fun chttpd_auth:default_authentication_handler/1
-    ],
-
     % for the path, use the raw path with the query string and fragment
     % removed, but URL quoting left intact
     RawUri = MochiReq:get(raw_path),
@@ -215,7 +212,7 @@ handle_request_int(MochiReq) ->
         check_request_uri_length(RawUri),
         case chttpd_cors:maybe_handle_preflight_request(HttpReq) of
         not_preflight ->
-            case authenticate_request(HttpReq, AuthenticationFuns) of
+            case chttpd_auth:authenticate(HttpReq, fun authenticate_request/1) of
             #httpd{} = Req ->
                 HandlerFun = chttpd_handlers:url_handler(
                     HandlerKey, fun chttpd_db:handle_request/1),
@@ -346,28 +343,33 @@ make_uri(Req, Raw) ->
     {[{<<"url">>,Url}, {<<"headers">>,{Headers}}]}.
 %%% end hack
 
+authenticate_request(Req) ->
+    AuthenticationFuns = [
+        {<<"cookie">>, fun chttpd_auth:cookie_authentication_handler/1},
+        {<<"default">>, fun chttpd_auth:default_authentication_handler/1},
+        {<<"local">>, fun chttpd_auth:party_mode_handler/1} %% should be last
+    ],
+    authenticate_request(Req, chttpd_auth_cache, AuthenticationFuns).
+
+authenticate_request(#httpd{} = Req0, AuthModule, AuthFuns) ->
+    Req = Req0#httpd{
+        auth_module = AuthModule,
+        authentication_handlers = AuthFuns},
+    authenticate_request(Req, AuthFuns).
 
 % Try authentication handlers in order until one returns a result
 authenticate_request(#httpd{user_ctx=#user_ctx{}} = Req, _AuthFuns) ->
     Req;
-authenticate_request(#httpd{} = Req, [AuthFun|Rest]) ->
-    authenticate_request(AuthFun(Req), Rest);
-authenticate_request(#httpd{} = Req, []) ->
-    case config:get("chttpd", "require_valid_user", "false") of
-    "true" ->
-        throw({unauthorized, <<"Authentication required.">>});
-    "false" ->
-        case config:get("admins") of
-        [] ->
-            Ctx = #user_ctx{roles=[<<"_reader">>, <<"_writer">>, <<"_admin">>]},
-            Req#httpd{user_ctx = Ctx};
-        _ ->
-            Req#httpd{user_ctx=#user_ctx{}}
-        end
-    end;
+authenticate_request(#httpd{} = Req, [{Name, AuthFun}|Rest]) ->
+    authenticate_request(maybe_set_handler(AuthFun(Req), Name), Rest);
 authenticate_request(Response, _AuthFuns) ->
     Response.
 
+maybe_set_handler(#httpd{user_ctx=#user_ctx{} = UserCtx} = Req, Name) ->
+    Req#httpd{user_ctx = UserCtx#user_ctx{handler = Name}};
+maybe_set_handler(Else, _) ->
+    Else.
+
 increment_method_stats(Method) ->
     couch_stats:increment_counter([couchdb, httpd_request_methods, Method]).
 

http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/90f1aa75/src/chttpd_auth.erl
----------------------------------------------------------------------
diff --git a/src/chttpd_auth.erl b/src/chttpd_auth.erl
index 1046538..7a45399 100644
--- a/src/chttpd_auth.erl
+++ b/src/chttpd_auth.erl
@@ -12,15 +12,66 @@
 
 -module(chttpd_auth).
 
+-export([authenticate/2]).
+
 -export([default_authentication_handler/1]).
 -export([cookie_authentication_handler/1]).
+-export([party_mode_handler/1]).
+
 -export([handle_session_req/1]).
 
+-include_lib("couch/include/couch_db.hrl").
+
+-define(SERVICE_ID, chttpd_auth).
+
+
+%% ------------------------------------------------------------------
+%% API Function Definitions
+%% ------------------------------------------------------------------
+
+authenticate(HttpReq, Default) ->
+    maybe_handle(authenticate, [HttpReq], Default).
+
+
+%% ------------------------------------------------------------------
+%% Default callbacks
+%% ------------------------------------------------------------------
+
 default_authentication_handler(Req) ->
     couch_httpd_auth:default_authentication_handler(Req, chttpd_auth_cache).
 
 cookie_authentication_handler(Req) ->
     couch_httpd_auth:cookie_authentication_handler(Req, chttpd_auth_cache).
 
+party_mode_handler(Req) ->
+    case config:get("chttpd", "require_valid_user", "false") of
+    "true" ->
+        throw({unauthorized, <<"Authentication required.">>});
+    "false" ->
+        case config:get("admins") of
+        [] ->
+            Ctx = #user_ctx{roles=[<<"_reader">>, <<"_writer">>, <<"_admin">>]},
+            Req#httpd{user_ctx = Ctx};
+        _ ->
+            Req#httpd{user_ctx=#user_ctx{}}
+        end
+    end.
+
 handle_session_req(Req) ->
     couch_httpd_auth:handle_session_req(Req, chttpd_auth_cache).
+
+
+%% ------------------------------------------------------------------
+%% Internal Function Definitions
+%% ------------------------------------------------------------------
+
+maybe_handle(Func, Args, Default) ->
+    Handle = couch_epi:get_handle(?SERVICE_ID),
+    case couch_epi:apply(Handle, ?SERVICE_ID, Func, Args, [ignore_providers]) of
+        [] when is_function(Default) ->
+            apply(Default, Args);
+        [] ->
+            Default;
+        [Result] ->
+            Result
+    end.

http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/90f1aa75/src/chttpd_sup.erl
----------------------------------------------------------------------
diff --git a/src/chttpd_sup.erl b/src/chttpd_sup.erl
index a4851e2..62d00eb 100644
--- a/src/chttpd_sup.erl
+++ b/src/chttpd_sup.erl
@@ -26,7 +26,7 @@ init([]) ->
     chttpd_config_listener:subscribe(),
     {ok, {{one_for_one, 3, 10}, [
         ?CHILD(chttpd, worker),
-        ?CHILD(chttpd_auth_cache, worker),
+        ?CHILD(auth_cache_handler(), worker),
         chttpd_handlers:provider(chttpd, chttpd_httpd_handlers),
         {chttpd_auth_cache_lru,
 	 {ets_lru, start_link, [chttpd_auth_cache_lru, lru_opts()]},
@@ -52,3 +52,11 @@ lru_opts() ->
         _ ->
             []
     end.
+
+auth_cache_handler() ->
+    case application:get_env(chttpd, auth_cache) of
+        {ok, Module} ->
+            Module;
+        _ ->
+            chttpd_auth_cache
+    end.


[02/11] chttpd commit: updated refs/heads/master to 238b8c4

Posted by rn...@apache.org.
Use '?ADMIN_USER' for admin party


Project: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/commit/f42f96c8
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/tree/f42f96c8
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/diff/f42f96c8

Branch: refs/heads/master
Commit: f42f96c897a3ad22f40e2c5bf35c737c4fd3fa92
Parents: 90f1aa7
Author: ILYA Khlopotov <ii...@ca.ibm.com>
Authored: Wed Aug 5 14:31:31 2015 -0700
Committer: ILYA Khlopotov <ii...@ca.ibm.com>
Committed: Tue Aug 11 08:44:37 2015 -0700

----------------------------------------------------------------------
 src/chttpd_auth.erl | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/f42f96c8/src/chttpd_auth.erl
----------------------------------------------------------------------
diff --git a/src/chttpd_auth.erl b/src/chttpd_auth.erl
index 7a45399..6683892 100644
--- a/src/chttpd_auth.erl
+++ b/src/chttpd_auth.erl
@@ -50,8 +50,7 @@ party_mode_handler(Req) ->
     "false" ->
         case config:get("admins") of
         [] ->
-            Ctx = #user_ctx{roles=[<<"_reader">>, <<"_writer">>, <<"_admin">>]},
-            Req#httpd{user_ctx = Ctx};
+            Req#httpd{user_ctx = ?ADMIN_USER};
         _ ->
             Req#httpd{user_ctx=#user_ctx{}}
         end


[04/11] chttpd commit: updated refs/heads/master to 238b8c4

Posted by rn...@apache.org.
Add `chttpd_auth:authorize/2` hook


Project: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/commit/cf58b04e
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/tree/cf58b04e
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/diff/cf58b04e

Branch: refs/heads/master
Commit: cf58b04e96fde0ba012a2aa339f9dc322c2d2f4e
Parents: 8d0fe1c
Author: ILYA Khlopotov <ii...@ca.ibm.com>
Authored: Wed Jul 29 10:15:50 2015 -0700
Committer: ILYA Khlopotov <ii...@ca.ibm.com>
Committed: Tue Aug 11 09:14:28 2015 -0700

----------------------------------------------------------------------
 src/chttpd.erl      | 4 +++-
 src/chttpd_auth.erl | 4 ++++
 2 files changed, 7 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/cf58b04e/src/chttpd.erl
----------------------------------------------------------------------
diff --git a/src/chttpd.erl b/src/chttpd.erl
index d1e07e9..215f509 100644
--- a/src/chttpd.erl
+++ b/src/chttpd.erl
@@ -220,7 +220,9 @@ handle_request_int(MochiReq) ->
             #httpd{} = Req ->
                 HandlerFun = chttpd_handlers:url_handler(
                     HandlerKey, fun chttpd_db:handle_request/1),
-                HandlerFun(chttpd_auth_request:authorize_request(possibly_hack(Req)));
+                AuthorizedReq = chttpd_auth:authorize(possibly_hack(Req),
+                    fun chttpd_auth_request:authorize_request/1),
+                HandlerFun(AuthorizedReq);
             Response ->
                 Response
             end;

http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/cf58b04e/src/chttpd_auth.erl
----------------------------------------------------------------------
diff --git a/src/chttpd_auth.erl b/src/chttpd_auth.erl
index 6683892..35a4bd5 100644
--- a/src/chttpd_auth.erl
+++ b/src/chttpd_auth.erl
@@ -13,6 +13,7 @@
 -module(chttpd_auth).
 
 -export([authenticate/2]).
+-export([authorize/2]).
 
 -export([default_authentication_handler/1]).
 -export([cookie_authentication_handler/1]).
@@ -32,6 +33,9 @@
 authenticate(HttpReq, Default) ->
     maybe_handle(authenticate, [HttpReq], Default).
 
+authorize(HttpReq, Default) ->
+    maybe_handle(authorize, [HttpReq], Default).
+
 
 %% ------------------------------------------------------------------
 %% Default callbacks


[09/11] chttpd commit: updated refs/heads/master to 238b8c4

Posted by rn...@apache.org.
Use `#httpd.qs` field


Project: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/commit/4ba06e0c
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/tree/4ba06e0c
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/diff/4ba06e0c

Branch: refs/heads/master
Commit: 4ba06e0c290fef1f3324271db9f93f0ca3dee5e6
Parents: b5d65ea
Author: ILYA Khlopotov <ii...@ca.ibm.com>
Authored: Fri Jul 31 06:27:20 2015 -0700
Committer: ILYA Khlopotov <ii...@ca.ibm.com>
Committed: Tue Aug 11 09:14:29 2015 -0700

----------------------------------------------------------------------
 src/chttpd.erl | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/4ba06e0c/src/chttpd.erl
----------------------------------------------------------------------
diff --git a/src/chttpd.erl b/src/chttpd.erl
index ec15033..749f550 100644
--- a/src/chttpd.erl
+++ b/src/chttpd.erl
@@ -480,8 +480,10 @@ qs_json_value(Req, Key, Default) ->
             ?JSON_DECODE(Result)
     end.
 
-qs(#httpd{mochi_req=MochiReq}) ->
-    MochiReq:parse_qs().
+qs(#httpd{mochi_req = MochiReq, qs = undefined}) ->
+    MochiReq:parse_qs();
+qs(#httpd{qs = QS}) ->
+    QS.
 
 path(#httpd{mochi_req=MochiReq}) ->
     MochiReq:get(path).


[07/11] chttpd commit: updated refs/heads/master to 238b8c4

Posted by rn...@apache.org.
Use #httpd.absolute_uri


Project: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/commit/9118f8da
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/tree/9118f8da
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/diff/9118f8da

Branch: refs/heads/master
Commit: 9118f8da1134e6cf5a701e8bbeef270e6c29507b
Parents: 8d8cf91
Author: ILYA Khlopotov <ii...@ca.ibm.com>
Authored: Mon Jun 22 11:37:54 2015 -0700
Committer: ILYA Khlopotov <ii...@ca.ibm.com>
Committed: Tue Aug 11 09:14:29 2015 -0700

----------------------------------------------------------------------
 src/chttpd.erl | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/9118f8da/src/chttpd.erl
----------------------------------------------------------------------
diff --git a/src/chttpd.erl b/src/chttpd.erl
index 7a7bad9..6a80f05 100644
--- a/src/chttpd.erl
+++ b/src/chttpd.erl
@@ -481,7 +481,7 @@ qs(#httpd{mochi_req=MochiReq}) ->
 path(#httpd{mochi_req=MochiReq}) ->
     MochiReq:get(path).
 
-absolute_uri(#httpd{mochi_req=MochiReq}, Path) ->
+absolute_uri(#httpd{mochi_req=MochiReq, absolute_uri = undefined}, Path) ->
     XHost = config:get("httpd", "x_forwarded_host", "X-Forwarded-Host"),
     Host = case MochiReq:get_header_value(XHost) of
         undefined ->
@@ -512,7 +512,9 @@ absolute_uri(#httpd{mochi_req=MochiReq}, Path) ->
                     end
             end
     end,
-    Scheme ++ "://" ++ Host ++ Path.
+    Scheme ++ "://" ++ Host ++ Path;
+absolute_uri(#httpd{absolute_uri = URI}, Path) ->
+    URI ++ Path.
 
 unquote(UrlEncodedString) ->
     mochiweb_util:unquote(UrlEncodedString).


[03/11] chttpd commit: updated refs/heads/master to 238b8c4

Posted by rn...@apache.org.
Derive HandlerKey from path_parts

This is a preparation for introducing `before_request` hook.

Plugin might want to manipulate Path in order to affect handler selection.
Therefore HandlerKey calculation has to happen after
`chttpd_plugin:before_request` and it should be based on the value
returned from that call.

HandlerKey was constructed using `mochiweb_util:partition(Path, "/")`.
We change the logic to use first part of path_parts field of #httpd{}
record.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/commit/8d0fe1c7
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/tree/8d0fe1c7
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/diff/8d0fe1c7

Branch: refs/heads/master
Commit: 8d0fe1c7129a27c4b82f2cd3aa2b498bc36dba25
Parents: f42f96c
Author: ILYA Khlopotov <ii...@ca.ibm.com>
Authored: Fri Jun 19 14:12:33 2015 -0700
Committer: ILYA Khlopotov <ii...@ca.ibm.com>
Committed: Tue Aug 11 09:10:13 2015 -0700

----------------------------------------------------------------------
 src/chttpd.erl | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/8d0fe1c7/src/chttpd.erl
----------------------------------------------------------------------
diff --git a/src/chttpd.erl b/src/chttpd.erl
index b6b30de..d1e07e9 100644
--- a/src/chttpd.erl
+++ b/src/chttpd.erl
@@ -149,8 +149,6 @@ handle_request_int(MochiReq) ->
     % removed, but URL quoting left intact
     RawUri = MochiReq:get(raw_path),
     {"/" ++ Path, _, _} = mochiweb_util:urlsplit_path(RawUri),
-    {HandlerKeyStr, _, _} = mochiweb_util:partition(Path, "/"),
-    HandlerKey = ?l2b(HandlerKeyStr),
 
     Peer = MochiReq:get(peer),
     LogForClosedSocket = io_lib:format("mochiweb_recv_error for ~s - ~p ~s", [
@@ -199,6 +197,12 @@ handle_request_int(MochiReq) ->
                 || Part <- string:tokens(Path, "/")]
     },
 
+    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, couch_util:to_hex(crypto:rand_bytes(5))),
 


[06/11] chttpd commit: updated refs/heads/master to 238b8c4

Posted by rn...@apache.org.
Refactor handle_request/1 to use #httpd_resp{}

Pass more info into #httpd{} and introduce #httpd_resp{} so we can
abstract updating stats and logging of request into separate functions.

We also prepare for introduction of before_request/after_request hooks.


Project: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/commit/8d8cf91a
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/tree/8d8cf91a
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/diff/8d8cf91a

Branch: refs/heads/master
Commit: 8d8cf91a9995a874734873ab767cde46c9c66637
Parents: cf58b04
Author: ILYA Khlopotov <ii...@ca.ibm.com>
Authored: Mon Jun 22 05:32:39 2015 -0700
Committer: ILYA Khlopotov <ii...@ca.ibm.com>
Committed: Tue Aug 11 09:14:29 2015 -0700

----------------------------------------------------------------------
 include/chttpd.hrl | 22 +++++++++++
 src/chttpd.erl     | 97 ++++++++++++++++++++++++++++++++++++++-----------
 2 files changed, 97 insertions(+), 22 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/8d8cf91a/include/chttpd.hrl
----------------------------------------------------------------------
diff --git a/include/chttpd.hrl b/include/chttpd.hrl
new file mode 100644
index 0000000..9d3bd97
--- /dev/null
+++ b/include/chttpd.hrl
@@ -0,0 +1,22 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+
+-record(httpd_resp, {
+    end_ts,
+    code,
+    response,
+    status,
+    nonce,
+    should_log = true,
+    reason
+}).

http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/8d8cf91a/src/chttpd.erl
----------------------------------------------------------------------
diff --git a/src/chttpd.erl b/src/chttpd.erl
index 215f509..7a7bad9 100644
--- a/src/chttpd.erl
+++ b/src/chttpd.erl
@@ -12,6 +12,7 @@
 
 -module(chttpd).
 -include_lib("couch/include/couch_db.hrl").
+-include_lib("chttpd/include/chttpd.hrl").
 
 -export([start_link/0, start_link/1, start_link/2,
     stop/0, handle_request/1, handle_request_int/1,
@@ -190,8 +191,14 @@ handle_request_int(MochiReq) ->
         Other -> Other
     end,
 
+    Nonce = couch_util:to_hex(crypto:rand_bytes(5)),
+
     HttpReq = #httpd{
         mochi_req = MochiReq,
+        begin_ts = Begin,
+        peer = Peer,
+        original_method = Method1,
+        nonce = Nonce,
         method = Method,
         path_parts = [list_to_binary(chttpd:unquote(Part))
                 || Part <- string:tokens(Path, "/")]
@@ -204,12 +211,12 @@ handle_request_int(MochiReq) ->
         end,
 
     % put small token on heap to keep requests synced to backend calls
-    erlang:put(nonce, couch_util:to_hex(crypto:rand_bytes(5))),
+    erlang:put(nonce, Nonce),
 
     % suppress duplicate log
     erlang:put(dont_log_request, true),
 
-    Result =
+    Result0 =
     try
         couch_httpd:validate_host(HttpReq),
         chttpd_csrf:validate(HttpReq),
@@ -260,28 +267,74 @@ handle_request_int(MochiReq) ->
             end
     end,
 
-    RequestTime = timer:now_diff(os:timestamp(), Begin)/1000,
-    {Status, Code} = case Result of
-    {ok, #delayed_resp{resp=Resp}} ->
-        {ok, Resp:get(code)};
-    {ok, Resp} ->
-        {ok, Resp:get(code)};
-    {aborted, Resp, _} ->
-        {aborted, Resp:get(code)}
+    {HttpReq1, HttpResp0} = result(Result0, HttpReq),
+
+    HttpResp1 = update_stats(HttpReq1, HttpResp0),
+    maybe_log(HttpReq1, HttpResp1),
+
+    case HttpResp1 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.
+
+result(Result, #httpd{nonce = Nonce} = Req) ->
+    {Status, Code, Reason} = case Result of
+        {ok, #delayed_resp{resp=Resp}} ->
+            {ok, Resp:get(code), undefined};
+        {ok, Resp} ->
+            {ok, Resp:get(code), undefined};
+        {aborted, Resp, AbortReason} ->
+            {aborted, Resp:get(code), AbortReason}
+        end,
+
+    HttpResp = #httpd_resp{
+        code = Code,
+        status = Status,
+        response = Resp,
+        nonce = Nonce,
+        reason = Reason
+    },
+    {Req, HttpResp}.
+
+
+update_stats(HttpReq, #httpd_resp{end_ts = undefined} = Res) ->
+    update_stats(HttpReq, Res#httpd_resp{end_ts = os:timestamp()});
+update_stats(#httpd{begin_ts = BeginTime}, #httpd_resp{} = Res) ->
+    #httpd_resp{status = Status, end_ts = EndTime} = Res,
+    RequestTime = timer:now_diff(EndTime, BeginTime) / 1000,
+    couch_stats:update_histogram([couchdb, request_time], RequestTime),
+    case Status of
+        ok ->
+            couch_stats:increment_counter([couchdb, httpd, requests]);
+        aborted ->
+            couch_stats:increment_counter([couchdb, httpd, aborted_requests])
     end,
+    Res.
+
+maybe_log(#httpd{} = HttpReq, #httpd_resp{should_log = true} = HttpResp) ->
+    #httpd{
+        mochi_req = MochiReq,
+        begin_ts = BeginTime,
+        original_method = Method,
+        peer = Peer,
+        nonce = Nonce
+    } = HttpReq,
+    #httpd_resp{
+        end_ts = EndTime,
+        code = Code,
+        status = Status
+    } = HttpResp,
     Host = MochiReq:get_header_value("Host"),
-    couch_log:notice("~s ~s ~s ~s ~s ~B ~p ~B", [get(nonce), Peer, Host,
-        atom_to_list(Method1), RawUri, Code, Status, round(RequestTime)]),
-    couch_stats:update_histogram([couchdb, request_time], RequestTime),
-    case Result of
-    {ok, _} ->
-        couch_stats:increment_counter([couchdb, httpd, requests]),
-        {ok, Resp};
-    {aborted, _, Reason} ->
-        couch_stats:increment_counter([couchdb, httpd, aborted_requests]),
-        couch_log:error("Response abnormally terminated: ~p", [Reason]),
-        exit(normal)
-    end.
+    RawUri = MochiReq:get(raw_path),
+    RequestTime = timer:now_diff(EndTime, BeginTime) / 1000,
+    couch_log:notice("~s ~s ~s ~s ~s ~B ~p ~B", [Nonce, Peer, Host,
+        atom_to_list(Method), RawUri, Code, Status, round(RequestTime)]);
+maybe_log(_HttpReq, #httpd_resp{should_log = false}) ->
+    ok.
+
 
 %% HACK: replication currently handles two forms of input, #db{} style
 %% and #http_db style. We need a third that makes use of fabric. #db{}


[05/11] chttpd commit: updated refs/heads/master to 238b8c4

Posted by rn...@apache.org.
Use private to_lower instead of string:to_lower


Project: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/commit/b5d65eae
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/tree/b5d65eae
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/diff/b5d65eae

Branch: refs/heads/master
Commit: b5d65eaef90435f1041b8d697788d3825e540b03
Parents: 64aa2fd
Author: ILYA Khlopotov <ii...@ca.ibm.com>
Authored: Wed Jul 29 11:59:42 2015 -0700
Committer: ILYA Khlopotov <ii...@ca.ibm.com>
Committed: Tue Aug 11 09:14:29 2015 -0700

----------------------------------------------------------------------
 src/chttpd_cors.erl | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/b5d65eae/src/chttpd_cors.erl
----------------------------------------------------------------------
diff --git a/src/chttpd_cors.erl b/src/chttpd_cors.erl
index fc30c9a..525fc5f 100644
--- a/src/chttpd_cors.erl
+++ b/src/chttpd_cors.erl
@@ -130,7 +130,7 @@ handle_preflight_request(Req, Config, Origin) ->
                         %% transform header list in something we
                         %% could check. make sure everything is a
                         %% list
-                        RH = [string:to_lower(H)
+                        RH = [to_lower(H)
                               || H <- split_headers(Headers)],
                         {Headers, RH}
                 end,
@@ -346,7 +346,7 @@ get_origin(Req) ->
         undefined ->
             undefined;
         Origin ->
-            list_to_binary(string:to_lower(Origin))
+            ?l2b(to_lower(Origin))
     end.
 
 


[10/11] chttpd commit: updated refs/heads/master to 238b8c4

Posted by rn...@apache.org.
Use `#httpd.cors_config`


Project: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/commit/2b427592
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/tree/2b427592
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/diff/2b427592

Branch: refs/heads/master
Commit: 2b427592d811db38723905127157a06bb3a19a9d
Parents: 9118f8d
Author: ILYA Khlopotov <ii...@ca.ibm.com>
Authored: Mon Jun 29 06:19:11 2015 -0700
Committer: ILYA Khlopotov <ii...@ca.ibm.com>
Committed: Tue Aug 11 09:14:29 2015 -0700

----------------------------------------------------------------------
 src/chttpd_cors.erl | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/2b427592/src/chttpd_cors.erl
----------------------------------------------------------------------
diff --git a/src/chttpd_cors.erl b/src/chttpd_cors.erl
index cedb86e..fc30c9a 100644
--- a/src/chttpd_cors.erl
+++ b/src/chttpd_cors.erl
@@ -265,7 +265,7 @@ allow_credentials(Config, Origin) ->
     get_origin_config(Config, Origin, <<"allow_credentials">>,
         ?CORS_DEFAULT_ALLOW_CREDENTIALS).
 
-get_cors_config(_Req) ->
+get_cors_config(#httpd{cors_config = undefined}) ->
     EnableCors = config:get("httpd", "enable_cors", "false") =:= "true",
     AllowCredentials = config:get("cors", "credentials", "false") =:= "true",
     AllowHeaders = case config:get("cors", "methods", undefined) of
@@ -288,8 +288,9 @@ get_cors_config(_Req) ->
         {<<"allow_methods">>, AllowMethods},
         {<<"allow_headers">>, AllowHeaders},
         {<<"origins">>, {Origins}}
-    ].
-
+    ];
+get_cors_config(#httpd{cors_config = Config}) ->
+    Config.
 
 is_cors_enabled(Config) ->
     case get(disable_couch_httpd_cors) of


[11/11] chttpd commit: updated refs/heads/master to 238b8c4

Posted by rn...@apache.org.
Return `{error, {illegal_database_name, Name}}`


Project: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/commit/238b8c48
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/tree/238b8c48
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/diff/238b8c48

Branch: refs/heads/master
Commit: 238b8c48285ed118821807ee057d1a59775acb06
Parents: 4ba06e0
Author: ILYA Khlopotov <ii...@ca.ibm.com>
Authored: Fri Jul 31 11:35:24 2015 -0700
Committer: ILYA Khlopotov <ii...@ca.ibm.com>
Committed: Tue Aug 11 09:14:29 2015 -0700

----------------------------------------------------------------------
 src/chttpd.erl                   | 9 +++++----
 test/chttpd_error_info_tests.erl | 6 +++---
 2 files changed, 8 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/238b8c48/src/chttpd.erl
----------------------------------------------------------------------
diff --git a/src/chttpd.erl b/src/chttpd.erl
index 749f550..52400ca 100644
--- a/src/chttpd.erl
+++ b/src/chttpd.erl
@@ -804,10 +804,11 @@ error_info({bad_ctype, Reason}) ->
     {415, <<"bad_content_type">>, Reason};
 error_info(requested_range_not_satisfiable) ->
     {416, <<"requested_range_not_satisfiable">>, <<"Requested range not satisfiable">>};
-error_info({error, illegal_database_name}) ->
-    {400, <<"illegal_database_name">>, <<"Only lowercase letters (a-z), "
-        "digits (0-9), and any of the characters _, $, (, ), +, -, and / are "
-        "allowed. Moreover, the database name must begin with a letter.">>};
+error_info({error, {illegal_database_name, Name}}) ->
+    Message = <<"Name: '", Name/binary, "'. Only lowercase characters (a-z), ",
+        "digits (0-9), and any of the characters _, $, (, ), +, -, and / ",
+        "are allowed. Must begin with a letter.">>,
+    {400, <<"illegal_database_name">>, Message};
 error_info({missing_stub, Reason}) ->
     {412, <<"missing_stub">>, Reason};
 error_info(request_entity_too_large) ->

http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/238b8c48/test/chttpd_error_info_tests.erl
----------------------------------------------------------------------
diff --git a/test/chttpd_error_info_tests.erl b/test/chttpd_error_info_tests.erl
index 447eb42..cb0a58a 100644
--- a/test/chttpd_error_info_tests.erl
+++ b/test/chttpd_error_info_tests.erl
@@ -110,11 +110,11 @@ error_info_test() ->
              <<"Requested range not satisfiable">>}
         },
         {
-            {error, illegal_database_name},
+            {error, {illegal_database_name, <<"foo">>}},
             {400, <<"illegal_database_name">>,
-             <<"Only lowercase letters (a-z), digits (0-9), and any of"
+             <<"Name: 'foo'. Only lowercase characters (a-z), digits (0-9), and any of"
                " the characters _, $, (, ), +, -, and / are allowed."
-               " Moreover, the database name must begin with a letter.">>}
+               " Must begin with a letter.">>}
         },
         {
             {missing_stub, Reason},


[08/11] chttpd commit: updated refs/heads/master to 238b8c4

Posted by rn...@apache.org.
Add chttpd_plugin hooks

We add following hooks:

 - chttpd_plugin:before_request/1
 - chttpd_plugin:after_request/2
 - chttpd_plugin:handle_error/1


Project: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/commit/64aa2fd0
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/tree/64aa2fd0
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/diff/64aa2fd0

Branch: refs/heads/master
Commit: 64aa2fd0933f1ac8beb3584441663b20cf6e3179
Parents: 2b42759
Author: ILYA Khlopotov <ii...@ca.ibm.com>
Authored: Wed Jul 29 11:31:28 2015 -0700
Committer: ILYA Khlopotov <ii...@ca.ibm.com>
Committed: Tue Aug 11 09:14:29 2015 -0700

----------------------------------------------------------------------
 src/chttpd.erl        | 32 +++++++++++++++++++++++--------
 src/chttpd_plugin.erl | 48 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 72 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/64aa2fd0/src/chttpd.erl
----------------------------------------------------------------------
diff --git a/src/chttpd.erl b/src/chttpd.erl
index 6a80f05..ec15033 100644
--- a/src/chttpd.erl
+++ b/src/chttpd.erl
@@ -193,7 +193,7 @@ handle_request_int(MochiReq) ->
 
     Nonce = couch_util:to_hex(crypto:rand_bytes(5)),
 
-    HttpReq = #httpd{
+    HttpReq0 = #httpd{
         mochi_req = MochiReq,
         begin_ts = Begin,
         peer = Peer,
@@ -204,6 +204,8 @@ handle_request_int(MochiReq) ->
                 || Part <- string:tokens(Path, "/")]
     },
 
+    {ok, HttpReq} = chttpd_plugin:before_request(HttpReq0),
+
     HandlerKey =
         case HttpReq#httpd.path_parts of
             [] -> <<>>;
@@ -229,7 +231,7 @@ handle_request_int(MochiReq) ->
                     HandlerKey, fun chttpd_db:handle_request/1),
                 AuthorizedReq = chttpd_auth:authorize(possibly_hack(Req),
                     fun chttpd_auth_request:authorize_request/1),
-                HandlerFun(AuthorizedReq);
+                {AuthorizedReq, HandlerFun(AuthorizedReq)};
             Response ->
                 Response
             end;
@@ -268,11 +270,12 @@ handle_request_int(MochiReq) ->
     end,
 
     {HttpReq1, HttpResp0} = result(Result0, HttpReq),
+    {ok, HttpResp1} = chttpd_plugin:after_request(HttpReq1, HttpResp0),
 
-    HttpResp1 = update_stats(HttpReq1, HttpResp0),
-    maybe_log(HttpReq1, HttpResp1),
+    HttpResp2 = update_stats(HttpReq1, HttpResp1),
+    maybe_log(HttpReq1, HttpResp2),
 
-    case HttpResp1 of
+    case HttpResp2 of
         #httpd_resp{status = ok, response = Resp} ->
             {ok, Resp};
         #httpd_resp{status = aborted, reason = Reason} ->
@@ -280,6 +283,8 @@ handle_request_int(MochiReq) ->
             exit(normal)
     end.
 
+result({#httpd{} = Req, Result}, _) ->
+    result(Result, Req);
 result(Result, #httpd{nonce = Nonce} = Req) ->
     {Status, Code, Reason} = case Result of
         {ok, #delayed_resp{resp=Resp}} ->
@@ -817,14 +822,25 @@ error_info({timeout, _Reason}) ->
     error_info(timeout);
 error_info({Error, null}) ->
     error_info(Error);
-error_info({Error, Reason}) ->
-    {500, couch_util:to_binary(Error), couch_util:to_binary(Reason)};
+error_info({_Error, _Reason} = Error) ->
+    maybe_handle_error(Error);
 error_info({Error, nil, _Stack}) ->
     error_info(Error);
 error_info({Error, Reason, _Stack}) ->
     {500, couch_util:to_binary(Error), couch_util:to_binary(Reason)};
 error_info(Error) ->
-    {500, <<"unknown_error">>, couch_util:to_binary(Error)}.
+    maybe_handle_error({<<"unknown_error">>, Error}).
+
+maybe_handle_error(Error) ->
+    case chttpd_plugin:handle_error(Error) of
+        {_Code, _Reason, _Description} = Result ->
+            Result;
+        {Err, Reason} ->
+            {500, couch_util:to_binary(Err), couch_util:to_binary(Reason)};
+        Error ->
+            {500, couch_util:to_binary(Error), null}
+    end.
+
 
 error_headers(#httpd{mochi_req=MochiReq}=Req, 401=Code, ErrorStr, ReasonStr) ->
     % this is where the basic auth popup is triggered

http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/64aa2fd0/src/chttpd_plugin.erl
----------------------------------------------------------------------
diff --git a/src/chttpd_plugin.erl b/src/chttpd_plugin.erl
new file mode 100644
index 0000000..e174a68
--- /dev/null
+++ b/src/chttpd_plugin.erl
@@ -0,0 +1,48 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+%   http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(chttpd_plugin).
+
+-export([
+    before_request/1,
+    after_request/2,
+    handle_error/1
+]).
+
+-include_lib("couch/include/couch_db.hrl").
+
+%% ------------------------------------------------------------------
+%% API Function Definitions
+%% ------------------------------------------------------------------
+
+before_request(HttpReq) ->
+    [HttpReq1] = with_pipe(before_request, [HttpReq]),
+    {ok, HttpReq1}.
+
+after_request(HttpReq, Result) ->
+    [_, Result1] = with_pipe(after_request, [HttpReq, Result]),
+    {ok, Result1}.
+
+handle_error(Error) ->
+    [Error1] = with_pipe(after_request, [Error]),
+    Error1.
+
+%% ------------------------------------------------------------------
+%% Internal Function Definitions
+%% ------------------------------------------------------------------
+
+with_pipe(Func, Args) ->
+    do_apply(Func, Args, [ignore_providers, pipe]).
+
+do_apply(Func, Args, Opts) ->
+    Handle = couch_epi:get_handle(chttpd),
+    couch_epi:apply(Handle, chttpd, Func, Args, Opts).