diff options
author | jiangphcn <jiangph@cn.ibm.com> | 2017-04-21 18:18:18 +0800 |
---|---|---|
committer | jiangphcn <jiangph@cn.ibm.com> | 2017-04-24 11:13:02 +0800 |
commit | 5713b30e0e1e3d86cd41a3adbcf878b7ed214873 (patch) | |
tree | 14f87db5cfee032e5d544b30af8bfa030def6037 | |
parent | 7547e7fbcfb2ac8e3cfe3de98c225a8208fb1af7 (diff) | |
download | couchdb-5713b30e0e1e3d86cd41a3adbcf878b7ed214873.tar.gz |
Avoid creation of document if deleting attachment on non-existent doc
- Check existence of document before deleting its attachment
- if document doesn’t exist, return 404 instead of creating new
document
Fixes COUCHDB-3362/FB 85549
-rw-r--r-- | src/chttpd/src/chttpd_db.erl | 4 | ||||
-rw-r--r-- | src/chttpd/test/chttpd_db_test.erl | 84 | ||||
-rw-r--r-- | src/couch/src/couch_httpd_db.erl | 4 |
3 files changed, 91 insertions, 1 deletions
diff --git a/src/chttpd/src/chttpd_db.erl b/src/chttpd/src/chttpd_db.erl index 37e466908..902b5b95b 100644 --- a/src/chttpd/src/chttpd_db.erl +++ b/src/chttpd/src/chttpd_db.erl @@ -1236,6 +1236,10 @@ db_attachment_req(#httpd{method=Method, user_ctx=Ctx}=Req, Db, DocId, FileNamePa Doc = case extract_header_rev(Req, chttpd:qs_value(Req, "rev")) of missing_rev -> % make the new doc + if Method =/= 'DELETE' -> ok; true -> + % check for the existence of the doc to handle the 404 case. + couch_doc_open(Db, DocId, nil, []) + end, couch_doc:validate_docid(DocId), #doc{id=DocId}; Rev -> diff --git a/src/chttpd/test/chttpd_db_test.erl b/src/chttpd/test/chttpd_db_test.erl index be091f9c3..b7ea7f006 100644 --- a/src/chttpd/test/chttpd_db_test.erl +++ b/src/chttpd/test/chttpd_db_test.erl @@ -19,6 +19,7 @@ -define(PASS, "pass"). -define(AUTH, {basic_auth, {?USER, ?PASS}}). -define(CONTENT_JSON, {"Content-Type", "application/json"}). +-define(FIXTURE_TXT, ?ABS_PATH(?FILE)). setup() -> ok = config:set("admins", ?USER, ?PASS, _Persist=false), @@ -56,7 +57,10 @@ all_test_() -> fun setup/0, fun teardown/1, [ fun should_return_ok_true_on_bulk_update/1, - fun should_accept_live_as_an_alias_for_continuous/1 + fun should_accept_live_as_an_alias_for_continuous/1, + fun should_return_404_for_delete_att_on_notadoc/1, + fun should_return_409_for_del_att_without_rev/1, + fun should_return_200_for_del_att_with_rev/1 ] } } @@ -97,3 +101,81 @@ should_accept_live_as_an_alias_for_continuous(Url) -> ?assertEqual(LastSeqNum + 1, SeqNum) end). + + +should_return_404_for_delete_att_on_notadoc(Url) -> + ?_test(begin + {ok, RC, _, RespBody} = test_request:delete( + Url ++ "/notadoc/att.pdf", + [?CONTENT_JSON, ?AUTH], + [] + ), + ?assertEqual(404, RC), + ?assertEqual( + {[{<<"error">>,<<"not_found">>}, + {<<"reason">>,<<"missing">>}]}, + jiffy:decode(RespBody) + ), + {ok, RC1, _, _} = test_request:get( + Url ++ "/notadoc", + [?CONTENT_JSON, ?AUTH], + [] + ), + ?assertEqual(404, RC1) + end). + + +should_return_409_for_del_att_without_rev(Url) -> + ?_test(begin + {ok, Data} = file:read_file(?FIXTURE_TXT), + Doc = {[ + {<<"_attachments">>, {[ + {<<"file.erl">>, {[ + {<<"content_type">>, <<"text/plain">>}, + {<<"data">>, base64:encode(Data)} + ]} + }]}} + ]}, + {ok, RC, _, _} = test_request:put( + Url ++ "/testdoc3", + [?CONTENT_JSON, ?AUTH], + jiffy:encode(Doc) + ), + ?assertEqual(201, RC), + + {ok, RC1, _, _} = test_request:delete( + Url ++ "/testdoc3/file.erl", + [?CONTENT_JSON, ?AUTH], + [] + ), + ?assertEqual(409, RC1) + end). + +should_return_200_for_del_att_with_rev(Url) -> + ?_test(begin + {ok, Data} = file:read_file(?FIXTURE_TXT), + Doc = {[ + {<<"_attachments">>, {[ + {<<"file.erl">>, {[ + {<<"content_type">>, <<"text/plain">>}, + {<<"data">>, base64:encode(Data)} + ]} + }]}} + ]}, + {ok, RC, _Headers, RespBody} = test_request:put( + Url ++ "/testdoc4", + [?CONTENT_JSON, ?AUTH], + jiffy:encode(Doc) + ), + ?assertEqual(201, RC), + + {ResultJson} = ?JSON_DECODE(RespBody), + Rev = couch_util:get_value(<<"rev">>, ResultJson, undefined), + + {ok, RC1, _, _} = test_request:delete( + Url ++ "/testdoc4/file.erl?rev=" ++ Rev, + [?CONTENT_JSON, ?AUTH], + [] + ), + ?assertEqual(200, RC1) + end). diff --git a/src/couch/src/couch_httpd_db.erl b/src/couch/src/couch_httpd_db.erl index e1af1bfdc..a6d83d619 100644 --- a/src/couch/src/couch_httpd_db.erl +++ b/src/couch/src/couch_httpd_db.erl @@ -1013,6 +1013,10 @@ db_attachment_req(#httpd{method=Method,mochi_req=MochiReq}=Req, Db, DocId, FileN Doc = case extract_header_rev(Req, couch_httpd:qs_value(Req, "rev")) of missing_rev -> % make the new doc + if Method =/= 'DELETE' -> ok; true -> + % check for the existence of the doc to handle the 404 case. + couch_doc_open(Db, DocId, nil, []) + end, couch_doc:validate_docid(DocId), #doc{id=DocId}; Rev -> |