summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorILYA Khlopotov <iilyak@apache.org>2020-06-22 14:04:00 -0700
committerILYA Khlopotov <iilyak@apache.org>2020-06-22 14:04:00 -0700
commitafbe32ed13c316acb188b2fdd6648e7991a04d07 (patch)
tree8b010cf2b1d00f63ace93029faf2fb61870de852
parent7e008d0fa3d4ba0fcc31989d3ded853683ecaf81 (diff)
downloadcouchdb-afbe32ed13c316acb188b2fdd6648e7991a04d07.tar.gz
Add max_bulk_get_count configuration option
-rw-r--r--rel/overlay/etc/default.ini4
-rw-r--r--src/chttpd/src/chttpd.erl2
-rw-r--r--src/chttpd/src/chttpd_db.erl5
-rw-r--r--src/chttpd/test/eunit/chttpd_db_doc_size_tests.erl24
4 files changed, 34 insertions, 1 deletions
diff --git a/rel/overlay/etc/default.ini b/rel/overlay/etc/default.ini
index 40a3b3179..1c37765be 100644
--- a/rel/overlay/etc/default.ini
+++ b/rel/overlay/etc/default.ini
@@ -59,6 +59,10 @@ max_document_size = 8000000 ; bytes
; returns a 413 error for the whole request
;max_bulk_docs_count = 10000
;
+; Maximum number of documents in a _bulk_get request. Anything larger
+; returns a 413 error for the whole request
+;max_bulk_get_count = 10000
+;
; Maximum attachment size.
; max_attachment_size = infinity
;
diff --git a/src/chttpd/src/chttpd.erl b/src/chttpd/src/chttpd.erl
index e8639ed8d..eca936fed 100644
--- a/src/chttpd/src/chttpd.erl
+++ b/src/chttpd/src/chttpd.erl
@@ -958,6 +958,8 @@ error_info({request_entity_too_large, {attachment, AttName}}) ->
{413, <<"attachment_too_large">>, AttName};
error_info({request_entity_too_large, {bulk_docs, Max}}) when is_integer(Max) ->
{413, <<"max_bulk_docs_count_exceeded">>, integer_to_binary(Max)};
+error_info({request_entity_too_large, {bulk_get, Max}}) when is_integer(Max) ->
+ {413, <<"max_bulk_get_count_exceeded">>, integer_to_binary(Max)};
error_info({request_entity_too_large, DocID}) ->
{413, <<"document_too_large">>, DocID};
error_info({error, security_migration_updates_disabled}) ->
diff --git a/src/chttpd/src/chttpd_db.erl b/src/chttpd/src/chttpd_db.erl
index 5af98fe3a..fdaf4af8c 100644
--- a/src/chttpd/src/chttpd_db.erl
+++ b/src/chttpd/src/chttpd_db.erl
@@ -560,6 +560,11 @@ db_req(#httpd{method='POST', path_parts=[_, <<"_bulk_get">>],
undefined ->
throw({bad_request, <<"Missing JSON list of 'docs'.">>});
Docs ->
+ MaxDocs = config:get_integer("couchdb", "max_bulk_get_count", 10000),
+ case length(Docs) =< MaxDocs of
+ true -> ok;
+ false -> throw({request_entity_too_large, {bulk_get, MaxDocs}})
+ end,
#doc_query_args{
options = Options
} = bulk_get_parse_doc_query(Req),
diff --git a/src/chttpd/test/eunit/chttpd_db_doc_size_tests.erl b/src/chttpd/test/eunit/chttpd_db_doc_size_tests.erl
index 2b04050a2..2826cda24 100644
--- a/src/chttpd/test/eunit/chttpd_db_doc_size_tests.erl
+++ b/src/chttpd/test/eunit/chttpd_db_doc_size_tests.erl
@@ -30,6 +30,7 @@ setup() ->
ok = config:set("admins", ?USER, ?b2l(Hashed), _Persist=false),
ok = config:set("couchdb", "max_document_size", "50"),
ok = config:set("couchdb", "max_bulk_docs_count", "2"),
+ ok = config:set("couchdb", "max_bulk_get_count", "2"),
TmpDb = ?tempdb(),
Addr = config:get("chttpd", "bind_address", "127.0.0.1"),
Port = mochiweb_socket_server:get(chttpd, port),
@@ -41,7 +42,9 @@ teardown(Url) ->
delete_db(Url),
ok = config:delete("admins", ?USER, _Persist=false),
ok = config:delete("couchdb", "max_document_size"),
- ok = config:delete("couchdb", "max_bulk_docs_count").
+ ok = config:delete("couchdb", "max_bulk_docs_count"),
+ ok = config:delete("couchdb", "max_bulk_get_count"),
+ ok.
create_db(Url) ->
{ok, Status, _, _} = test_request:put(Url, [?CONTENT_JSON, ?AUTH], "{}"),
@@ -70,6 +73,7 @@ all_test_() ->
fun put_single_doc/1,
fun bulk_doc/1,
fun bulk_docs_too_many_docs/1,
+ fun bulk_get_too_many_docs/1,
fun put_post_doc_attach_inline/1,
fun put_multi_part_related/1,
fun post_multi_part_form/1
@@ -120,6 +124,24 @@ bulk_docs_too_many_docs(Url) ->
?_assertEqual({413, ExpectJson}, {Code, ResultJson}).
+bulk_get_too_many_docs(Url) ->
+ Docs = lists:map(fun(_) ->
+ {ok, 201, _, Body} = test_request:post(Url,
+ [?CONTENT_JSON, ?AUTH], "{}"),
+ {Props} = ?JSON_DECODE(Body),
+ {lists:keydelete(<<"ok">>, 1, Props)}
+ end, [1, 2, 3, 4]),
+
+ {ok, Code, _, ResultBody} = test_request:post(Url ++ "/_bulk_get/",
+ [?CONTENT_JSON, ?AUTH], ?JSON_ENCODE({[{<<"docs">>, Docs}]})),
+ ResultJson = ?JSON_DECODE(ResultBody),
+ ExpectJson = {[
+ {<<"error">>,<<"max_bulk_get_count_exceeded">>},
+ {<<"reason">>,<<"2">>}
+ ]},
+ ?_assertEqual({413, ExpectJson}, {Code, ResultJson}).
+
+
put_post_doc_attach_inline(Url) ->
Body1 = "{\"body\":\"This is a body.\",",
Body2 = lists:concat(["{\"body\":\"This is a body it should fail",