diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/couchdb/couch_httpd.erl | 10 | ||||
-rw-r--r-- | src/couchdb/couch_httpd_db.erl | 77 | ||||
-rw-r--r-- | src/couchdb/couch_httpd_misc_handlers.erl | 2 | ||||
-rw-r--r-- | src/couchdb/couch_httpd_view.erl | 24 |
4 files changed, 47 insertions, 66 deletions
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), |