Bug 1199049 - Part 13: Cancel the preflight channel if the original channel gets canceled when a CORS preflight is in progress; r=jduell,sicking
authorEhsan Akhgari <ehsan@mozilla.com>
Thu, 03 Sep 2015 18:40:18 -0400
changeset 294832 03449091a3a3fdad9ed27fa36b4fa56236341604
parent 294831 b0ee24b21b2ad27962d6affa3ec06c652af68a53
child 294833 29f4582c95e035e6ac9abb763087627f7ba62c77
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjduell, sicking
bugs1199049
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 1199049 - Part 13: Cancel the preflight channel if the original channel gets canceled when a CORS preflight is in progress; r=jduell,sicking
netwerk/protocol/http/nsHttpChannel.cpp
netwerk/protocol/http/nsHttpChannel.h
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -447,23 +447,23 @@ nsHttpChannel::Connect()
 
 nsresult
 nsHttpChannel::ContinueConnect()
 {
     // If we need to start a CORS preflight, do it now!
     // Note that it is important to do this before the early returns below.
     if (!mIsCorsPreflightDone && mRequireCORSPreflight &&
         mInterceptCache != INTERCEPTED) {
-        nsCOMPtr<nsIChannel> preflightChannel;
+        MOZ_ASSERT(!mPreflightChannel);
         nsresult rv =
             nsCORSListenerProxy::StartCORSPreflight(this, mListener,
                                                     mPreflightPrincipal, this,
                                                     mWithCredentials,
                                                     mUnsafeHeaders,
-                                                    getter_AddRefs(preflightChannel));
+                                                    getter_AddRefs(mPreflightChannel));
         return rv;
     }
 
     MOZ_RELEASE_ASSERT(!(mRequireCORSPreflight &&
                          mInterceptCache != INTERCEPTED) ||
                        mIsCorsPreflightDone,
                        "CORS preflight must have been finished by the time we "
                        "do the rest of ContinueConnect");
@@ -4885,16 +4885,18 @@ NS_INTERFACE_MAP_END_INHERITING(HttpBase
 //-----------------------------------------------------------------------------
 // nsHttpChannel::nsIRequest
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 nsHttpChannel::Cancel(nsresult status)
 {
     MOZ_ASSERT(NS_IsMainThread());
+    // We should never have a pump open while a CORS preflight is in progress.
+    MOZ_ASSERT_IF(mPreflightChannel, !mCachePump);
 
     LOG(("nsHttpChannel::Cancel [this=%p status=%x]\n", this, status));
     if (mCanceled) {
         LOG(("  ignoring; already canceled\n"));
         return NS_OK;
     }
     if (mWaitingForRedirectCallback) {
         LOG(("channel canceled during wait for redirect callback"));
@@ -4907,16 +4909,18 @@ nsHttpChannel::Cancel(nsresult status)
         gHttpHandler->CancelTransaction(mTransaction, status);
     if (mTransactionPump)
         mTransactionPump->Cancel(status);
     mCacheInputStream.CloseAndRelease();
     if (mCachePump)
         mCachePump->Cancel(status);
     if (mAuthProvider)
         mAuthProvider->Cancel(status);
+    if (mPreflightChannel)
+        mPreflightChannel->Cancel(status);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHttpChannel::Suspend()
 {
     NS_ENSURE_TRUE(mIsPending, NS_ERROR_NOT_AVAILABLE);
 
@@ -6999,25 +7003,27 @@ nsHttpChannel::SetCouldBeSynthesized()
   mResponseCouldBeSynthesized = true;
 }
 
 NS_IMETHODIMP
 nsHttpChannel::OnPreflightSucceeded()
 {
     MOZ_ASSERT(mRequireCORSPreflight, "Why did a preflight happen?");
     mIsCorsPreflightDone = 1;
+    mPreflightChannel = nullptr;
 
     return ContinueConnect();
 }
 
 NS_IMETHODIMP
 nsHttpChannel::OnPreflightFailed(nsresult aError)
 {
     MOZ_ASSERT(mRequireCORSPreflight, "Why did a preflight happen?");
     mIsCorsPreflightDone = 1;
+    mPreflightChannel = nullptr;
 
     Cancel(aError);
     mListener->OnStartRequest(this, mListenerContext);
     mListener->OnStopRequest(this, mListenerContext, aError);
 
     CloseCacheEntry(true);
     return NS_OK;
 }
--- a/netwerk/protocol/http/nsHttpChannel.h
+++ b/netwerk/protocol/http/nsHttpChannel.h
@@ -489,16 +489,18 @@ private:
     // Whether fetching the content is meant to be handled by the
     // packaged app service, which behaves like a caching layer.
     // Upon successfully fetching the package, the resource will be placed in
     // the cache, and served by calling OnCacheEntryAvailable.
     uint32_t                          mIsPackagedAppResource : 1;
     // True if CORS preflight has been performed
     uint32_t                          mIsCorsPreflightDone : 1;
 
+    nsCOMPtr<nsIChannel>              mPreflightChannel;
+
     nsTArray<nsContinueRedirectionFunc> mRedirectFuncStack;
 
     // Needed for accurate DNS timing
     nsRefPtr<nsDNSPrefetch>           mDNSPrefetch;
 
     Http2PushedStream                 *mPushedStream;
     // True if the channel's principal was found on a phishing, malware, or
     // tracking (if tracking protection is enabled) blocklist