Bug 1196592: Make retargeting Fetch to another thread actually work. r=nsm
authorKyle Huey <khuey@kylehuey.com>
Fri, 28 Aug 2015 13:49:07 -0700
changeset 259893 fa3fabfe2b02b220229e761f4d660bdac48f4a4f
parent 259892 2e731191c6920f29f12b4592466f9a4dc2df1842
child 259894 7afe43b2288ed4a485096dea49bb8b4e816f4cd4
push id29296
push userryanvm@gmail.com
push dateSun, 30 Aug 2015 19:45:10 +0000
treeherdermozilla-central@2ad5077d86ba [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnsm
bugs1196592
milestone43.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1196592: Make retargeting Fetch to another thread actually work. r=nsm
dom/fetch/FetchDriver.cpp
dom/fetch/FetchDriver.h
dom/security/nsCORSListenerProxy.cpp
dom/security/nsCORSListenerProxy.h
--- a/dom/fetch/FetchDriver.cpp
+++ b/dom/fetch/FetchDriver.cpp
@@ -36,17 +36,17 @@
 #include "InternalRequest.h"
 #include "InternalResponse.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_ISUPPORTS(FetchDriver,
                   nsIStreamListener, nsIChannelEventSink, nsIInterfaceRequestor,
-                  nsIAsyncVerifyRedirectCallback)
+                  nsIAsyncVerifyRedirectCallback, nsIThreadRetargetableStreamListener)
 
 FetchDriver::FetchDriver(InternalRequest* aRequest, nsIPrincipal* aPrincipal,
                          nsILoadGroup* aLoadGroup)
   : mPrincipal(aPrincipal)
   , mLoadGroup(aLoadGroup)
   , mRequest(aRequest)
   , mFetchRecursionCount(0)
   , mResponseAvailableCalled(false)
@@ -777,30 +777,33 @@ FetchDriver::OnStartRequest(nsIRequest* 
   nsCOMPtr<nsIEventTarget> sts = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     FailWithNetworkError();
     // Cancel request.
     return rv;
   }
 
   // Try to retarget off main thread.
-  nsCOMPtr<nsIThreadRetargetableRequest> rr = do_QueryInterface(aRequest);
-  if (rr) {
-    rr->RetargetDeliveryTo(sts);
+  if (nsCOMPtr<nsIThreadRetargetableRequest> rr = do_QueryInterface(aRequest)) {
+    NS_WARN_IF(NS_FAILED(rr->RetargetDeliveryTo(sts)));
   }
   return NS_OK;
 }
 
 NS_IMETHODIMP
 FetchDriver::OnDataAvailable(nsIRequest* aRequest,
                              nsISupports* aContext,
                              nsIInputStream* aInputStream,
                              uint64_t aOffset,
                              uint32_t aCount)
 {
+  // NB: This can be called on any thread!  But we're guaranteed that it is
+  // called between OnStartRequest and OnStopRequest, so we don't need to worry
+  // about races.
+
   uint32_t aRead;
   MOZ_ASSERT(mResponse);
   MOZ_ASSERT(mPipeOutputStream);
 
   nsresult rv = aInputStream->ReadSegments(NS_CopySegmentToStream,
                                            mPipeOutputStream,
                                            aCount, &aRead);
   return rv;
@@ -882,16 +885,22 @@ FetchDriver::AsyncOnChannelRedirect(nsIC
     }
     return rv;
   }
 
   (void) OnRedirectVerifyCallback(NS_OK);
   return NS_OK;
 }
 
+NS_IMETHODIMP
+FetchDriver::CheckListenerChain()
+{
+  return NS_OK;
+}
+
 // Returns NS_OK if no preflight is required, error otherwise.
 nsresult
 FetchDriver::DoesNotRequirePreflight(nsIChannel* aChannel)
 {
   // If this is a same-origin request or the channel's URI inherits
   // its principal, it's allowed.
   if (nsContentUtils::CheckMayLoad(mPrincipal, aChannel, true)) {
     return NS_OK;
--- a/dom/fetch/FetchDriver.h
+++ b/dom/fetch/FetchDriver.h
@@ -7,16 +7,17 @@
 #ifndef mozilla_dom_FetchDriver_h
 #define mozilla_dom_FetchDriver_h
 
 #include "nsAutoPtr.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "nsIChannelEventSink.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIStreamListener.h"
+#include "nsIThreadRetargetableStreamListener.h"
 #include "mozilla/nsRefPtr.h"
 
 #include "mozilla/DebugOnly.h"
 #include "mozilla/net/ReferrerPolicy.h"
 
 class nsIDocument;
 class nsIOutputStream;
 class nsILoadGroup;
@@ -39,25 +40,27 @@ public:
 protected:
   virtual ~FetchDriverObserver()
   { };
 };
 
 class FetchDriver final : public nsIStreamListener,
                           public nsIChannelEventSink,
                           public nsIInterfaceRequestor,
-                          public nsIAsyncVerifyRedirectCallback
+                          public nsIAsyncVerifyRedirectCallback,
+                          public nsIThreadRetargetableStreamListener
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSISTREAMLISTENER
   NS_DECL_NSICHANNELEVENTSINK
   NS_DECL_NSIINTERFACEREQUESTOR
   NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
+  NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
 
   explicit FetchDriver(InternalRequest* aRequest, nsIPrincipal* aPrincipal,
                        nsILoadGroup* aLoadGroup);
   NS_IMETHOD Fetch(FetchDriverObserver* aObserver);
 
   void
   SetDocument(nsIDocument* aDocument);
 
--- a/dom/security/nsCORSListenerProxy.cpp
+++ b/dom/security/nsCORSListenerProxy.cpp
@@ -407,17 +407,18 @@ nsPreflightCache::GetCacheKey(nsIURI* aU
   return true;
 }
 
 //////////////////////////////////////////////////////////////////////////
 // nsCORSListenerProxy
 
 NS_IMPL_ISUPPORTS(nsCORSListenerProxy, nsIStreamListener,
                   nsIRequestObserver, nsIChannelEventSink,
-                  nsIInterfaceRequestor, nsIAsyncVerifyRedirectCallback)
+                  nsIInterfaceRequestor, nsIAsyncVerifyRedirectCallback,
+                  nsIThreadRetargetableStreamListener)
 
 /* static */
 void
 nsCORSListenerProxy::Startup()
 {
   Preferences::AddBoolVarCache(&gDisableCORS,
                                "content.cors.disable");
   Preferences::AddBoolVarCache(&gDisableCORSPrivateData,
@@ -670,21 +671,25 @@ nsCORSListenerProxy::OnStopRequest(nsIRe
   mRedirectCallback = nullptr;
   mOldRedirectChannel = nullptr;
   mNewRedirectChannel = nullptr;
   return rv;
 }
 
 NS_IMETHODIMP
 nsCORSListenerProxy::OnDataAvailable(nsIRequest* aRequest,
-                                     nsISupports* aContext, 
+                                     nsISupports* aContext,
                                      nsIInputStream* aInputStream,
                                      uint64_t aOffset,
                                      uint32_t aCount)
 {
+  // NB: This can be called on any thread!  But we're guaranteed that it is
+  // called between OnStartRequest and OnStopRequest, so we don't need to worry
+  // about races.
+
   MOZ_ASSERT(mInited, "nsCORSListenerProxy has not been initialized properly");
   if (!mRequestApproved) {
     return NS_ERROR_DOM_BAD_URI;
   }
   return mOuterListener->OnDataAvailable(aRequest, aContext, aInputStream,
                                          aOffset, aCount);
 }
 
@@ -821,16 +826,29 @@ nsCORSListenerProxy::OnRedirectVerifyCal
 
   mOldRedirectChannel = nullptr;
   mNewRedirectChannel = nullptr;
   mRedirectCallback->OnRedirectVerifyCallback(result);
   mRedirectCallback   = nullptr;
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsCORSListenerProxy::CheckListenerChain()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener =
+        do_QueryInterface(mOuterListener)) {
+    return retargetableListener->CheckListenerChain();
+  }
+
+  return NS_ERROR_NO_INTERFACE;
+}
+
 // Please note that the CSP directive 'upgrade-insecure-requests' relies
 // on the promise that channels get updated from http: to https: before
 // the channel fetches any data from the netwerk. Such channels should
 // not be blocked by CORS and marked as cross origin requests. E.g.:
 // toplevel page: https://www.example.com loads
 //           xhr: http://www.example.com/foo which gets updated to
 //                https://www.example.com/foo
 // In such a case we should bail out of CORS and rely on the promise that
@@ -1258,17 +1276,16 @@ nsCORSPreflightListener::AsyncOnChannelR
 }
 
 NS_IMETHODIMP
 nsCORSPreflightListener::GetInterface(const nsIID & aIID, void **aResult)
 {
   return QueryInterface(aIID, aResult);
 }
 
-
 nsresult
 NS_StartCORSPreflight(nsIChannel* aRequestChannel,
                       nsIStreamListener* aListener,
                       nsIPrincipal* aPrincipal,
                       bool aWithCredentials,
                       nsTArray<nsCString>& aUnsafeHeaders,
                       nsIChannel** aPreflightChannel)
 {
--- a/dom/security/nsCORSListenerProxy.h
+++ b/dom/security/nsCORSListenerProxy.h
@@ -11,16 +11,17 @@
 #include "nsIInterfaceRequestor.h"
 #include "nsCOMPtr.h"
 #include "nsString.h"
 #include "nsIURI.h"
 #include "nsTArray.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIChannelEventSink.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
+#include "nsIThreadRetargetableStreamListener.h"
 #include "mozilla/Attributes.h"
 
 class nsIURI;
 class nsIPrincipal;
 class nsINetworkInterceptController;
 
 nsresult
 NS_StartCORSPreflight(nsIChannel* aRequestChannel,
@@ -34,17 +35,18 @@ enum class DataURIHandling
 {
   Allow,
   Disallow
 };
 
 class nsCORSListenerProxy final : public nsIStreamListener,
                                   public nsIInterfaceRequestor,
                                   public nsIChannelEventSink,
-                                  public nsIAsyncVerifyRedirectCallback
+                                  public nsIAsyncVerifyRedirectCallback,
+                                  public nsIThreadRetargetableStreamListener
 {
 public:
   nsCORSListenerProxy(nsIStreamListener* aOuter,
                       nsIPrincipal* aRequestingPrincipal,
                       bool aWithCredentials);
   nsCORSListenerProxy(nsIStreamListener* aOuter,
                       nsIPrincipal* aRequestingPrincipal,
                       bool aWithCredentials,
@@ -52,16 +54,17 @@ public:
                       const nsTArray<nsCString>& aPreflightHeaders);
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSISTREAMLISTENER
   NS_DECL_NSIINTERFACEREQUESTOR
   NS_DECL_NSICHANNELEVENTSINK
   NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
+  NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
 
   // Must be called at startup.
   static void Startup();
 
   static void Shutdown();
 
   nsresult Init(nsIChannel* aChannel, DataURIHandling aAllowDataURI);