summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilipe David Borba Manana <fdmanana@apache.org>2011-05-23 10:56:08 +0000
committerFilipe David Borba Manana <fdmanana@apache.org>2011-05-23 10:56:08 +0000
commit1a4f2d8c5ef87933192125b3feb98eaaa33a7bbc (patch)
tree89657f44e39f9f1fa5e5a67b1f94dfb4ac4a654e
parentee6bb16b53069e6b213d1314f78cde2bd648b069 (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
-rw-r--r--src/couchdb/couch_doc.erl17
-rw-r--r--src/couchdb/couch_httpd_db.erl17
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])).