You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by rn...@apache.org on 2018/08/29 14:55:33 UTC

[couchdb] 02/13: Enforce partition:id format in doc ids

This is an automated email from the ASF dual-hosted git repository.

rnewson pushed a commit to branch user-partitioned-dbs-6
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit e55bd2bbccde2c589e0d1d7acf289dd4fb649023
Author: Robert Newson <rn...@apache.org>
AuthorDate: Thu Aug 2 14:41:03 2018 +0100

    Enforce partition:id format in doc ids
---
 src/chttpd/src/chttpd_db.erl       |   9 +++++++--
 src/couch/src/couch_doc.erl        |  33 +++++++++++++++++++++++++++++----
 src/couch/test/fixtures/test.couch | Bin 16482 -> 0 bytes
 3 files changed, 36 insertions(+), 6 deletions(-)

diff --git a/src/chttpd/src/chttpd_db.erl b/src/chttpd/src/chttpd_db.erl
index 0905559..63d2907 100644
--- a/src/chttpd/src/chttpd_db.erl
+++ b/src/chttpd/src/chttpd_db.erl
@@ -758,7 +758,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))),
@@ -1291,7 +1291,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
@@ -1766,6 +1766,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 f960ec5..f821696 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]).
@@ -133,6 +133,13 @@ from_json_obj_validate(EJson) ->
 from_json_obj_validate(EJson, DbName) ->
     MaxSize = config:get_integer("couchdb", "max_document_size", 4294967296),
     Doc = from_json_obj(EJson, DbName),
+    case is_binary(DbName) andalso mem3:is_partitioned(DbName) of
+        true ->
+            Options = [{partitioned, true}],
+            couch_doc:validate_docid(Doc#doc.id, DbName, Options);
+        false ->
+            ok
+    end,
     case couch_ejson_size:encoded_size(Doc#doc.body) =< MaxSize of
         true ->
              validate_attachment_sizes(Doc#doc.atts),
@@ -199,12 +206,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] ->
+                            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 32c79af..0000000
Binary files a/src/couch/test/fixtures/test.couch and /dev/null differ