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 13:05:26 UTC

svn commit: r1126431 - in /couchdb/branches/1.0.x/src/couchdb: couch_doc.erl couch_httpd_db.erl

Author: fdmanana
Date: Mon May 23 11:05:26 2011
New Revision: 1126431

URL: http://svn.apache.org/viewvc?rev=1126431&view=rev
Log:
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.


Modified:
    couchdb/branches/1.0.x/src/couchdb/couch_doc.erl
    couchdb/branches/1.0.x/src/couchdb/couch_httpd_db.erl

Modified: couchdb/branches/1.0.x/src/couchdb/couch_doc.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/1.0.x/src/couchdb/couch_doc.erl?rev=1126431&r1=1126430&r2=1126431&view=diff
==============================================================================
--- couchdb/branches/1.0.x/src/couchdb/couch_doc.erl (original)
+++ couchdb/branches/1.0.x/src/couchdb/couch_doc.erl Mon May 23 11:05:26 2011
@@ -443,11 +443,13 @@ 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 
@@ -465,7 +467,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/branches/1.0.x/src/couchdb/couch_httpd_db.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/1.0.x/src/couchdb/couch_httpd_db.erl?rev=1126431&r1=1126430&r2=1126431&view=diff
==============================================================================
--- couchdb/branches/1.0.x/src/couchdb/couch_httpd_db.erl (original)
+++ couchdb/branches/1.0.x/src/couchdb/couch_httpd_db.erl Mon May 23 11:05:26 2011
@@ -683,10 +683,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" ->
@@ -804,7 +806,14 @@ send_docs_multipart(Req, Results, Option
     couch_httpd:last_chunk(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">>).
     
 update_doc_result_to_json({{Id, Rev}, Error}) ->
         {_Code, Err, Msg} = couch_httpd:error_info(Error),