Repository: couchdb-chttpd Updated Branches: refs/heads/2992-limit-doc-size f7affd0d2 -> 1ac365dd8
Move max_document_size logic to update only COUCHDB-2992 Project: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/repo Commit: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/commit/03fdcde5 Tree: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/tree/03fdcde5 Diff: http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/diff/03fdcde5 Branch: refs/heads/2992-limit-doc-size Commit: 03fdcde571585f17c2077a3a0313bc8703e32197 Parents: f7affd0 Author: Tony Sun <tony....@cloudant.com> Authored: Tue Apr 19 18:41:32 2016 -0700 Committer: Tony Sun <tony....@cloudant.com> Committed: Tue Apr 19 18:41:32 2016 -0700 ---------------------------------------------------------------------- include/chttpd.hrl | 3 ++ src/chttpd.erl | 9 ++--- src/chttpd_db.erl | 65 ++++++++++++++++++++--------------- src/chttpd_external.erl | 4 +-- test/chttpd_db_doc_size_test.erl | 6 ++-- 5 files changed, 50 insertions(+), 37 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/03fdcde5/include/chttpd.hrl ---------------------------------------------------------------------- diff --git a/include/chttpd.hrl b/include/chttpd.hrl index a7f9aaa..d26a2ee 100644 --- a/include/chttpd.hrl +++ b/include/chttpd.hrl @@ -26,3 +26,6 @@ (C >= $a andalso C =< $f) orelse (C >= $A andalso C =< $F) )). + +% For any PUT/POST request, max size will be 4 GB (semi-unlimited) +-define(DEFAULT_RECV_BODY, 4294967296). http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/03fdcde5/src/chttpd.erl ---------------------------------------------------------------------- diff --git a/src/chttpd.erl b/src/chttpd.erl index 1f8c160..ef1c140 100644 --- a/src/chttpd.erl +++ b/src/chttpd.erl @@ -599,12 +599,9 @@ body_length(#httpd{mochi_req=MochiReq}) -> body(#httpd{mochi_req=MochiReq, req_body=ReqBody}) -> case ReqBody of undefined -> - % Maximum size of document PUT request body (4GB) - MaxSize = list_to_integer( - config:get("couchdb", "max_document_size", "4294967296")), Begin = os:timestamp(), try - MochiReq:recv_body(MaxSize) + MochiReq:recv_body(?DEFAULT_RECV_BODY) after T = timer:now_diff(os:timestamp(), Begin) div 1000, put(body_time, T) @@ -858,9 +855,9 @@ error_info({error, {database_name_too_long, DbName}}) -> <<"At least one path segment of `", DbName/binary, "` is too long.">>}; error_info({missing_stub, Reason}) -> {412, <<"missing_stub">>, Reason}; -error_info({single_doc_too_large, MaxSize}) -> +error_info({request_entity_too_large, MaxSize}) -> SizeBin = list_to_binary(integer_to_list(MaxSize)), - {413, <<"too_large">>, <<"Document exceeded single_max_doc_size:", + {413, <<"too_large">>, <<"Document exceeded max_document_size:", SizeBin/binary>>}; error_info(request_entity_too_large) -> {413, <<"too_large">>, <<"the request entity is too large">>}; http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/03fdcde5/src/chttpd_db.erl ---------------------------------------------------------------------- diff --git a/src/chttpd_db.erl b/src/chttpd_db.erl index 2a3fe1b..fdfd03d 100644 --- a/src/chttpd_db.erl +++ b/src/chttpd_db.erl @@ -13,6 +13,7 @@ -module(chttpd_db). -include_lib("couch/include/couch_db.hrl"). -include_lib("couch_mrview/include/couch_mrview.hrl"). +-include_lib("chttpd/include/chttpd.hrl"). -export([handle_request/1, handle_compact_req/2, handle_design_req/2, db_req/2, couch_doc_open/4,handle_changes_req/2, @@ -309,7 +310,7 @@ db_req(#httpd{method='POST', path_parts=[DbName], user_ctx=Ctx}=Req, Db) -> Options = [{user_ctx,Ctx}, {w,W}], Body = chttpd:json_body(Req), - ok = verify_doc_size(Body), + ok = maybe_verify_body_size(Body), Doc = couch_doc:from_json_obj(Body), Doc2 = case Doc#doc.id of @@ -377,7 +378,7 @@ db_req(#httpd{method='POST',path_parts=[_,<<"_bulk_docs">>], user_ctx=Ctx}=Req, DocsArray0 -> DocsArray0 end, - {ExceedErrs, DocsArray1} = remove_exceed_docs(DocsArray), + {ExceedErrs, DocsArray1} = maybe_remove_exceed_docs(DocsArray), couch_stats:update_histogram([couchdb, httpd, bulk_docs], length(DocsArray)), W = case couch_util:get_value(<<"w">>, JsonProps) of Value when is_integer(Value) -> @@ -769,7 +770,7 @@ db_doc_req(#httpd{method='PUT', user_ctx=Ctx}=Req, Db, DocId) -> "ok" -> % batch Body = chttpd:json_body(Req), - ok = verify_doc_size(Body), + ok = maybe_verify_body_size(Body), Doc = couch_doc_from_req(Req, DocId, Body), spawn(fun() -> @@ -787,7 +788,7 @@ db_doc_req(#httpd{method='PUT', user_ctx=Ctx}=Req, Db, DocId) -> _Normal -> % normal Body = chttpd:json_body(Req), - ok = verify_doc_size(Body), + ok = maybe_verify_body_size(Body), Doc = couch_doc_from_req(Req, DocId, Body), send_updated_doc(Req, Db, DocId, Doc, RespHeaders, UpdateType) end @@ -1634,33 +1635,43 @@ bulk_get_open_doc_revs1(Db, Props, _, {DocId, Revs, Options}) -> {DocId, Results, Options} end. -remove_exceed_docs(DocArray0) -> - MaxSize = list_to_integer(config:get("couchdb", - "single_max_doc_size", "1048576")), - {ExceedDocs, DocsArray} = lists:splitwith(fun (Doc) -> - exceed_doc_size(Doc, MaxSize) - end, DocArray0), - ExceedErrs = lists:map (fun ({Doc}) -> - DocId = case couch_util:get_value(<<"_id">>, Doc) of - undefined -> couch_uuids:new(); - Id0 -> Id0 - end, - Reason = lists:concat(["Document exceeded single_max_doc_size:", - " of ", MaxSize, " bytes"]), - {[{id, DocId}, {error, <<"too_large">>}, - {reason, ?l2b(Reason)}]} - end, ExceedDocs), - {ExceedErrs, DocsArray}. +maybe_remove_exceed_docs(DocArray0) -> + case config:get_boolean("couchdb", "use_max_document_size", false) of + true -> + Max = config:get_integer("couchdb", "max_document_size", + 16777216), + {ExceedDocs, DocsArray} = lists:splitwith(fun (Doc) -> + exceed_doc_size(Doc, Max) + end, DocArray0), + ExceedErrs = lists:map (fun ({Doc}) -> + DocId = case couch_util:get_value(<<"_id">>, Doc) of + undefined -> <<"no id generated since update failed">>; + Id0 -> Id0 + end, + Reason = lists:concat(["Document exceeded max_document_size:", + " of ", Max, " bytes"]), + {[{id, DocId}, {error, <<"request_entity_too_large">>}, + {reason, ?l2b(Reason)}]} + end, ExceedDocs), + {ExceedErrs, DocsArray}; + false -> + {[], DocArray0} + end. exceed_doc_size(JsonBody, MaxSize) -> size(term_to_binary(JsonBody)) > MaxSize. -verify_doc_size(JsonBody) -> - SMaxSize = list_to_integer(config:get("couchdb", - "single_max_doc_size", "1048576")), - case exceed_doc_size(JsonBody, SMaxSize) of - true -> throw({single_doc_too_large, SMaxSize}); - false -> ok +maybe_verify_body_size(JsonBody) -> + case config:get_boolean("couchdb", "use_max_document_size", false) of + true -> + Max = config:get_integer("couchdb", "max_document_size", + 16777216), + case exceed_doc_size(JsonBody, Max) of + true -> throw({request_entity_too_large, Max}); + false -> ok + end; + false -> + ok end. parse_field(<<"id">>, undefined) -> http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/03fdcde5/src/chttpd_external.erl ---------------------------------------------------------------------- diff --git a/src/chttpd_external.erl b/src/chttpd_external.erl index f9bebed..e8efff2 100644 --- a/src/chttpd_external.erl +++ b/src/chttpd_external.erl @@ -20,6 +20,7 @@ -import(chttpd,[send_error/4]). -include_lib("couch/include/couch_db.hrl"). +-include_lib("chttpd/include/chttpd.hrl"). % handle_external_req/2 % for the old type of config usage: @@ -93,8 +94,7 @@ json_req_obj_field(<<"headers">>, #httpd{mochi_req=Req}, _Db, _DocId) -> Hlist = mochiweb_headers:to_list(Headers), to_json_terms(Hlist); json_req_obj_field(<<"body">>, #httpd{req_body=undefined, mochi_req=Req}, _Db, _DocId) -> - MaxSize = config:get_integer("couchdb", "max_document_size", 4294967296), - Req:recv_body(MaxSize); + Req:recv_body(?DEFAULT_RECV_BODY); json_req_obj_field(<<"body">>, #httpd{req_body=Body}, _Db, _DocId) -> Body; json_req_obj_field(<<"peer">>, #httpd{mochi_req=Req}, _Db, _DocId) -> http://git-wip-us.apache.org/repos/asf/couchdb-chttpd/blob/03fdcde5/test/chttpd_db_doc_size_test.erl ---------------------------------------------------------------------- diff --git a/test/chttpd_db_doc_size_test.erl b/test/chttpd_db_doc_size_test.erl index 02ae3cd..ce29c17 100644 --- a/test/chttpd_db_doc_size_test.erl +++ b/test/chttpd_db_doc_size_test.erl @@ -22,7 +22,8 @@ setup() -> ok = config:set("admins", ?USER, ?PASS, _Persist=false), - ok = config:set("couchdb", "single_max_doc_size", "50"), + ok = config:set("couchdb", "max_document_size", "50"), + ok = config:set("couchdb", "use_max_document_size", "true"), TmpDb = ?tempdb(), Addr = config:get("chttpd", "bind_address", "127.0.0.1"), Port = mochiweb_socket_server:get(chttpd, port), @@ -33,7 +34,8 @@ setup() -> teardown(Url) -> delete_db(Url), ok = config:delete("admins", ?USER, _Persist=false), - ok = config:delete("couchdb", "single_max_doc_size"). + ok = config:delete("couchdb", "max_document_size"), + ok = config:delete("couchdb", "use_max_document_size"). create_db(Url) -> {ok, Status, _, _} = test_request:put(Url, [?CONTENT_JSON, ?AUTH], "{}"),