diff options
author | ILYA Khlopotov <iilyak@apache.org> | 2020-06-22 14:04:00 -0700 |
---|---|---|
committer | ILYA Khlopotov <iilyak@apache.org> | 2020-06-22 14:04:00 -0700 |
commit | afbe32ed13c316acb188b2fdd6648e7991a04d07 (patch) | |
tree | 8b010cf2b1d00f63ace93029faf2fb61870de852 | |
parent | 7e008d0fa3d4ba0fcc31989d3ded853683ecaf81 (diff) | |
download | couchdb-afbe32ed13c316acb188b2fdd6648e7991a04d07.tar.gz |
Add max_bulk_get_count configuration option
-rw-r--r-- | rel/overlay/etc/default.ini | 4 | ||||
-rw-r--r-- | src/chttpd/src/chttpd.erl | 2 | ||||
-rw-r--r-- | src/chttpd/src/chttpd_db.erl | 5 | ||||
-rw-r--r-- | src/chttpd/test/eunit/chttpd_db_doc_size_tests.erl | 24 |
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", |