From d5da180b06b8711c72bf38e35c380a25804e018f Mon Sep 17 00:00:00 2001 From: Filipe David Borba Manana Date: Sun, 12 Jun 2011 16:16:29 +0000 Subject: Backport revision 1129897 from trunk Fixes to the doc PUT multipart API Don't hold the connection forever if the document is rejected by a validate_doc_update function. The solution is to discard all the attachments' data if the document was rejected. git-svn-id: https://svn.apache.org/repos/asf/couchdb/branches/1.1.x@1134942 13f79535-47bb-0310-9956-ffa450edef68 --- src/couchdb/couch_doc.erl | 19 ++++++++++++++++++- src/couchdb/couch_httpd_db.erl | 14 ++++++++++---- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/couchdb/couch_doc.erl b/src/couchdb/couch_doc.erl index 5cd6ac80..531eb6bb 100644 --- a/src/couchdb/couch_doc.erl +++ b/src/couchdb/couch_doc.erl @@ -18,6 +18,7 @@ -export([validate_docid/1]). -export([doc_from_multi_part_stream/2]). -export([doc_to_multi_part_stream/5, len_doc_to_multi_part_stream/4]). +-export([abort_multi_part_stream/1]). -include("couch_db.hrl"). @@ -501,7 +502,7 @@ doc_from_multi_part_stream(ContentType, DataFun) -> receive {Parser, finished} -> ok end, erlang:put(mochiweb_request_recv, true) end, - {ok, Doc#doc{atts=Atts2}, WaitFun} + {ok, Doc#doc{atts=Atts2}, WaitFun, Parser} end. mp_parse_doc({headers, H}, []) -> @@ -542,3 +543,19 @@ mp_parse_atts(body_end) -> end. +abort_multi_part_stream(Parser) -> + abort_multi_part_stream(Parser, erlang:monitor(process, Parser)). + +abort_multi_part_stream(Parser, MonRef) -> + case is_process_alive(Parser) of + true -> + Parser ! {get_bytes, self()}, + receive + {bytes, _Bytes} -> + abort_multi_part_stream(Parser, MonRef); + {'DOWN', MonRef, _, _, _} -> + ok + end; + false -> + erlang:demonitor(MonRef, [flush]) + end. diff --git a/src/couchdb/couch_httpd_db.erl b/src/couchdb/couch_httpd_db.erl index e3638b25..71204598 100644 --- a/src/couchdb/couch_httpd_db.erl +++ b/src/couchdb/couch_httpd_db.erl @@ -692,12 +692,18 @@ db_doc_req(#httpd{method='PUT'}=Req, Db, DocId) -> RespHeaders = [{"Location", Loc}], case couch_util:to_list(couch_httpd:header_value(Req, "Content-Type")) of ("multipart/related;" ++ _) = ContentType -> - {ok, Doc0, WaitFun} = couch_doc:doc_from_multi_part_stream( + {ok, Doc0, WaitFun, Parser} = couch_doc:doc_from_multi_part_stream( ContentType, fun() -> receive_request_data(Req) end), Doc = couch_doc_from_req(Req, DocId, Doc0), - Result = update_doc(Req, Db, DocId, Doc, RespHeaders, UpdateType), - WaitFun(), - Result; + try + Result = update_doc(Req, Db, DocId, Doc, RespHeaders, UpdateType), + WaitFun(), + Result + catch throw:Err -> + % Document rejected by a validate_doc_update function. + couch_doc:abort_multi_part_stream(Parser), + throw(Err) + end; _Else -> case couch_httpd:qs_value(Req, "batch") of "ok" -> -- cgit v1.2.3