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:56:08 UTC

svn commit: r1126428 - in /couchdb/branches/1.1.x/src/couchdb: couch_doc.erl couch_httpd_db.erl

Author: fdmanana
Date: Mon May 23 10:56:08 2011
New Revision: 1126428

URL: http://svn.apache.org/viewvc?rev=1126428&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.1.x/src/couchdb/couch_doc.erl
    couchdb/branches/1.1.x/src/couchdb/couch_httpd_db.erl

Modified: couchdb/branches/1.1.x/src/couchdb/couch_doc.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/1.1.x/src/couchdb/couch_doc.erl?rev=1126428&r1=1126427&r2=1126428&view=diff
==============================================================================
--- couchdb/branches/1.1.x/src/couchdb/couch_doc.erl (original)
+++ couchdb/branches/1.1.x/src/couchdb/couch_doc.erl Mon May 23 10:56:08 2011
@@ -461,16 +461,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.
@@ -484,7 +485,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.1.x/src/couchdb/couch_httpd_db.erl
URL: http://svn.apache.org/viewvc/couchdb/branches/1.1.x/src/couchdb/couch_httpd_db.erl?rev=1126428&r1=1126427&r2=1126428&view=diff
==============================================================================
--- couchdb/branches/1.1.x/src/couchdb/couch_httpd_db.erl (original)
+++ couchdb/branches/1.1.x/src/couchdb/couch_httpd_db.erl Mon May 23 10:56:08 2011
@@ -687,10 +687,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" ->
@@ -825,7 +827,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])).