Bug 1253777 P1 Ensure buffered copying when reading body in service worker respondWith(). r=jdm a=ritu
authorBen Kelly <ben@wanderview.com>
Wed, 09 Mar 2016 13:41:29 -0800
changeset 323399 668216085fce11fa3a8eea1af17e6da1827652a1
parent 323398 f28fdbf2af288acd789c96cf838cf804325e4bed
child 323400 4ce28157620f5ce2cbd32638d7e634780c8b10aa
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdm, ritu
bugs1253777
milestone47.0a2
Bug 1253777 P1 Ensure buffered copying when reading body in service worker respondWith(). r=jdm a=ritu MozReview-Commit-ID: LlFMXNSwq4A
dom/workers/ServiceWorkerEvents.cpp
--- a/dom/workers/ServiceWorkerEvents.cpp
+++ b/dom/workers/ServiceWorkerEvents.cpp
@@ -352,29 +352,29 @@ struct RespondWithClosure
   {
   }
 };
 
 void RespondWithCopyComplete(void* aClosure, nsresult aStatus)
 {
   nsAutoPtr<RespondWithClosure> data(static_cast<RespondWithClosure*>(aClosure));
   nsCOMPtr<nsIRunnable> event;
-  if (NS_SUCCEEDED(aStatus)) {
-    event = new FinishResponse(data->mInterceptedChannel,
-                               data->mInternalResponse,
-                               data->mWorkerChannelInfo,
-                               data->mScriptSpec,
-                               data->mResponseURLSpec);
-  } else {
+  if (NS_WARN_IF(NS_FAILED(aStatus))) {
     AsyncLog(data->mInterceptedChannel, data->mRespondWithScriptSpec,
              data->mRespondWithLineNumber, data->mRespondWithColumnNumber,
              NS_LITERAL_CSTRING("InterceptionFailedWithURL"),
              data->mRequestURL);
     event = new CancelChannelRunnable(data->mInterceptedChannel,
                                       NS_ERROR_INTERCEPTION_FAILED);
+  } else {
+    event = new FinishResponse(data->mInterceptedChannel,
+                               data->mInternalResponse,
+                               data->mWorkerChannelInfo,
+                               data->mScriptSpec,
+                               data->mResponseURLSpec);
   }
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(event)));
 }
 
 namespace {
 
 void
 ExtractErrorValues(JSContext* aCx, JS::Handle<JS::Value> aValue,
@@ -624,25 +624,44 @@ RespondWithHandler::ResolvedCallback(JSC
     response->SetBodyUsed();
 
     nsCOMPtr<nsIOutputStream> responseBody;
     rv = mInterceptedChannel->GetResponseBody(getter_AddRefs(responseBody));
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return;
     }
 
+    const uint32_t kCopySegmentSize = 4096;
+
+    // Depending on how the Response passed to .respondWith() was created, we may
+    // get a non-buffered input stream.  In addition, in some configurations the
+    // destination channel's output stream can be unbuffered.  We wrap the output
+    // stream side here so that NS_AsyncCopy() works.  Wrapping the output side
+    // provides the most consistent operation since there are fewer stream types
+    // we are writing to.  The input stream can be a wide variety of concrete
+    // objects which may or many not play well with NS_InputStreamIsBuffered().
+    if (!NS_OutputStreamIsBuffered(responseBody)) {
+      nsCOMPtr<nsIOutputStream> buffered;
+      rv = NS_NewBufferedOutputStream(getter_AddRefs(buffered), responseBody,
+           kCopySegmentSize);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return;
+      }
+      responseBody = buffered;
+    }
+
     nsCOMPtr<nsIEventTarget> stsThread = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
     if (NS_WARN_IF(!stsThread)) {
       return;
     }
 
     // XXXnsm, Fix for Bug 1141332 means that if we decide to make this
     // streaming at some point, we'll need a different solution to that bug.
-    rv = NS_AsyncCopy(body, responseBody, stsThread, NS_ASYNCCOPY_VIA_READSEGMENTS, 4096,
-                      RespondWithCopyComplete, closure.forget());
+    rv = NS_AsyncCopy(body, responseBody, stsThread, NS_ASYNCCOPY_VIA_WRITESEGMENTS,
+                      kCopySegmentSize, RespondWithCopyComplete, closure.forget());
     if (NS_WARN_IF(NS_FAILED(rv))) {
       return;
     }
   } else {
     RespondWithCopyComplete(closure.forget(), NS_OK);
   }
 
   MOZ_ASSERT(!closure);