You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ch...@apache.org on 2014/03/28 19:45:51 UTC

[1/7] chttpd commit: updated refs/heads/1993-bigcouch-couch-mrview to 93c771d

Repository: couchdb-chttpd
Updated Branches:
  refs/heads/1993-bigcouch-couch-mrview a93a9ab18 -> 93c771d6f (forced update)


Switch to couch_log


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

Branch: refs/heads/1993-bigcouch-couch-mrview
Commit: 30e7912a8524cc8833d19e452519372f94215a2d
Parents: a1b8b07
Author: Robert Newson <ro...@cloudant.com>
Authored: Wed Feb 12 20:10:59 2014 +0000
Committer: Robert Newson <ro...@cloudant.com>
Committed: Wed Feb 12 20:10:59 2014 +0000

----------------------------------------------------------------------
 src/chttpd.app.src     |  2 +-
 src/chttpd.erl         | 10 +++++-----
 src/chttpd_db.erl      |  4 ++--
 src/chttpd_rewrite.erl |  4 ++--
 4 files changed, 10 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/30e7912a/src/chttpd.app.src
----------------------------------------------------------------------
diff --git a/src/chttpd.app.src b/src/chttpd.app.src
index 9ab91c8..3ce0c72 100644
--- a/src/chttpd.app.src
+++ b/src/chttpd.app.src
@@ -32,7 +32,7 @@
     {applications, [
         kernel,
         stdlib,
-        twig,
+        couch_log,
         config,
         couch,
         fabric

http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/30e7912a/src/chttpd.erl
----------------------------------------------------------------------
diff --git a/src/chttpd.erl b/src/chttpd.erl
index b7f8013..4c6cfc4 100644
--- a/src/chttpd.erl
+++ b/src/chttpd.erl
@@ -168,7 +168,7 @@ handle_request(MochiReq) ->
     MethodOverride = MochiReq:get_primary_header_value("X-HTTP-Method-Override"),
     Method2 = case lists:member(MethodOverride, ["GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT", "COPY"]) of
     true ->
-        twig:log(notice, "MethodOverride: ~s (real method was ~s)", [MethodOverride, Method1]),
+        couch_log:log(notice, "MethodOverride: ~s (real method was ~s)", [MethodOverride, Method1]),
         case Method1 of
         'POST' -> couch_util:to_existing_atom(MethodOverride);
         _ ->
@@ -215,7 +215,7 @@ handle_request(MochiReq) ->
         throw:{invalid_json, _} ->
             send_error(HttpReq, {bad_request, "invalid UTF-8 JSON"});
         exit:{mochiweb_recv_error, E} ->
-            twig:log(notice, LogForClosedSocket ++ " - ~p", [E]),
+            couch_log:log(notice, LogForClosedSocket ++ " - ~p", [E]),
             exit(normal);
         throw:Error ->
             send_error(HttpReq, Error);
@@ -231,7 +231,7 @@ handle_request(MochiReq) ->
                     exit(normal); % Client disconnect (R14)
                 _Else ->
                     JsonStack = json_stack({Error, nil, Stack}),
-                    twig:log(error, "req_err ~p:~p ~p", [Tag, Error, JsonStack]),
+                    couch_log:log(error, "req_err ~p:~p ~p", [Tag, Error, JsonStack]),
                     send_error(HttpReq, {Error, nil, Stack})
             end
     end,
@@ -246,7 +246,7 @@ handle_request(MochiReq) ->
         {aborted, Resp:get(code)}
     end,
     Host = MochiReq:get_header_value("Host"),
-    twig:log(notice, "~s ~s ~s ~s ~B ~p ~B", [Peer, Host,
+    couch_log:log(notice, "~s ~s ~s ~s ~B ~p ~B", [Peer, Host,
         atom_to_list(Method1), RawUri, Code, Status, round(RequestTime)]),
     couch_stats_collector:record({couchdb, request_time}, RequestTime),
     case Result of
@@ -255,7 +255,7 @@ handle_request(MochiReq) ->
         {ok, Resp};
     {aborted, _, Reason} ->
         couch_stats_collector:increment({httpd, aborted_requests}),
-        twig:log(error, "Response abnormally terminated: ~p", [Reason]),
+        couch_log:log(error, "Response abnormally terminated: ~p", [Reason]),
         exit(normal)
     end.
 

http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/30e7912a/src/chttpd_db.erl
----------------------------------------------------------------------
diff --git a/src/chttpd_db.erl b/src/chttpd_db.erl
index de99828..eb1a1c0 100644
--- a/src/chttpd_db.erl
+++ b/src/chttpd_db.erl
@@ -234,7 +234,7 @@ db_req(#httpd{method='POST', path_parts=[DbName], user_ctx=Ctx}=Req, Db) ->
                 {ok, _} -> ok;
                 {accepted, _} -> ok;
                 Error ->
-                    twig:log(debug, "Batch doc error (~s): ~p",[DocId, Error])
+                    couch_log:log(debug, "Batch doc error (~s): ~p",[DocId, Error])
                 end
             end),
 
@@ -646,7 +646,7 @@ db_doc_req(#httpd{method='PUT', user_ctx=Ctx}=Req, Db, DocId) ->
                     {ok, _} -> ok;
                     {accepted, _} -> ok;
                     Error ->
-                        twig:log(notice, "Batch doc error (~s): ~p",[DocId, Error])
+                        couch_log:log(notice, "Batch doc error (~s): ~p",[DocId, Error])
                     end
                 end),
             send_json(Req, 202, [], {[

http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/30e7912a/src/chttpd_rewrite.erl
----------------------------------------------------------------------
diff --git a/src/chttpd_rewrite.erl b/src/chttpd_rewrite.erl
index a18fa00..c8df271 100644
--- a/src/chttpd_rewrite.erl
+++ b/src/chttpd_rewrite.erl
@@ -165,7 +165,7 @@ handle_rewrite_req(#httpd{
             % normalize final path (fix levels "." and "..")
             RawPath1 = ?b2l(iolist_to_binary(normalize_path(RawPath))),
 
-            twig:log(debug, "rewrite to ~p ~n", [RawPath1]),
+            couch_log:log(debug, "rewrite to ~p ~n", [RawPath1]),
 
             % build a new mochiweb request
             MochiReq1 = mochiweb_request:new(MochiReq:get(socket),
@@ -415,7 +415,7 @@ path_to_list([<<"..">>|R], Acc, DotDotCount) when DotDotCount == 2 ->
     "false" ->
         path_to_list(R, [<<"..">>|Acc], DotDotCount+1);
     _Else ->
-        twig:log(notice, "insecure_rewrite_rule ~p blocked", [lists:reverse(Acc) ++ [<<"..">>] ++ R]),
+        couch_log:log(notice, "insecure_rewrite_rule ~p blocked", [lists:reverse(Acc) ++ [<<"..">>] ++ R]),
         throw({insecure_rewrite_rule, "too many ../.. segments"})
     end;
 path_to_list([<<"..">>|R], Acc, DotDotCount) ->


[2/7] chttpd commit: updated refs/heads/1993-bigcouch-couch-mrview to 93c771d

Posted by ch...@apache.org.
Ask couch_httpd:log_request not to log a duplicate line


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

Branch: refs/heads/1993-bigcouch-couch-mrview
Commit: 927a8d11ba127484ab46a5c46ccc7c5b95db1acf
Parents: 30e7912
Author: Robert Newson <ro...@cloudant.com>
Authored: Wed Feb 12 22:52:20 2014 +0000
Committer: Robert Newson <ro...@cloudant.com>
Committed: Wed Feb 12 22:52:20 2014 +0000

----------------------------------------------------------------------
 src/chttpd.erl | 3 +++
 1 file changed, 3 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/927a8d11/src/chttpd.erl
----------------------------------------------------------------------
diff --git a/src/chttpd.erl b/src/chttpd.erl
index 4c6cfc4..2ff7189 100644
--- a/src/chttpd.erl
+++ b/src/chttpd.erl
@@ -198,6 +198,9 @@ handle_request(MochiReq) ->
     % put small token on heap to keep requests synced to backend calls
     erlang:put(nonce, couch_util:to_hex(crypto:rand_bytes(4))),
 
+    % suppress duplicate log
+    erlang:put(dont_log_request, true),
+
     Result =
     try
         case authenticate_request(HttpReq, AuthenticationFuns) of


[6/7] chttpd commit: updated refs/heads/1993-bigcouch-couch-mrview to 93c771d

Posted by ch...@apache.org.
Update chttpd show and list functions to use couch_mrview


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

Branch: refs/heads/1993-bigcouch-couch-mrview
Commit: b858f5abfe07eb4c87c1a5b54b6bb93aeadf7889
Parents: 4a154f7
Author: Russell Branca <ch...@gmail.com>
Authored: Thu Mar 27 12:11:07 2014 -0700
Committer: Russell Branca <ch...@gmail.com>
Committed: Fri Mar 28 11:30:40 2014 -0700

----------------------------------------------------------------------
 src/chttpd_show.erl | 103 ++++-------------------------------------------
 1 file changed, 8 insertions(+), 95 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/b858f5ab/src/chttpd_show.erl
----------------------------------------------------------------------
diff --git a/src/chttpd_show.erl b/src/chttpd_show.erl
index b028f4c..781d392 100644
--- a/src/chttpd_show.erl
+++ b/src/chttpd_show.erl
@@ -15,15 +15,7 @@
 -export([handle_doc_show_req/3, handle_doc_update_req/3, handle_view_list_req/3]).
 
 -include_lib("couch/include/couch_db.hrl").
-
--record(lacc, {
-    req,
-    resp = nil,
-    qserver,
-    lname,
-    db,
-    etag
-}).
+-include_lib("couch_mrview/include/couch_mrview.hrl").
 
 % /db/_design/foo/_show/bar/docid
 % show converts a json doc to a response of any content-type. 
@@ -152,13 +144,13 @@ send_doc_update_response(Req, Db, DDoc, UpdateName, Doc, DocId) ->
 % view-list request with view and list from same design doc.
 handle_view_list_req(#httpd{method='GET',
         path_parts=[_, _, DesignName, _, ListName, ViewName]}=Req, Db, DDoc) ->
-    Keys = chttpd:qs_json_value(Req, "keys", nil),
+    Keys = chttpd:qs_json_value(Req, "keys", undefined),
     handle_view_list(Req, Db, DDoc, ListName, {DesignName, ViewName}, Keys);
 
 % view-list request with view and list from different design docs.
 handle_view_list_req(#httpd{method='GET',
         path_parts=[_, _, _, _, ListName, DesignName, ViewName]}=Req, Db, DDoc) ->
-    Keys = chttpd:qs_json_value(Req, "keys", nil),
+    Keys = chttpd:qs_json_value(Req, "keys", undefined),
     handle_view_list(Req, Db, DDoc, ListName, {DesignName, ViewName}, Keys);
 
 handle_view_list_req(#httpd{method='GET'}=Req, _Db, _DDoc) ->
@@ -168,7 +160,7 @@ handle_view_list_req(#httpd{method='POST',
         path_parts=[_, _, DesignName, _, ListName, ViewName]}=Req, Db, DDoc) ->
     ReqBody = chttpd:body(Req),
     {Props2} = ?JSON_DECODE(ReqBody),
-    Keys = proplists:get_value(<<"keys">>, Props2, nil),
+    Keys = proplists:get_value(<<"keys">>, Props2, undefined),
     handle_view_list(Req#httpd{req_body=ReqBody}, Db, DDoc, ListName,
         {DesignName, ViewName}, Keys);
 
@@ -176,7 +168,7 @@ handle_view_list_req(#httpd{method='POST',
         path_parts=[_, _, _, _, ListName, DesignName, ViewName]}=Req, Db, DDoc) ->
     ReqBody = chttpd:body(Req),
     {Props2} = ?JSON_DECODE(ReqBody),
-    Keys = proplists:get_value(<<"keys">>, Props2, nil),
+    Keys = proplists:get_value(<<"keys">>, Props2, undefined),
     handle_view_list(Req#httpd{req_body=ReqBody}, Db, DDoc, ListName,
         {DesignName, ViewName}, Keys);
 
@@ -189,14 +181,10 @@ handle_view_list_req(Req, _Db, _DDoc) ->
 handle_view_list(Req, Db, DDoc, LName, {ViewDesignName, ViewName}, Keys) ->
     %% Will throw an exception if the _list handler is missing
     couch_util:get_nested_json_value(DDoc#doc.body, [<<"lists">>, LName]),
-    {ok, VDoc} = fabric:open_doc(Db, <<"_design/", ViewDesignName/binary>>, []),
-    Group = couch_view_group:design_doc_to_view_group(VDoc),
-    IsReduce = chttpd_view:get_reduce_type(Req),
-    ViewType = chttpd_view:extract_view_type(ViewName,
-        couch_view_group:get_views(Group), IsReduce),
-    QueryArgs = chttpd_view:parse_view_params(Req, Keys, ViewType),
-    CB = fun list_callback/2,
+    {ok, VDoc} = ddoc_cache:open(Db#db.name, <<"_design/", ViewDesignName/binary>>),
+    CB = fun couch_mrview_show:list_cb/2,
     Etag = couch_uuids:new(),
+    QueryArgs = couch_mrview_http:parse_params(Req, Keys),
     chttpd:etag_respond(Req, Etag, fun() ->
         couch_query_servers:with_ddoc_proc(DDoc, fun(QServer) ->
             Acc0 = #lacc{
@@ -210,81 +198,6 @@ handle_view_list(Req, Db, DDoc, LName, {ViewDesignName, ViewName}, Keys) ->
         end)
     end).
 
-list_callback({total_and_offset, Total, Offset}, #lacc{resp=nil} = Acc) ->
-    start_list_resp({[{<<"total_rows">>, Total}, {<<"offset">>, Offset}]}, Acc);
-list_callback({total_and_offset, _, _}, Acc) ->
-    % a sorted=false view where the message came in late.  Ignore.
-    {ok, Acc};
-list_callback({row, Row}, #lacc{resp=nil} = Acc) ->
-    % first row of a reduce view, or a sorted=false view
-    {ok, NewAcc} = start_list_resp({[]}, Acc),
-    send_list_row(Row, NewAcc);
-list_callback({row, Row}, Acc) ->
-    send_list_row(Row, Acc);
-list_callback(complete, Acc) ->
-    #lacc{qserver = {Proc, _}, resp = Resp0} = Acc,
-    if Resp0 =:= nil ->
-        {ok, #lacc{resp = Resp}} = start_list_resp({[]}, Acc);
-    true ->
-        Resp = Resp0
-    end,
-    try couch_query_servers:proc_prompt(Proc, [<<"list_end">>]) of
-    [<<"end">>, Chunk] ->
-        {ok, Resp1} = send_non_empty_chunk(Resp, Chunk),
-        chttpd:send_delayed_last_chunk(Resp1)
-    catch Error ->
-        {ok, Resp1} = chttpd:send_delayed_error(Resp, Error),
-        {stop, Resp1}
-    end;
-list_callback({error, Reason}, #lacc{resp=Resp}) ->
-    chttpd:send_delayed_error(Resp, Reason).
-
-start_list_resp(Head, Acc) ->
-    #lacc{
-        req = Req,
-        db = Db,
-        qserver = QServer,
-        lname = LName,
-        etag = Etag
-    } = Acc,
-
-    % use a separate process because we're already in a receive loop, and
-    % json_req_obj calls fabric:get_db_info()
-    spawn_monitor(fun() -> exit(chttpd_external:json_req_obj(Req, Db)) end),
-    receive {'DOWN', _, _, _, JsonReq} -> ok end,
-
-    [<<"start">>,Chunk,JsonResp] = couch_query_servers:ddoc_proc_prompt(QServer,
-        [<<"lists">>, LName], [Head, JsonReq]),
-    JsonResp2 = apply_etag(JsonResp, Etag),
-    #extern_resp_args{
-        code = Code,
-        ctype = CType,
-        headers = ExtHeaders
-    } = couch_httpd_external:parse_external_response(JsonResp2),
-    JsonHeaders = couch_httpd_external:default_or_content_type(CType, ExtHeaders),
-    {ok, Resp} = chttpd:start_delayed_chunked_response(Req, Code,
-        JsonHeaders, Chunk),
-    {ok, Acc#lacc{resp=Resp}}.
-
-send_list_row(Row, #lacc{qserver = {Proc, _}, resp = Resp} = Acc) ->
-    try couch_query_servers:proc_prompt(Proc, [<<"list_row">>, Row]) of
-    [<<"chunks">>, Chunk] ->
-        {ok, Resp1} = send_non_empty_chunk(Resp, Chunk),
-        {ok, Acc#lacc{resp=Resp1}};
-    [<<"end">>, Chunk] ->
-        {ok, Resp1} = send_non_empty_chunk(Resp, Chunk),
-        {ok, Resp2} = chttpd:send_delayed_last_chunk(Resp1),
-        {stop, Resp2}
-    catch Error ->
-        {ok, Resp1} = chttpd:send_delayed_error(Resp, Error),
-        {stop, Resp1}
-    end.
-
-send_non_empty_chunk(Resp, []) ->
-    {ok, Resp};
-send_non_empty_chunk(Resp, Chunk) ->
-    chttpd:send_delayed_chunk(Resp, Chunk).
-
 % Maybe this is in the proplists API
 % todo move to couch_util
 json_apply_field(H, {L}) ->


[3/7] chttpd commit: updated refs/heads/1993-bigcouch-couch-mrview to 93c771d

Posted by ch...@apache.org.
Change API to function per level


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

Branch: refs/heads/1993-bigcouch-couch-mrview
Commit: faaf44e987580b884961a910f862462f22f0d98d
Parents: 927a8d1
Author: Robert Newson <rn...@apache.org>
Authored: Wed Feb 12 23:22:44 2014 +0000
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Feb 12 23:22:44 2014 +0000

----------------------------------------------------------------------
 src/chttpd.erl         | 10 +++++-----
 src/chttpd_db.erl      |  4 ++--
 src/chttpd_rewrite.erl |  4 ++--
 3 files changed, 9 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/faaf44e9/src/chttpd.erl
----------------------------------------------------------------------
diff --git a/src/chttpd.erl b/src/chttpd.erl
index 2ff7189..7504db4 100644
--- a/src/chttpd.erl
+++ b/src/chttpd.erl
@@ -168,7 +168,7 @@ handle_request(MochiReq) ->
     MethodOverride = MochiReq:get_primary_header_value("X-HTTP-Method-Override"),
     Method2 = case lists:member(MethodOverride, ["GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT", "COPY"]) of
     true ->
-        couch_log:log(notice, "MethodOverride: ~s (real method was ~s)", [MethodOverride, Method1]),
+        couch_log:notice("MethodOverride: ~s (real method was ~s)", [MethodOverride, Method1]),
         case Method1 of
         'POST' -> couch_util:to_existing_atom(MethodOverride);
         _ ->
@@ -218,7 +218,7 @@ handle_request(MochiReq) ->
         throw:{invalid_json, _} ->
             send_error(HttpReq, {bad_request, "invalid UTF-8 JSON"});
         exit:{mochiweb_recv_error, E} ->
-            couch_log:log(notice, LogForClosedSocket ++ " - ~p", [E]),
+            couch_log:notice(LogForClosedSocket ++ " - ~p", [E]),
             exit(normal);
         throw:Error ->
             send_error(HttpReq, Error);
@@ -234,7 +234,7 @@ handle_request(MochiReq) ->
                     exit(normal); % Client disconnect (R14)
                 _Else ->
                     JsonStack = json_stack({Error, nil, Stack}),
-                    couch_log:log(error, "req_err ~p:~p ~p", [Tag, Error, JsonStack]),
+                    couch_log:error("req_err ~p:~p ~p", [Tag, Error, JsonStack]),
                     send_error(HttpReq, {Error, nil, Stack})
             end
     end,
@@ -249,7 +249,7 @@ handle_request(MochiReq) ->
         {aborted, Resp:get(code)}
     end,
     Host = MochiReq:get_header_value("Host"),
-    couch_log:log(notice, "~s ~s ~s ~s ~B ~p ~B", [Peer, Host,
+    couch_log:notice("~s ~s ~s ~s ~B ~p ~B", [Peer, Host,
         atom_to_list(Method1), RawUri, Code, Status, round(RequestTime)]),
     couch_stats_collector:record({couchdb, request_time}, RequestTime),
     case Result of
@@ -258,7 +258,7 @@ handle_request(MochiReq) ->
         {ok, Resp};
     {aborted, _, Reason} ->
         couch_stats_collector:increment({httpd, aborted_requests}),
-        couch_log:log(error, "Response abnormally terminated: ~p", [Reason]),
+        couch_log:error("Response abnormally terminated: ~p", [Reason]),
         exit(normal)
     end.
 

http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/faaf44e9/src/chttpd_db.erl
----------------------------------------------------------------------
diff --git a/src/chttpd_db.erl b/src/chttpd_db.erl
index eb1a1c0..0f2c5e3 100644
--- a/src/chttpd_db.erl
+++ b/src/chttpd_db.erl
@@ -234,7 +234,7 @@ db_req(#httpd{method='POST', path_parts=[DbName], user_ctx=Ctx}=Req, Db) ->
                 {ok, _} -> ok;
                 {accepted, _} -> ok;
                 Error ->
-                    couch_log:log(debug, "Batch doc error (~s): ~p",[DocId, Error])
+                    couch_log:debug("Batch doc error (~s): ~p",[DocId, Error])
                 end
             end),
 
@@ -646,7 +646,7 @@ db_doc_req(#httpd{method='PUT', user_ctx=Ctx}=Req, Db, DocId) ->
                     {ok, _} -> ok;
                     {accepted, _} -> ok;
                     Error ->
-                        couch_log:log(notice, "Batch doc error (~s): ~p",[DocId, Error])
+                        couch_log:notice("Batch doc error (~s): ~p",[DocId, Error])
                     end
                 end),
             send_json(Req, 202, [], {[

http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/faaf44e9/src/chttpd_rewrite.erl
----------------------------------------------------------------------
diff --git a/src/chttpd_rewrite.erl b/src/chttpd_rewrite.erl
index c8df271..2a0cf64 100644
--- a/src/chttpd_rewrite.erl
+++ b/src/chttpd_rewrite.erl
@@ -165,7 +165,7 @@ handle_rewrite_req(#httpd{
             % normalize final path (fix levels "." and "..")
             RawPath1 = ?b2l(iolist_to_binary(normalize_path(RawPath))),
 
-            couch_log:log(debug, "rewrite to ~p ~n", [RawPath1]),
+            couch_log:debug("rewrite to ~p ~n", [RawPath1]),
 
             % build a new mochiweb request
             MochiReq1 = mochiweb_request:new(MochiReq:get(socket),
@@ -415,7 +415,7 @@ path_to_list([<<"..">>|R], Acc, DotDotCount) when DotDotCount == 2 ->
     "false" ->
         path_to_list(R, [<<"..">>|Acc], DotDotCount+1);
     _Else ->
-        couch_log:log(notice, "insecure_rewrite_rule ~p blocked", [lists:reverse(Acc) ++ [<<"..">>] ++ R]),
+        couch_log:notice("insecure_rewrite_rule ~p blocked", [lists:reverse(Acc) ++ [<<"..">>] ++ R]),
         throw({insecure_rewrite_rule, "too many ../.. segments"})
     end;
 path_to_list([<<"..">>|R], Acc, DotDotCount) ->


[5/7] chttpd commit: updated refs/heads/1993-bigcouch-couch-mrview to 93c771d

Posted by ch...@apache.org.
Update _all_dbs to use couch_mrview


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

Branch: refs/heads/1993-bigcouch-couch-mrview
Commit: 4a154f7d3ec7d61a7a59a257f9cc2c55a0433bb2
Parents: e2d1e92
Author: Russell Branca <ch...@gmail.com>
Authored: Thu Mar 27 12:10:41 2014 -0700
Committer: Russell Branca <ch...@gmail.com>
Committed: Fri Mar 28 11:30:40 2014 -0700

----------------------------------------------------------------------
 src/chttpd_misc.erl | 40 ++++++++++++++++++++++++----------------
 1 file changed, 24 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/4a154f7d/src/chttpd_misc.erl
----------------------------------------------------------------------
diff --git a/src/chttpd_misc.erl b/src/chttpd_misc.erl
index 8c5f50e..01bddf7 100644
--- a/src/chttpd_misc.erl
+++ b/src/chttpd_misc.erl
@@ -89,34 +89,42 @@ handle_sleep_req(Req) ->
     send_method_not_allowed(Req, "GET,HEAD").
 
 handle_all_dbs_req(#httpd{method='GET'}=Req) ->
+    Args = couch_mrview_http:parse_params(Req, undefined),
     ShardDbName = config:get("mem3", "shard_db", "dbs"),
     %% shard_db is not sharded but mem3:shards treats it as an edge case
     %% so it can be pushed thru fabric
     {ok, Info} = fabric:get_db_info(ShardDbName),
     Etag = couch_httpd:make_etag({Info}),
-    chttpd:etag_respond(Req, Etag, fun() ->
+    {ok, Resp} = chttpd:etag_respond(Req, Etag, fun() ->
         {ok, Resp} = chttpd:start_delayed_json_response(Req, 200, [{"Etag",Etag}]),
-        fabric:all_docs(ShardDbName, fun all_dbs_callback/2,
-            {nil, Resp}, #mrargs{})
-    end);
+        VAcc = #vacc{req=Req,resp=Resp},
+        fabric:all_docs(ShardDbName, fun all_dbs_callback/2, VAcc, Args)
+    end),
+    case is_record(Resp, vacc) of
+        true -> {ok, Resp#vacc.resp};
+        _ -> {ok, Resp}
+    end;
 handle_all_dbs_req(Req) ->
     send_method_not_allowed(Req, "GET,HEAD").
 
-all_dbs_callback({total_and_offset, _Total, _Offset}, {_, Resp}) ->
-    {ok, Resp1} = chttpd:send_delayed_chunk(Resp, "["),
-    {ok, {"", Resp1}};
-all_dbs_callback({row, {Row}}, {Prepend, Resp}) ->
+all_dbs_callback({meta, _Meta}, #vacc{resp=Resp0}=Acc) ->
+    {ok, Resp1} = chttpd:send_delayed_chunk(Resp0, "["),
+    {ok, Acc#vacc{resp=Resp1}};
+all_dbs_callback({row, Row}, #vacc{resp=Resp0}=Acc) ->
+    Prepend = couch_mrview_http:prepend_val(Acc),
     case couch_util:get_value(id, Row) of <<"_design", _/binary>> ->
-        {ok, {Prepend, Resp}};
+        {ok, Acc};
     DbName ->
-        {ok, Resp1} = chttpd:send_delayed_chunk(Resp, [Prepend, ?JSON_ENCODE(DbName)]),
-        {ok, {",", Resp1}}
+        {ok, Resp1} = chttpd:send_delayed_chunk(Resp0, [Prepend, ?JSON_ENCODE(DbName)]),
+        {ok, Acc#vacc{prepend=",", resp=Resp1}}
     end;
-all_dbs_callback(complete, {_, Resp}) ->
-    {ok, Resp1} = chttpd:send_delayed_chunk(Resp, "]"),
-    chttpd:end_delayed_json_response(Resp1);
-all_dbs_callback({error, Reason}, {_, Resp}) ->
-    chttpd:send_delayed_error(Resp, Reason).
+all_dbs_callback(complete, #vacc{resp=Resp0}=Acc) ->
+    {ok, Resp1} = chttpd:send_delayed_chunk(Resp0, "]"),
+    {ok, Resp2} = chttpd:end_delayed_json_response(Resp1),
+    {ok, Acc#vacc{resp=Resp2}};
+all_dbs_callback({error, Reason}, #vacc{resp=Resp0}=Acc) ->
+    {ok, Resp1} = chttpd:send_delayed_error(Resp0, Reason),
+    {ok, Acc#vacc{resp=Resp1}}.
 
 handle_task_status_req(#httpd{method='GET'}=Req) ->
     {Replies, _BadNodes} = gen_server:multi_call(couch_task_status, all),


[7/7] chttpd commit: updated refs/heads/1993-bigcouch-couch-mrview to 93c771d

Posted by ch...@apache.org.
Switch to using couch_mrview for the chttpd design info endpoint

This also standardizes the output of design info to use the format
from CouchDB. In particular, this outputs {"name","foo"} as CouchDB
currently does, rather than the {"name","_design/foo"} that it did
previously.


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

Branch: refs/heads/1993-bigcouch-couch-mrview
Commit: 93c771d6ffd331389f7352b5122ee3a360c16972
Parents: b858f5a
Author: Russell Branca <ch...@gmail.com>
Authored: Thu Mar 27 12:12:58 2014 -0700
Committer: Russell Branca <ch...@gmail.com>
Committed: Fri Mar 28 11:30:40 2014 -0700

----------------------------------------------------------------------
 src/chttpd_db.erl | 43 +++++++++++++++++--------------------------
 1 file changed, 17 insertions(+), 26 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/93c771d6/src/chttpd_db.erl
----------------------------------------------------------------------
diff --git a/src/chttpd_db.erl b/src/chttpd_db.erl
index 0f2c5e3..0c08dd9 100644
--- a/src/chttpd_db.erl
+++ b/src/chttpd_db.erl
@@ -12,6 +12,7 @@
 
 -module(chttpd_db).
 -include_lib("couch/include/couch_db.hrl").
+-include_lib("couch_mrview/include/couch_mrview.hrl").
 
 -export([handle_request/1, handle_compact_req/2, handle_design_req/2,
     db_req/2, couch_doc_open/4,handle_changes_req/2,
@@ -162,10 +163,11 @@ handle_design_req(Req, Db) ->
 bad_action_req(#httpd{path_parts=[_, _, Name|FileNameParts]}=Req, Db, _DDoc) ->
     db_attachment_req(Req, Db, <<"_design/",Name/binary>>, FileNameParts).
 
-handle_design_info_req(#httpd{method='GET'}=Req, Db, #doc{id=Id} = DDoc) ->
+handle_design_info_req(#httpd{method='GET'}=Req, Db, #doc{} = DDoc) ->
+    [_, _, Name, _] = Req#httpd.path_parts,
     {ok, GroupInfoList} = fabric:get_view_group_info(Db, DDoc),
     send_json(Req, 200, {[
-        {name,  Id},
+        {name,  Name},
         {view_index, {GroupInfoList}}
     ]});
 
@@ -477,30 +479,19 @@ db_req(#httpd{path_parts=[_, DocId | FileNameParts]}=Req, Db) ->
     db_attachment_req(Req, Db, DocId, FileNameParts).
 
 all_docs_view(Req, Db, Keys) ->
-    % measure the time required to generate the etag, see if it's worth it
-    T0 = os:timestamp(),
-    {ok, Info} = fabric:get_db_info(Db),
-    Etag = couch_httpd:make_etag(Info),
-    DeltaT = timer:now_diff(os:timestamp(), T0) / 1000,
-    couch_stats_collector:record({couchdb, dbinfo}, DeltaT),
-    QueryArgs = chttpd_view:parse_view_params(Req, Keys, map),
-    chttpd:etag_respond(Req, Etag, fun() ->
-        {ok, Resp} = chttpd:start_delayed_json_response(Req, 200, [{"Etag",Etag}]),
-        fabric:all_docs(Db, fun all_docs_callback/2, {nil, Resp}, QueryArgs)
-    end).
-
-all_docs_callback({total_and_offset, Total, Offset}, {_, Resp}) ->
-    Chunk = "{\"total_rows\":~p,\"offset\":~p,\"rows\":[\r\n",
-    {ok, Resp1} = chttpd:send_delayed_chunk(Resp, io_lib:format(Chunk, [Total, Offset])),
-    {ok, {"", Resp1}};
-all_docs_callback({row, Row}, {Prepend, Resp}) ->
-    {ok, Resp1} = chttpd:send_delayed_chunk(Resp, [Prepend, ?JSON_ENCODE(Row)]),
-    {ok, {",\r\n", Resp1}};
-all_docs_callback(complete, {_, Resp}) ->
-    {ok, Resp1} = chttpd:send_delayed_chunk(Resp, "\r\n]}"),
-    chttpd:end_delayed_json_response(Resp1);
-all_docs_callback({error, Reason}, {_, Resp}) ->
-    chttpd:send_delayed_error(Resp, Reason).
+    Args0 = couch_mrview_http:parse_params(Req, Keys),
+    ETagFun = fun(Sig, Acc0) ->
+        couch_mrview_http:check_view_etag(Sig, Acc0, Req)
+    end,
+    Args = Args0#mrargs{preflight_fun=ETagFun},
+    {ok, Resp} = couch_httpd:etag_maybe(Req, fun() ->
+        VAcc0 = #vacc{db=Db, req=Req},
+        fabric:all_docs(Db, fun couch_mrview_http:view_cb/2, VAcc0, Args)
+    end),
+    case is_record(Resp, vacc) of
+        true -> {ok, Resp#vacc.resp};
+        _ -> {ok, Resp}
+    end.
 
 db_doc_req(#httpd{method='DELETE'}=Req, Db, DocId) ->
     % check for the existence of the doc to handle the 404 case.


[4/7] chttpd commit: updated refs/heads/1993-bigcouch-couch-mrview to 93c771d

Posted by ch...@apache.org.
Use couch_mrview for view logic and callbacks

This updates the various view functions to use couch_mrview utility
functions, and removes a large amount of the view utility functions
that are better served by couch_mrview. It also uses the view
callbacks from couch_mrview, removing even more logic from this
module.


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

Branch: refs/heads/1993-bigcouch-couch-mrview
Commit: e2d1e926d3a224d0adb48b9ea1bbd764b4128152
Parents: faaf44e
Author: Russell Branca <ch...@gmail.com>
Authored: Thu Mar 27 12:10:11 2014 -0700
Committer: Russell Branca <ch...@gmail.com>
Committed: Fri Mar 28 11:30:39 2014 -0700

----------------------------------------------------------------------
 src/chttpd_view.erl | 428 +++++++----------------------------------------
 1 file changed, 61 insertions(+), 367 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/e2d1e926/src/chttpd_view.erl
----------------------------------------------------------------------
diff --git a/src/chttpd_view.erl b/src/chttpd_view.erl
index 85b88a3..471c380 100644
--- a/src/chttpd_view.erl
+++ b/src/chttpd_view.erl
@@ -14,117 +14,81 @@
 -include_lib("couch/include/couch_db.hrl").
 -include_lib("couch_mrview/include/couch_mrview.hrl").
 
--export([handle_view_req/3, handle_temp_view_req/2, get_reduce_type/1,
-    parse_view_params/3, view_group_etag/2, view_group_etag/3,
-    parse_bool_param/1, extract_view_type/3]).
-
+-export([handle_view_req/3, handle_temp_view_req/2]).
 
 multi_query_view(Req, Db, DDoc, ViewName, Queries) ->
-    Group = couch_view_group:design_doc_to_view_group(DDoc),
-    IsReduce = get_reduce_type(Req),
-    ViewType = extract_view_type(ViewName, couch_view_group:get_views(Group),
-        IsReduce),
-    % TODO proper calculation of etag
-    % Etag = view_group_etag(ViewGroup, Db, Queries),
-    Etag = couch_uuids:new(),
-    DefaultParams = lists:flatmap(fun({K,V}) -> parse_view_param(K,V) end,
-        chttpd:qs(Req)),
-    [couch_stats_collector:increment({httpd, view_reads}) || _I <- Queries],
-    chttpd:etag_respond(Req, Etag, fun() ->
+    Args0 = couch_mrview_http:parse_params(Req, undefined),
+    DbName = mem3:dbname(Db#db.name),
+    Args1 = couch_util:with_db(DbName, fun(WDb) ->
+        {ok, _, _, Args} = couch_mrview_util:get_view(WDb, DDoc, ViewName, Args0),
+        Args
+    end),
+    ArgQueries = lists:map(fun({Query}) ->
+        QueryArg = couch_mrview_http:parse_params(Query, undefined, Args1),
+        couch_mrview_util:validate_args(QueryArg)
+    end, Queries),
+    {ok, Resp2} = couch_httpd:etag_maybe(Req, fun() ->
+        VAcc0 = #vacc{db=Db, req=Req, prepend="\r\n"},
+        %% TODO: proper calculation of etag
+        Etag = couch_uuids:new(),
+        Headers = [{"ETag", Etag}],
         FirstChunk = "{\"results\":[",
-        {ok, Resp} = chttpd:start_delayed_json_response(Req, 200, [{"Etag",Etag}], FirstChunk),
-        {_, Resp1} = lists:foldl(fun({QueryProps}, {Chunk, RespAcc}) ->
-            if Chunk =/= nil -> chttpd:send_delayed_chunk(Resp, Chunk); true -> ok end,
-            ThisQuery = lists:flatmap(fun parse_json_view_param/1, QueryProps),
-            FullParams = lists:ukeymerge(1, ThisQuery, DefaultParams),
-            {ok, RespAcc1} = fabric:query_view(
-                Db,
-                DDoc,
-                ViewName,
-                fun view_callback/2,
-                {nil, RespAcc},
-                parse_view_params(FullParams, nil, ViewType)
-            ),
-            {",\n", RespAcc1}
-        end, {nil,Resp}, Queries),
-        chttpd:send_delayed_chunk(Resp1, "]}"),
-        chttpd:end_delayed_json_response(Resp1)
-    end).
-
-design_doc_view(Req, Db, DDoc, ViewName, Keys) ->
-    Group = couch_view_group:design_doc_to_view_group(DDoc),
-    IsReduce = get_reduce_type(Req),
-    ViewType = extract_view_type(ViewName, couch_view_group:get_views(Group),
-        IsReduce),
-    QueryArgs = parse_view_params(Req, Keys, ViewType),
-    % TODO proper calculation of etag
-    % Etag = view_group_etag(ViewGroup, Db, Keys),
-    Etag = couch_uuids:new(),
-    couch_stats_collector:increment({httpd, view_reads}),
-    chttpd:etag_respond(Req, Etag, fun() ->
-        {ok, Resp} = chttpd:start_delayed_json_response(Req, 200, [{"Etag",Etag}]),
-        CB = fun view_callback/2,
-        {ok, Resp1} = fabric:query_view(Db, DDoc, ViewName, CB, {nil, Resp}, QueryArgs),
-        chttpd:end_delayed_json_response(Resp1)
-    end).
+        {ok, Resp0} = chttpd:start_delayed_json_response(VAcc0#vacc.req, 200, Headers, FirstChunk),
+        VAcc1 = VAcc0#vacc{resp=Resp0},
+        VAcc2 = lists:foldl(fun(Args, Acc0) ->
+            {ok, Acc1} = fabric:query_view(Db, DDoc, ViewName, fun couch_mrview_http:view_cb/2, Acc0, Args),
+            Acc1
+        end, VAcc1, ArgQueries),
+        {ok, Resp1} = chttpd:send_delayed_chunk(VAcc2#vacc.resp, "\r\n]}"),
+        {ok, Resp2} = chttpd:end_delayed_json_response(Resp1),
+        {ok, VAcc2#vacc{resp=Resp2}}
+    end),
+    case is_record(Resp2, vacc) of
+        true -> {ok, Resp2#vacc.resp};
+        _ -> {ok, Resp2}
+    end.
 
-view_callback({total_and_offset, Total, Offset}, {nil, Resp}) ->
-    Chunk = "{\"total_rows\":~p,\"offset\":~p,\"rows\":[\r\n",
-    {ok, Resp1} = chttpd:send_delayed_chunk(Resp, io_lib:format(Chunk, [Total, Offset])),
-    {ok, {"", Resp1}};
-view_callback({total_and_offset, _, _}, Acc) ->
-    % a sorted=false view where the message came in late.  Ignore.
-    {ok, Acc};
-view_callback({row, Row}, {nil, Resp}) ->
-    % first row of a reduce view, or a sorted=false view
-    {ok, Resp1} = chttpd:send_delayed_chunk(Resp, ["{\"rows\":[\r\n", ?JSON_ENCODE(Row)]),
-    {ok, {",\r\n", Resp1}};
-view_callback({row, Row}, {Prepend, Resp}) ->
-    {ok, Resp1} = chttpd:send_delayed_chunk(Resp, [Prepend, ?JSON_ENCODE(Row)]),
-    {ok, {",\r\n", Resp1}};
-view_callback(complete, {nil, Resp}) ->
-    chttpd:send_delayed_chunk(Resp, "{\"rows\":[]}");
-view_callback(complete, {_, Resp}) ->
-    chttpd:send_delayed_chunk(Resp, "\r\n]}");
-view_callback({error, Reason}, {_, Resp}) ->
-    chttpd:send_delayed_error(Resp, Reason).
 
-extract_view_type(_ViewName, [], _IsReduce) ->
-    throw({not_found, missing_named_view});
-extract_view_type(ViewName, [View|Rest], IsReduce) ->
-    case lists:member(ViewName, [Name || {Name, _} <- View#mrview.reduce_funs]) of
-    true ->
-        if IsReduce -> reduce; true -> red_map end;
-    false ->
-        case lists:member(ViewName, View#mrview.map_names) of
-        true -> map;
-        false -> extract_view_type(ViewName, Rest, IsReduce)
-        end
+design_doc_view(Req, Db, DDoc, ViewName, Keys) ->
+    Args0 = couch_mrview_http:parse_params(Req, Keys),
+    ETagFun = fun(Sig, Acc0) ->
+        couch_mrview_http:check_view_etag(Sig, Acc0, Req)
+    end,
+    Args = Args0#mrargs{preflight_fun=ETagFun},
+    {ok, Resp} = couch_httpd:etag_maybe(Req, fun() ->
+        VAcc0 = #vacc{db=Db, req=Req},
+        fabric:query_view(Db, DDoc, ViewName, fun couch_mrview_http:view_cb/2, VAcc0, Args)
+    end),
+    case is_record(Resp, vacc) of
+        true -> {ok, Resp#vacc.resp};
+        _ -> {ok, Resp}
     end.
 
 handle_view_req(#httpd{method='GET',
         path_parts=[_, _, _, _, ViewName]}=Req, Db, DDoc) ->
-    Keys = chttpd:qs_json_value(Req, "keys", nil),
+    couch_stats_collector:increment({httpd, view_reads}),
+    Keys = chttpd:qs_json_value(Req, "keys", undefined),
     design_doc_view(Req, Db, DDoc, ViewName, Keys);
 
 handle_view_req(#httpd{method='POST',
         path_parts=[_, _, _, _, ViewName]}=Req, Db, DDoc) ->
-    {Fields} = chttpd:json_body_obj(Req),
-    Queries = couch_util:get_value(<<"queries">>, Fields),
-    Keys = couch_util:get_value(<<"keys">>, Fields),
+    Props = couch_httpd:json_body_obj(Req),
+    Keys = couch_mrview_util:get_view_keys(Props),
+    Queries = couch_mrview_util:get_view_queries(Props),
     case {Queries, Keys} of
-    {Queries, undefined} when is_list(Queries) ->
-        multi_query_view(Req, Db, DDoc, ViewName, Queries);
-    {undefined, Keys} when is_list(Keys) ->
-        design_doc_view(Req, Db, DDoc, ViewName, Keys);
-    {undefined, undefined} ->
-        throw({bad_request, "POST body must contain `keys` or `queries` field"});
-    {undefined, _} ->
-        throw({bad_request, "`keys` body member must be an array"});
-    {_, undefined} ->
-        throw({bad_request, "`queries` body member must be an array"});
-    {_, _} ->
-        throw({bad_request, "`keys` and `queries` are mutually exclusive"})
+        {Queries, undefined} when is_list(Queries) ->
+            [couch_stats_collector:increment({httpd, view_reads}) || _I <- Queries],
+            multi_query_view(Req, Db, DDoc, ViewName, Queries);
+        {undefined, Keys} when is_list(Keys) ->
+            couch_stats_collector:increment({httpd, view_reads}),
+            design_doc_view(Req, Db, DDoc, ViewName, Keys);
+        {undefined, undefined} ->
+            throw({
+                bad_request,
+                "POST body must contain `keys` or `queries` field"
+            });
+        {_, _} ->
+            throw({bad_request, "`keys` and `queries` are mutually exclusive"})
     end;
 
 handle_view_req(Req, _Db, _DDoc) ->
@@ -133,273 +97,3 @@ handle_view_req(Req, _Db, _DDoc) ->
 handle_temp_view_req(Req, _Db) ->
     Msg = <<"Temporary views are not supported in CouchDB">>,
     chttpd:send_error(Req, 403, forbidden, Msg).
-
-reverse_key_default(?MIN_STR) -> ?MAX_STR;
-reverse_key_default(?MAX_STR) -> ?MIN_STR;
-reverse_key_default(Key) -> Key.
-
-get_reduce_type(Req) ->
-    case chttpd:qs_value(Req, "reduce", "true") of
-    "true" ->
-        true;
-    "false" ->
-        false;
-    _Error ->
-        throw({bad_request, "`reduce` qs param must be `true` or `false`"})
-    end.
-
-parse_view_params(Req, Keys, ViewType) when not is_list(Req) ->
-    QueryParams = lists:flatmap(fun({K,V}) -> parse_view_param(K,V) end,
-        chttpd:qs(Req)),
-    parse_view_params(QueryParams, Keys, ViewType);
-parse_view_params(QueryParams, Keys, ViewType) ->
-    IsMultiGet = (Keys =/= nil),
-    Args = #mrargs{
-        view_type=ViewType,
-        multi_get=IsMultiGet,
-        keys=Keys
-    },
-    QueryArgs = lists:foldl(fun({K, V}, Args2) ->
-        validate_view_query(K, V, Args2)
-    end, Args, QueryParams),
-
-    GroupLevel = QueryArgs#mrargs.group_level,
-    case {ViewType, GroupLevel, IsMultiGet} of
-        {reduce, exact, true} ->
-            QueryArgs;
-        {reduce, _, false} ->
-            QueryArgs;
-        {reduce, _, _} ->
-            Msg = <<"Multi-key fetchs for reduce "
-                    "view must include `group=true`">>,
-            throw({query_parse_error, Msg});
-        _ ->
-            QueryArgs
-    end,
-    QueryArgs.
-
-parse_json_view_param({<<"key">>, V}) ->
-    [{start_key, V}, {end_key, V}];
-parse_json_view_param({<<"startkey_docid">>, V}) ->
-    [{start_key_docid, V}];
-parse_json_view_param({<<"endkey_docid">>, V}) ->
-    [{end_key_docid, V}];
-parse_json_view_param({<<"startkey">>, V}) ->
-    [{start_key, V}];
-parse_json_view_param({<<"endkey">>, V}) ->
-    [{end_key, V}];
-parse_json_view_param({<<"limit">>, V}) when is_integer(V), V > 0 ->
-    [{limit, V}];
-parse_json_view_param({<<"stale">>, <<"ok">>}) ->
-    [{stale, ok}];
-parse_json_view_param({<<"stale">>, <<"update_after">>}) ->
-    [{stale, update_after}];
-parse_json_view_param({<<"descending">>, V}) when is_boolean(V) ->
-    [{descending, V}];
-parse_json_view_param({<<"skip">>, V}) when is_integer(V) ->
-    [{skip, V}];
-parse_json_view_param({<<"group">>, true}) ->
-    [{group_level, exact}];
-parse_json_view_param({<<"group">>, false}) ->
-    [{group_level, 0}];
-parse_json_view_param({<<"group_level">>, V}) when is_integer(V), V > 0 ->
-    [{group_level, V}];
-parse_json_view_param({<<"inclusive_end">>, V}) when is_boolean(V) ->
-    [{inclusive_end, V}];
-parse_json_view_param({<<"reduce">>, V}) when is_boolean(V) ->
-    [{reduce, V}];
-parse_json_view_param({<<"include_docs">>, V}) when is_boolean(V) ->
-    [{include_docs, V}];
-parse_json_view_param({<<"conflicts">>, V}) when is_boolean(V) ->
-    [{conflicts, V}];
-parse_json_view_param({<<"list">>, V}) ->
-    [{list, couch_util:to_binary(V)}];
-parse_json_view_param({<<"sorted">>, V}) when is_boolean(V) ->
-    [{sorted, V}];
-parse_json_view_param({K, V}) ->
-    [{extra, {K, V}}].
-
-parse_view_param("", _) ->
-    [];
-parse_view_param("key", Value) ->
-    JsonKey = ?JSON_DECODE(Value),
-    [{start_key, JsonKey}, {end_key, JsonKey}];
-parse_view_param("startkey_docid", Value) ->
-    [{start_key_docid, ?l2b(Value)}];
-parse_view_param("endkey_docid", Value) ->
-    [{end_key_docid, ?l2b(Value)}];
-parse_view_param("startkey", Value) ->
-    [{start_key, ?JSON_DECODE(Value)}];
-parse_view_param("endkey", Value) ->
-    [{end_key, ?JSON_DECODE(Value)}];
-parse_view_param("limit", Value) ->
-    [{limit, parse_positive_int_param(Value)}];
-parse_view_param("count", _Value) ->
-    throw({query_parse_error, <<"Query parameter 'count' is now 'limit'.">>});
-parse_view_param("stale", "ok") ->
-    [{stale, ok}];
-parse_view_param("stale", "update_after") ->
-    [{stale, update_after}];
-parse_view_param("stale", _Value) ->
-    throw({query_parse_error,
-            <<"stale only available as stale=ok or as stale=update_after">>});
-parse_view_param("update", _Value) ->
-    throw({query_parse_error, <<"update=false is now stale=ok">>});
-parse_view_param("descending", Value) ->
-    [{descending, parse_bool_param(Value)}];
-parse_view_param("skip", Value) ->
-    [{skip, parse_int_param(Value)}];
-parse_view_param("group", Value) ->
-    case parse_bool_param(Value) of
-        true -> [{group_level, exact}];
-        false -> [{group_level, 0}]
-    end;
-parse_view_param("group_level", Value) ->
-    [{group_level, parse_positive_int_param(Value)}];
-parse_view_param("inclusive_end", Value) ->
-    [{inclusive_end, parse_bool_param(Value)}];
-parse_view_param("reduce", Value) ->
-    [{reduce, parse_bool_param(Value)}];
-parse_view_param("include_docs", Value) ->
-    [{include_docs, parse_bool_param(Value)}];
-parse_view_param("conflicts", Value) ->
-    [{conflicts, parse_bool_param(Value)}];
-parse_view_param("list", Value) ->
-    [{list, ?l2b(Value)}];
-parse_view_param("callback", _) ->
-    []; % Verified in the JSON response functions
-parse_view_param("sorted", Value) ->
-    [{sorted, parse_bool_param(Value)}];
-parse_view_param(Key, Value) ->
-    [{extra, {Key, Value}}].
-
-validate_view_query(start_key, Value, Args) ->
-    case Args#mrargs.multi_get of
-        true ->
-            Msg = <<"Query parameter `start_key` is "
-                    "not compatiible with multi-get">>,
-            throw({query_parse_error, Msg});
-        _ ->
-            Args#mrargs{start_key=Value}
-    end;
-validate_view_query(start_key_docid, Value, Args) ->
-    Args#mrargs{start_key_docid=Value};
-validate_view_query(end_key, Value, Args) ->
-    case Args#mrargs.multi_get of
-        true->
-            Msg = <<"Query paramter `end_key` is "
-                    "not compatibile with multi-get">>,
-            throw({query_parse_error, Msg});
-        _ ->
-            Args#mrargs{end_key=Value}
-    end;
-validate_view_query(end_key_docid, Value, Args) ->
-    Args#mrargs{end_key_docid=Value};
-validate_view_query(limit, Value, Args) ->
-    Args#mrargs{limit=Value};
-validate_view_query(list, Value, Args) ->
-    Args#mrargs{list=Value};
-validate_view_query(stale, Value, Args) ->
-    Args#mrargs{stale=Value};
-validate_view_query(descending, true, Args) ->
-    case Args#mrargs.direction of
-        rev -> Args; % Already reversed
-        fwd ->
-            Args#mrargs{
-                direction = rev,
-                start_key_docid =
-                    reverse_key_default(Args#mrargs.start_key_docid),
-                end_key_docid =
-                    reverse_key_default(Args#mrargs.end_key_docid)
-            }
-    end;
-validate_view_query(descending, false, Args) ->
-    Args; % Ignore default condition
-validate_view_query(skip, Value, Args) ->
-    Args#mrargs{skip=Value};
-validate_view_query(group_level, Value, Args) ->
-    case Args#mrargs.view_type of
-        reduce ->
-            Args#mrargs{group_level=Value};
-        _ ->
-            Msg = <<"Invalid URL parameter 'group' or "
-                    " 'group_level' for non-reduce view.">>,
-            throw({query_parse_error, Msg})
-    end;
-validate_view_query(inclusive_end, Value, Args) ->
-    Args#mrargs{inclusive_end=Value};
-validate_view_query(reduce, false, Args) ->
-    Args;
-validate_view_query(reduce, _, Args) ->
-    case Args#mrargs.view_type of
-        map ->
-            Msg = <<"Invalid URL parameter `reduce` for map view.">>,
-            throw({query_parse_error, Msg});
-        _ ->
-            Args
-    end;
-validate_view_query(include_docs, true, Args) ->
-    case Args#mrargs.view_type of
-        reduce ->
-            Msg = <<"Query paramter `include_docs` "
-                    "is invalid for reduce views.">>,
-            throw({query_parse_error, Msg});
-        _ ->
-            Args#mrargs{include_docs=true}
-    end;
-validate_view_query(include_docs, _Value, Args) ->
-    Args;
-validate_view_query(conflicts, true, Args) ->
-    case Args#mrargs.view_type of
-    reduce ->
-        Msg = <<"Query parameter `conflicts` "
-                "is invalid for reduce views.">>,
-        throw({query_parse_error, Msg});
-    _ ->
-        Args#mrargs{extra = [conflicts|Args#mrargs.extra]}
-    end;
-validate_view_query(conflicts, _Value, Args) ->
-    Args;
-validate_view_query(sorted, false, Args) ->
-    Args#mrargs{sorted=false};
-validate_view_query(sorted, _Value, Args) ->
-    Args;
-validate_view_query(extra, _Value, Args) ->
-    Args.
-
-view_group_etag(Group, Db) ->
-    view_group_etag(Group, Db, nil).
-
-view_group_etag(Group, _Db, Extra) ->
-    Sig = couch_view_group:get_signature(Group),
-    CurrentSeq = couch_view_group:get_current_seq(Group),
-    % This is not as granular as it could be.
-    % If there are updates to the db that do not effect the view index,
-    % they will change the Etag. For more granular Etags we'd need to keep
-    % track of the last Db seq that caused an index change.
-    chttpd:make_etag({Sig, CurrentSeq, Extra}).
-
-parse_bool_param("true") -> true;
-parse_bool_param("false") -> false;
-parse_bool_param(Val) ->
-    Msg = io_lib:format("Invalid value for boolean paramter: ~p", [Val]),
-    throw({query_parse_error, ?l2b(Msg)}).
-
-parse_int_param(Val) ->
-    case (catch list_to_integer(Val)) of
-    IntVal when is_integer(IntVal) ->
-        IntVal;
-    _ ->
-        Msg = io_lib:format("Invalid value for integer parameter: ~p", [Val]),
-        throw({query_parse_error, ?l2b(Msg)})
-    end.
-
-parse_positive_int_param(Val) ->
-    case parse_int_param(Val) of
-    IntVal when IntVal >= 0 ->
-        IntVal;
-    _ ->
-        Fmt = "Invalid value for positive integer parameter: ~p",
-        Msg = io_lib:format(Fmt, [Val]),
-        throw({query_parse_error, ?l2b(Msg)})
-    end.