You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by fd...@apache.org on 2011/05/23 12:53:37 UTC
svn commit: r1126426 - in /couchdb/trunk/src/couchdb: couch_doc.erl
couch_httpd_db.erl
Author: fdmanana
Date: Mon May 23 10:53:37 2011
New Revision: 1126426
URL: http://svn.apache.org/viewvc?rev=1126426&view=rev
Log:
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.
Modified:
couchdb/trunk/src/couchdb/couch_doc.erl
couchdb/trunk/src/couchdb/couch_httpd_db.erl
Modified: couchdb/trunk/src/couchdb/couch_doc.erl
URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_doc.erl?rev=1126426&r1=1126425&r2=1126426&view=diff
==============================================================================
--- couchdb/trunk/src/couchdb/couch_doc.erl (original)
+++ couchdb/trunk/src/couchdb/couch_doc.erl Mon May 23 10:53:37 2011
@@ -480,16 +480,17 @@ atts_to_mp([Att | RestAtts], Boundary, W
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.
@@ -503,7 +504,11 @@ doc_from_multi_part_stream(ContentType,
(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}, []) ->
Modified: couchdb/trunk/src/couchdb/couch_httpd_db.erl
URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_httpd_db.erl?rev=1126426&r1=1126425&r2=1126426&view=diff
==============================================================================
--- couchdb/trunk/src/couchdb/couch_httpd_db.erl (original)
+++ couchdb/trunk/src/couchdb/couch_httpd_db.erl Mon May 23 10:53:37 2011
@@ -691,10 +691,12 @@ db_doc_req(#httpd{method='PUT'}=Req, Db,
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" ->
@@ -829,7 +831,14 @@ send_ranges_multipart(Req, ContentType,
{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])).