summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--share/www/script/test/basics.js4
-rw-r--r--share/www/script/test/view_errors.js2
-rw-r--r--src/couchdb/couch_httpd.erl10
-rw-r--r--src/couchdb/couch_httpd_db.erl77
-rw-r--r--src/couchdb/couch_httpd_misc_handlers.erl2
-rw-r--r--src/couchdb/couch_httpd_view.erl24
6 files changed, 50 insertions, 69 deletions
diff --git a/share/www/script/test/basics.js b/share/www/script/test/basics.js
index 8e6d4c7a..00785dc8 100644
--- a/share/www/script/test/basics.js
+++ b/share/www/script/test/basics.js
@@ -204,14 +204,14 @@ couchTests.basics = function(debug) {
T(xhr.status == 400);
result = JSON.parse(xhr.responseText);
T(result.error == "bad_request");
- T(result.reason == "Body must be a JSON object");
+ T(result.reason == "Request body must be a JSON object");
// Body of an _all_docs multi-get is not a {"key": [...]} structure.
xhr = CouchDB.request("POST", "/test_suite_db/_all_docs", {body: "[]"});
T(xhr.status == 400);
result = JSON.parse(xhr.responseText);
T(result.error == "bad_request");
- T(result.reason == "Body must be a JSON object");
+ T(result.reason == "Request body must be a JSON object");
var data = "{\"keys\": 1}";
xhr = CouchDB.request("POST", "/test_suite_db/_all_docs", {body:data});
T(xhr.status == 400);
diff --git a/share/www/script/test/view_errors.js b/share/www/script/test/view_errors.js
index 1a613c04..ec0dcce6 100644
--- a/share/www/script/test/view_errors.js
+++ b/share/www/script/test/view_errors.js
@@ -123,7 +123,7 @@ couchTests.view_errors = function(debug) {
T(xhr.status == 400);
result = JSON.parse(xhr.responseText);
T(result.error == "bad_request");
- T(result.reason == "Body must be a JSON object");
+ T(result.reason == "Request body must be a JSON object");
var data = "{\"keys\": 1}";
xhr = CouchDB.request("POST", path, {body:data});
T(xhr.status == 400);
diff --git a/src/couchdb/couch_httpd.erl b/src/couchdb/couch_httpd.erl
index 5775e3a7..7a803c85 100644
--- a/src/couchdb/couch_httpd.erl
+++ b/src/couchdb/couch_httpd.erl
@@ -17,7 +17,7 @@
-export([header_value/2,header_value/3,qs_value/2,qs_value/3,qs/1,path/1,absolute_uri/2]).
-export([verify_is_server_admin/1,unquote/1,quote/1,recv/2,recv_chunked/4,error_info/1]).
--export([parse_form/1,json_body/1,body/1,doc_etag/1, make_etag/1, etag_respond/3]).
+-export([parse_form/1,json_body/1,json_body_obj/1,body/1,doc_etag/1, make_etag/1, etag_respond/3]).
-export([primary_header_value/2,partition/1,serve_file/3]).
-export([start_chunked_response/3,send_chunk/2]).
-export([start_json_response/2, start_json_response/3, end_json_response/1]).
@@ -299,6 +299,14 @@ body(#httpd{mochi_req=MochiReq}) ->
json_body(Httpd) ->
?JSON_DECODE(body(Httpd)).
+json_body_obj(Httpd) ->
+ case json_body(Httpd) of
+ {Props} -> {Props};
+ _Else ->
+ throw({bad_request, "Request body must be a JSON object"})
+ end.
+
+
doc_etag(#doc{revs={Start, [DiskRev|_]}}) ->
"\"" ++ ?b2l(couch_doc:rev_to_str({Start, DiskRev})) ++ "\"".
diff --git a/src/couchdb/couch_httpd_db.erl b/src/couchdb/couch_httpd_db.erl
index f603def0..dc0514b6 100644
--- a/src/couchdb/couch_httpd_db.erl
+++ b/src/couchdb/couch_httpd_db.erl
@@ -207,13 +207,7 @@ db_req(#httpd{path_parts=[_,<<"_ensure_full_commit">>]}=Req, _Db) ->
db_req(#httpd{method='POST',path_parts=[_,<<"_bulk_docs">>]}=Req, Db) ->
couch_stats_collector:increment({httpd, bulk_requests}),
- JsonProps =
- case couch_httpd:json_body(Req) of
- {Fields} ->
- Fields;
- _ ->
- throw({bad_request, "Body must be a JSON object"})
- end,
+ {JsonProps} = couch_httpd:json_body_obj(Req),
DocsArray = proplists:get_value(<<"docs">>, JsonProps),
case couch_httpd:header_value(Req, "X-Couch-Full-Commit", "false") of
"true" ->
@@ -249,47 +243,26 @@ db_req(#httpd{method='POST',path_parts=[_,<<"_bulk_docs">>]}=Req, Db) ->
case couch_db:update_docs(Db, Docs, Options2) of
{ok, Results} ->
% output the results
- DocResults = lists:zipwith(
- fun(Doc, {ok, NewRev}) ->
- {[{<<"id">>, Doc#doc.id}, {<<"rev">>, couch_doc:rev_to_str(NewRev)}]};
- (Doc, Error) ->
- {_Code, Err, Msg} = couch_httpd:error_info(Error),
- % maybe we should add the http error code to the json?
- {[{<<"id">>, Doc#doc.id}, {<<"error">>, Err}, {"reason", Msg}]}
- end,
+ DocResults = lists:zipwith(fun update_doc_result_to_json/2,
Docs, Results),
send_json(Req, 201, DocResults);
{aborted, Errors} ->
ErrorsJson =
- lists:map(
- fun({{Id, Rev}, Error}) ->
- {_Code, Err, Msg} = couch_httpd:error_info(Error),
- {[{<<"id">>, Id},
- {<<"rev">>, couch_doc:rev_to_str(Rev)},
- {<<"error">>, Err},
- {"reason", Msg}]}
- end, Errors),
+ lists:map(fun update_doc_result_to_json/1, Errors),
send_json(Req, 417, ErrorsJson)
end;
false ->
Docs = [couch_doc:from_json_obj(JsonObj) || JsonObj <- DocsArray],
{ok, Errors} = couch_db:update_docs(Db, Docs, Options, replicated_changes),
ErrorsJson =
- lists:map(
- fun({{Id, Rev}, Error}) ->
- {_Code, Err, Msg} = couch_httpd:error_info(Error),
- {[{<<"id">>, Id},
- {<<"rev">>, couch_doc:rev_to_str(Rev)},
- {<<"error">>, Err},
- {"reason", Msg}]}
- end, Errors),
+ lists:map(fun update_doc_result_to_json/1, Errors),
send_json(Req, 201, ErrorsJson)
end;
db_req(#httpd{path_parts=[_,<<"_bulk_docs">>]}=Req, _Db) ->
send_method_not_allowed(Req, "POST");
db_req(#httpd{method='POST',path_parts=[_,<<"_purge">>]}=Req, Db) ->
- {IdsRevs} = couch_httpd:json_body(Req),
+ {IdsRevs} = couch_httpd:json_body_obj(Req),
IdsRevs2 = [{Id, couch_doc:parse_revs(Revs)} || {Id, Revs} <- IdsRevs],
case couch_db:purge_docs(Db, IdsRevs2) of
@@ -307,19 +280,15 @@ db_req(#httpd{method='GET',path_parts=[_,<<"_all_docs">>]}=Req, Db) ->
all_docs_view(Req, Db, nil);
db_req(#httpd{method='POST',path_parts=[_,<<"_all_docs">>]}=Req, Db) ->
- case couch_httpd:json_body(Req) of
- {Fields} ->
- case proplists:get_value(<<"keys">>, Fields, nil) of
- nil ->
- ?LOG_DEBUG("POST to _all_docs with no keys member.", []),
- all_docs_view(Req, Db, nil);
- Keys when is_list(Keys) ->
- all_docs_view(Req, Db, Keys);
- _ ->
- throw({bad_request, "`keys` member must be a array."})
- end;
+ {Fields} = couch_httpd:json_body_obj(Req),
+ case proplists:get_value(<<"keys">>, Fields, nil) of
+ nil ->
+ ?LOG_DEBUG("POST to _all_docs with no keys member.", []),
+ all_docs_view(Req, Db, nil);
+ Keys when is_list(Keys) ->
+ all_docs_view(Req, Db, Keys);
_ ->
- throw({bad_request, "Body must be a JSON object"})
+ throw({bad_request, "`keys` member must be a array."})
end;
db_req(#httpd{path_parts=[_,<<"_all_docs">>]}=Req, _Db) ->
@@ -382,7 +351,7 @@ db_req(#httpd{path_parts=[_,<<"_all_docs_by_seq">>]}=Req, _Db) ->
send_method_not_allowed(Req, "GET,HEAD");
db_req(#httpd{method='POST',path_parts=[_,<<"_missing_revs">>]}=Req, Db) ->
- {JsonDocIdRevs} = couch_httpd:json_body(Req),
+ {JsonDocIdRevs} = couch_httpd:json_body_obj(Req),
JsonDocIdRevs2 = [{Id, [couch_doc:parse_rev(RevStr) || RevStr <- RevStrs]} || {Id, RevStrs} <- JsonDocIdRevs],
{ok, Results} = couch_db:get_missing_revs(Db, JsonDocIdRevs2),
Results2 = [{Id, [couch_doc:rev_to_str(Rev) || Rev <- Revs]} || {Id, Revs} <- Results],
@@ -640,7 +609,7 @@ db_doc_req(#httpd{method='COPY'}=Req, Db, SourceDocId) ->
case couch_db:update_doc(Db, Doc#doc{id=TargetDocId, revs=TargetRevs}, []) of
{ok, NewTargetRev} ->
send_json(Req, 201, [{"Etag", "\"" ++ ?b2l(couch_doc:rev_to_str(NewTargetRev)) ++ "\""}],
- update_result_to_json({ok, NewTargetRev}));
+ update_doc_result_to_json(TargetDocId, {ok, NewTargetRev}));
Error ->
throw(Error)
end;
@@ -648,11 +617,19 @@ db_doc_req(#httpd{method='COPY'}=Req, Db, SourceDocId) ->
db_doc_req(Req, _Db, _DocId) ->
send_method_not_allowed(Req, "DELETE,GET,HEAD,POST,PUT,COPY").
-update_result_to_json({ok, NewRev}) ->
- {[{rev, couch_doc:rev_to_str(NewRev)}]};
-update_result_to_json(Error) ->
+
+update_doc_result_to_json({{Id, Rev}, Error}) ->
+ {_Code, Err, Msg} = couch_httpd:error_info(Error),
+ {[{id, Id}, {rev, couch_doc:rev_to_str(Rev)},
+ {error, Err}, {reason, Msg}]}.
+
+update_doc_result_to_json(#doc{id=DocId}, Result) ->
+ update_doc_result_to_json(DocId, Result);
+update_doc_result_to_json(DocId, {ok, NewRev}) ->
+ {[{id, DocId}, {rev, couch_doc:rev_to_str(NewRev)}]};
+update_doc_result_to_json(DocId, Error) ->
{_Code, ErrorStr, Reason} = couch_httpd:error_info(Error),
- {[{error, ErrorStr}, {reason, Reason}]}.
+ {[{id, DocId}, {error, ErrorStr}, {reason, Reason}]}.
update_doc(Req, Db, DocId, Json) ->
diff --git a/src/couchdb/couch_httpd_misc_handlers.erl b/src/couchdb/couch_httpd_misc_handlers.erl
index fa42e9c3..d03cbd3f 100644
--- a/src/couchdb/couch_httpd_misc_handlers.erl
+++ b/src/couchdb/couch_httpd_misc_handlers.erl
@@ -91,7 +91,7 @@ get_rep_endpoint(#httpd{user_ctx=UserCtx}, <<DbName/binary>>) ->
{local, DbName, UserCtx}.
handle_replicate_req(#httpd{method='POST'}=Req) ->
- {Props} = couch_httpd:json_body(Req),
+ {Props} = couch_httpd:json_body_obj(Req),
Source = get_rep_endpoint(Req, proplists:get_value(<<"source">>, Props)),
Target = get_rep_endpoint(Req, proplists:get_value(<<"target">>, Props)),
case couch_rep:replicate(Source, Target) of
diff --git a/src/couchdb/couch_httpd_view.erl b/src/couchdb/couch_httpd_view.erl
index 7c13cdf2..016a391a 100644
--- a/src/couchdb/couch_httpd_view.erl
+++ b/src/couchdb/couch_httpd_view.erl
@@ -58,20 +58,16 @@ handle_view_req(#httpd{method='GET',
handle_view_req(#httpd{method='POST',
path_parts=[_Db, _Design, DName, _View, ViewName]}=Req, Db) ->
- case couch_httpd:json_body(Req) of
- {Fields} ->
- case proplists:get_value(<<"keys">>, Fields, nil) of
- nil ->
- Fmt = "POST to view ~p/~p in database ~p with no keys member.",
- ?LOG_DEBUG(Fmt, [DName, ViewName, Db]),
- design_doc_view(Req, Db, DName, ViewName, nil);
- Keys when is_list(Keys) ->
- design_doc_view(Req, Db, DName, ViewName, Keys);
- _ ->
- throw({bad_request, "`keys` member must be a array."})
- end;
+ {Fields} = couch_httpd:json_body_obj(Req),
+ case proplists:get_value(<<"keys">>, Fields, nil) of
+ nil ->
+ Fmt = "POST to view ~p/~p in database ~p with no keys member.",
+ ?LOG_DEBUG(Fmt, [DName, ViewName, Db]),
+ design_doc_view(Req, Db, DName, ViewName, nil);
+ Keys when is_list(Keys) ->
+ design_doc_view(Req, Db, DName, ViewName, Keys);
_ ->
- throw({bad_request, "Body must be a JSON object"})
+ throw({bad_request, "`keys` member must be a array."})
end;
handle_view_req(Req, _Db) ->
@@ -79,7 +75,7 @@ handle_view_req(Req, _Db) ->
handle_temp_view_req(#httpd{method='POST'}=Req, Db) ->
couch_stats_collector:increment({httpd, temporary_view_reads}),
- {Props} = couch_httpd:json_body(Req),
+ {Props} = couch_httpd:json_body_obj(Req),
Language = proplists:get_value(<<"language">>, Props, <<"javascript">>),
{DesignOptions} = proplists:get_value(<<"options">>, Props, {[]}),
MapSrc = proplists:get_value(<<"map">>, Props),