diff options
author | Filipe David Borba Manana <fdmanana@apache.org> | 2011-05-23 10:56:08 +0000 |
---|---|---|
committer | Filipe David Borba Manana <fdmanana@apache.org> | 2011-05-23 10:56:08 +0000 |
commit | 1a4f2d8c5ef87933192125b3feb98eaaa33a7bbc (patch) | |
tree | 89657f44e39f9f1fa5e5a67b1f94dfb4ac4a654e /src/couchdb | |
parent | ee6bb16b53069e6b213d1314f78cde2bd648b069 (diff) |
Merged revision 1126426 from trunk
Fix timing issues in the doc PUT multipart/related API
Two issues were present:
1) the handler replied to the request before the multipart parser consumed
all the request's data, causing a subsequent request in the same connection
to consume the remaining data from the multipart/related request;
2) the data function passed to the multipart parser could consume, and
discard, all or part of the data from a subsequent request in the same
connection.
This closes COUCHDB-1174.
git-svn-id: https://svn.apache.org/repos/asf/couchdb/branches/1.1.x@1126428 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/couchdb')
-rw-r--r-- | src/couchdb/couch_doc.erl | 17 | ||||
-rw-r--r-- | src/couchdb/couch_httpd_db.erl | 17 |
2 files changed, 24 insertions, 10 deletions
diff --git a/src/couchdb/couch_doc.erl b/src/couchdb/couch_doc.erl index e3d66145..e2690f3e 100644 --- a/src/couchdb/couch_doc.erl +++ b/src/couchdb/couch_doc.erl @@ -461,16 +461,17 @@ atts_to_mp([Att | RestAtts], Boundary, WriteFun, doc_from_multi_part_stream(ContentType, DataFun) -> - Self = self(), + Parent = self(), Parser = spawn_link(fun() -> - couch_httpd:parse_multipart_request(ContentType, DataFun, - fun(Next)-> mp_parse_doc(Next, []) end), - unlink(Self) + {<<"--">>, _, _} = couch_httpd:parse_multipart_request( + ContentType, DataFun, + fun(Next) -> mp_parse_doc(Next, []) end), + unlink(Parent), + Parent ! {self(), finished} end), Parser ! {get_doc_bytes, self()}, receive {doc_bytes, DocBytes} -> - erlang:put(mochiweb_request_recv, true), Doc = from_json_obj(?JSON_DECODE(DocBytes)), % go through the attachments looking for 'follows' in the data, % replace with function that reads the data from MIME stream. @@ -484,7 +485,11 @@ doc_from_multi_part_stream(ContentType, DataFun) -> (A) -> A end, Doc#doc.atts), - {ok, Doc#doc{atts=Atts2}} + WaitFun = fun() -> + receive {Parser, finished} -> ok end, + erlang:put(mochiweb_request_recv, true) + end, + {ok, Doc#doc{atts=Atts2}, WaitFun} end. mp_parse_doc({headers, H}, []) -> diff --git a/src/couchdb/couch_httpd_db.erl b/src/couchdb/couch_httpd_db.erl index 8336cac0..468ae3f0 100644 --- a/src/couchdb/couch_httpd_db.erl +++ b/src/couchdb/couch_httpd_db.erl @@ -687,10 +687,12 @@ 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} = couch_doc:doc_from_multi_part_stream(ContentType, - fun() -> receive_request_data(Req) end), + {ok, Doc0, WaitFun} = couch_doc:doc_from_multi_part_stream( + ContentType, fun() -> receive_request_data(Req) end), Doc = couch_doc_from_req(Req, DocId, Doc0), - update_doc(Req, Db, DocId, Doc, RespHeaders, UpdateType); + Result = update_doc(Req, Db, DocId, Doc, RespHeaders, UpdateType), + WaitFun(), + Result; _Else -> case couch_httpd:qs_value(Req, "batch") of "ok" -> @@ -825,7 +827,14 @@ send_ranges_multipart(Req, ContentType, Len, Att, Ranges) -> {ok, Resp}. receive_request_data(Req) -> - {couch_httpd:recv(Req, 0), fun() -> receive_request_data(Req) end}. + receive_request_data(Req, couch_httpd:body_length(Req)). + +receive_request_data(Req, LenLeft) when LenLeft > 0 -> + Len = erlang:min(4096, LenLeft), + Data = couch_httpd:recv(Req, Len), + {Data, fun() -> receive_request_data(Req, LenLeft - iolist_size(Data)) end}; +receive_request_data(_Req, _) -> + throw(<<"expected more data">>). make_content_range(From, To, Len) -> ?l2b(io_lib:format("bytes ~B-~B/~B", [From, To, Len])). |