summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Newson <rnewson@apache.org>2018-08-02 14:41:03 +0100
committerRobert Newson <rnewson@apache.org>2018-09-17 13:58:27 +0100
commit3aec64026f7a78720140c1ed37f39a80b092e3b9 (patch)
treea4da38664e4d1867e931838e43734d82d9662944
parent77fd776f6310d1c60f4865af8820beaeb92f5c33 (diff)
downloadcouchdb-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.erl34
-rw-r--r--src/couch/src/couch_doc.erl26
-rw-r--r--src/couch/test/fixtures/test.couchbin16482 -> 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
deleted file mode 100644
index 32c79af32..000000000
--- a/src/couch/test/fixtures/test.couch
+++ /dev/null
Binary files differ