diff options
author | Robert Newson <rnewson@apache.org> | 2018-08-02 14:41:03 +0100 |
---|---|---|
committer | Robert Newson <rnewson@apache.org> | 2018-09-17 13:58:27 +0100 |
commit | 3aec64026f7a78720140c1ed37f39a80b092e3b9 (patch) | |
tree | a4da38664e4d1867e931838e43734d82d9662944 | |
parent | 77fd776f6310d1c60f4865af8820beaeb92f5c33 (diff) | |
download | couchdb-3aec64026f7a78720140c1ed37f39a80b092e3b9.tar.gz |
Enforce partition:id format in doc ids
Co-authored-by: Garren Smith <garren.smith@gmail.com>
Co-authored-by: Robert Newson <rnewson@apache.org>
-rw-r--r-- | src/chttpd/src/chttpd_db.erl | 34 | ||||
-rw-r--r-- | src/couch/src/couch_doc.erl | 26 | ||||
-rw-r--r-- | src/couch/test/fixtures/test.couch | bin | 16482 -> 0 bytes |
3 files changed, 46 insertions, 14 deletions
diff --git a/src/chttpd/src/chttpd_db.erl b/src/chttpd/src/chttpd_db.erl index 090555935..356825c74 100644 --- a/src/chttpd/src/chttpd_db.erl +++ b/src/chttpd/src/chttpd_db.erl @@ -414,16 +414,19 @@ db_req(#httpd{method='POST',path_parts=[_,<<"_bulk_docs">>], user_ctx=Ctx}=Req, _ -> Options = [{user_ctx,Ctx}, {w,W}] end, + DbName = couch_db:name(Db), + VOpts = [{partitioned, mem3:is_partitioned(DbName)}], case couch_util:get_value(<<"new_edits">>, JsonProps, true) of true -> Docs = lists:map( fun(JsonObj) -> - Doc = couch_doc:from_json_obj_validate(JsonObj), + Doc = couch_doc:from_json_obj_validate(JsonObj, DbName), validate_attachment_names(Doc), Id = case Doc#doc.id of <<>> -> couch_uuids:new(); Id0 -> Id0 end, + couch_doc:validate_docid(Id, DbName, VOpts), Doc#doc{id=Id} end, DocsArray), @@ -449,7 +452,11 @@ db_req(#httpd{method='POST',path_parts=[_,<<"_bulk_docs">>], user_ctx=Ctx}=Req, send_json(Req, 417, ErrorsJson) end; false -> - Docs = [couch_doc:from_json_obj_validate(JsonObj) || JsonObj <- DocsArray], + Docs = [begin + couch_doc:from_json_obj_validate(JsonObj) + end + || JsonObj <- DocsArray], + [couch_doc:validate_docid(D#doc.id, DbName, VOpts) || D <- Docs], [validate_attachment_names(D) || D <- Docs], case fabric:update_docs(Db, Docs, [replicated_changes|Options]) of {ok, Errors} -> @@ -758,7 +765,7 @@ db_doc_req(#httpd{method='GET', mochi_req=MochiReq}=Req, Db, DocId) -> db_doc_req(#httpd{method='POST', user_ctx=Ctx}=Req, Db, DocId) -> couch_httpd:validate_referer(Req), - couch_doc:validate_docid(DocId, couch_db:name(Db)), + validate_docid(DocId, couch_db:name(Db)), chttpd:validate_ctype(Req, "multipart/form-data"), W = chttpd:qs_value(Req, "w", integer_to_list(mem3:quorum(Db))), @@ -814,7 +821,7 @@ db_doc_req(#httpd{method='PUT', user_ctx=Ctx}=Req, Db, DocId) -> update_type = UpdateType } = parse_doc_query(Req), DbName = couch_db:name(Db), - couch_doc:validate_docid(DocId, DbName), + validate_docid(DocId, DbName), W = chttpd:qs_value(Req, "w", integer_to_list(mem3:quorum(Db))), Options = [{user_ctx,Ctx}, {w,W}], @@ -1291,7 +1298,7 @@ db_attachment_req(#httpd{method=Method, user_ctx=Ctx}=Req, Db, DocId, FileNamePa % check for the existence of the doc to handle the 404 case. couch_doc_open(Db, DocId, nil, []) end, - couch_doc:validate_docid(DocId, couch_db:name(Db)), + validate_docid(DocId, couch_db:name(Db)), #doc{id=DocId}; Rev -> case fabric:open_revs(Db, DocId, [Rev], [{user_ctx,Ctx}]) of @@ -1645,7 +1652,7 @@ bulk_get_open_doc_revs(Db, {Props}, Options) -> bulk_get_open_doc_revs1(Db, Props, Options, {}) -> - case parse_field(<<"id">>, couch_util:get_value(<<"id">>, Props)) of + case parse_id_field(couch_util:get_value(<<"id">>, Props), Db) of {error, {DocId, Error, Reason}} -> {DocId, {error, {null, Error, Reason}}, Options}; @@ -1694,16 +1701,18 @@ bulk_get_open_doc_revs1(Db, Props, _, {DocId, Revs, Options}) -> end. -parse_field(<<"id">>, undefined) -> +parse_id_field(undefined, _Db) -> {ok, undefined}; -parse_field(<<"id">>, Value) -> +parse_id_field(Value, Db) -> try - ok = couch_doc:validate_docid(Value), + ok = validate_docid(Value, couch_db:name(Db)), {ok, Value} catch throw:{Error, Reason} -> {error, {Value, Error, Reason}} - end; + end. + + parse_field(<<"rev">>, undefined) -> {ok, undefined}; parse_field(<<"rev">>, Value) -> @@ -1766,6 +1775,11 @@ bulk_get_json_error(DocId, Rev, Error, Reason) -> {<<"error">>, Error}, {<<"reason">>, Reason}]}}]}). +validate_docid(DocId, DbName) -> + Partitioned = mem3:is_partitioned(DbName), + Options = [{partitioned, Partitioned}], + couch_doc:validate_docid(DocId, DbName, Options). + -ifdef(TEST). -include_lib("eunit/include/eunit.hrl"). diff --git a/src/couch/src/couch_doc.erl b/src/couch/src/couch_doc.erl index f960ec5c2..2c92a9a06 100644 --- a/src/couch/src/couch_doc.erl +++ b/src/couch/src/couch_doc.erl @@ -16,7 +16,7 @@ -export([from_json_obj/1, from_json_obj_validate/1]). -export([from_json_obj/2, from_json_obj_validate/2]). -export([to_json_obj/2, has_stubs/1, merge_stubs/2]). --export([validate_docid/1, validate_docid/2, get_validate_doc_fun/1]). +-export([validate_docid/1, validate_docid/2, validate_docid/3, get_validate_doc_fun/1]). -export([doc_from_multi_part_stream/2, doc_from_multi_part_stream/3]). -export([doc_from_multi_part_stream/4]). -export([doc_to_multi_part_stream/5, len_doc_to_multi_part_stream/4]). @@ -199,12 +199,30 @@ parse_revs(_) -> validate_docid(DocId, DbName) -> - case DbName =:= ?l2b(config:get("mem3", "shards_db", "_dbs")) andalso - lists:member(DocId, ?SYSTEM_DATABASES) of + validate_docid(DocId, DbName, []). + +validate_docid(DocId, DbName, Options) -> + SystemId = DbName =:= ?l2b(config:get("mem3", "shards_db", "_dbs")) andalso + lists:member(DocId, ?SYSTEM_DATABASES), + case SystemId of true -> ok; false -> - validate_docid(DocId) + Partitioned = couch_util:get_value(partitioned, Options, false), + case Partitioned of + true -> + case binary:split(DocId, <<":">>) of + [<<"_design/", _/binary>> | _Rest] -> + validate_docid(DocId); + [Partition, Rest] when Rest =/= <<>> -> + ok = validate_docid(Partition), + validate_docid(Rest); + _ -> + throw({illegal_docid, <<"doc id must be of form partition:id">>}) + end; + false -> + validate_docid(DocId) + end end. validate_docid(<<"">>) -> diff --git a/src/couch/test/fixtures/test.couch b/src/couch/test/fixtures/test.couch Binary files differdeleted file mode 100644 index 32c79af32..000000000 --- a/src/couch/test/fixtures/test.couch +++ /dev/null |