Bug 1199049 - Part 3: Add a CORS preflight result notification API; r=jduell,ckerschb,sicking
authorEhsan Akhgari <ehsan@mozilla.com>
Thu, 27 Aug 2015 14:37:07 -0400
changeset 294822 712ee72787adb5731a3a2ba27a7b33079ace12a6
parent 294821 815732d94c8611c223ac3fbad37d0c852fd5d0c2
child 294823 c0503e3636eca775f2a20624e95e719a37900795
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, ckerschb, 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 3: Add a CORS preflight result notification API; r=jduell,ckerschb,sicking
netwerk/protocol/http/nsCORSListenerProxy.cpp
netwerk/protocol/http/nsCORSListenerProxy.h
netwerk/protocol/http/nsICorsPreflightCallback.h
--- a/netwerk/protocol/http/nsCORSListenerProxy.cpp
+++ b/netwerk/protocol/http/nsCORSListenerProxy.cpp
@@ -34,16 +34,17 @@
 #include "nsILoadGroup.h"
 #include "nsILoadContext.h"
 #include "nsIConsoleService.h"
 #include "nsIDOMNode.h"
 #include "nsIDOMWindowUtils.h"
 #include "nsIDOMWindow.h"
 #include "nsINetworkInterceptController.h"
 #include "nsNullPrincipal.h"
+#include "nsICorsPreflightCallback.h"
 #include <algorithm>
 
 using namespace mozilla;
 
 #define PREFLIGHT_CACHE_SIZE 100
 
 static bool gDisableCORS = false;
 static bool gDisableCORSPrivateData = false;
@@ -1040,21 +1041,21 @@ class nsCORSPreflightListener final : pu
                                       public nsIInterfaceRequestor,
                                       public nsIChannelEventSink
 {
 public:
   nsCORSPreflightListener(nsIChannel* aOuterChannel,
                           nsIStreamListener* aOuterListener,
                           nsISupports* aOuterContext,
                           nsIPrincipal* aReferrerPrincipal,
-                          const nsACString& aRequestMethod,
+                          nsICorsPreflightCallback* aCallback,
                           bool aWithCredentials)
    : mOuterChannel(aOuterChannel), mOuterListener(aOuterListener),
      mOuterContext(aOuterContext), mReferrerPrincipal(aReferrerPrincipal),
-     mRequestMethod(aRequestMethod), mWithCredentials(aWithCredentials)
+     mCallback(aCallback), mWithCredentials(aWithCredentials)
   { }
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSISTREAMLISTENER
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSIINTERFACEREQUESTOR
   NS_DECL_NSICHANNELEVENTSINK
 
@@ -1062,17 +1063,17 @@ private:
   ~nsCORSPreflightListener() {}
 
   void AddResultToCache(nsIRequest* aRequest);
 
   nsCOMPtr<nsIChannel> mOuterChannel;
   nsCOMPtr<nsIStreamListener> mOuterListener;
   nsCOMPtr<nsISupports> mOuterContext;
   nsCOMPtr<nsIPrincipal> mReferrerPrincipal;
-  nsCString mRequestMethod;
+  nsCOMPtr<nsICorsPreflightCallback> mCallback;
   bool mWithCredentials;
 };
 
 NS_IMPL_ISUPPORTS(nsCORSPreflightListener, nsIStreamListener,
                   nsIRequestObserver, nsIInterfaceRequestor,
                   nsIChannelEventSink)
 
 void
@@ -1198,55 +1199,35 @@ nsCORSPreflightListener::OnStartRequest(
   if (NS_SUCCEEDED(rv)) {
     rv = status;
   }
 
   if (NS_SUCCEEDED(rv)) {
     // Everything worked, try to cache and then fire off the actual request.
     AddResultToCache(aRequest);
 
-    nsCOMPtr<nsILoadInfo> loadInfo = mOuterChannel->GetLoadInfo();
-    MOZ_ASSERT(loadInfo, "can not perform CORS preflight without a loadInfo");
-    if (!loadInfo) {
-      return NS_ERROR_FAILURE;
-    }
-    nsSecurityFlags securityMode = loadInfo->GetSecurityMode();
-
-    MOZ_ASSERT(securityMode == 0 ||
-               securityMode == nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS,
-               "how did we end up here?");
-
-    if (securityMode == nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS) {
-      MOZ_ASSERT(!mOuterContext, "AsyncOpen(2) does not take context as a second arg");
-      rv = mOuterChannel->AsyncOpen2(mOuterListener);
-    }
-    else {
-      rv = mOuterChannel->AsyncOpen(mOuterListener, mOuterContext);
-    }
+    mCallback->OnPreflightSucceeded();
+  } else {
+    mCallback->OnPreflightFailed(rv);
+    mOuterListener->OnStartRequest(mOuterChannel, mOuterContext);
+    mOuterListener->OnStopRequest(mOuterChannel, mOuterContext, rv);
   }
 
-  if (NS_FAILED(rv)) {
-    mOuterChannel->Cancel(rv);
-    mOuterListener->OnStartRequest(mOuterChannel, mOuterContext);
-    mOuterListener->OnStopRequest(mOuterChannel, mOuterContext, rv);
-    
-    return rv;
-  }
-
-  return NS_OK;
+  return rv;
 }
 
 NS_IMETHODIMP
 nsCORSPreflightListener::OnStopRequest(nsIRequest *aRequest,
                                        nsISupports *aContext,
                                        nsresult aStatus)
 {
   mOuterChannel = nullptr;
   mOuterListener = nullptr;
   mOuterContext = nullptr;
+  mCallback = nullptr;
   return NS_OK;
 }
 
 /** nsIStreamListener methods **/
 
 NS_IMETHODIMP
 nsCORSPreflightListener::OnDataAvailable(nsIRequest *aRequest,
                                          nsISupports *ctxt,
@@ -1278,16 +1259,17 @@ nsCORSPreflightListener::GetInterface(co
 {
   return QueryInterface(aIID, aResult);
 }
 
 nsresult
 NS_StartCORSPreflight(nsIChannel* aRequestChannel,
                       nsIStreamListener* aListener,
                       nsIPrincipal* aPrincipal,
+                      nsICorsPreflightCallback* aCallback,
                       bool aWithCredentials,
                       nsTArray<nsCString>& aUnsafeHeaders,
                       nsIChannel** aPreflightChannel)
 {
   *aPreflightChannel = nullptr;
 
   nsAutoCString method;
   nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequestChannel));
@@ -1311,21 +1293,18 @@ NS_StartCORSPreflight(nsIChannel* aReque
              "how did we end up here?");
 
   nsPreflightCache::CacheEntry* entry =
     sPreflightCache ?
     sPreflightCache->GetEntry(uri, aPrincipal, aWithCredentials, false) :
     nullptr;
 
   if (entry && entry->CheckRequest(method, aUnsafeHeaders)) {
-    // We have a cached preflight result, just start the original channel
-    if (securityMode == nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS) {
-      return aRequestChannel->AsyncOpen2(aListener);
-    }
-    return aRequestChannel->AsyncOpen(aListener, nullptr);
+    aCallback->OnPreflightSucceeded();
+    return NS_OK;
   }
 
   // Either it wasn't cached or the cached result has expired. Build a
   // channel for the OPTIONS request.
 
   nsCOMPtr<nsILoadGroup> loadGroup;
   rv = aRequestChannel->GetLoadGroup(getter_AddRefs(loadGroup));
   NS_ENSURE_SUCCESS(rv, rv);
@@ -1358,17 +1337,17 @@ NS_StartCORSPreflight(nsIChannel* aReque
     // here and allow service workers to intercept CORS preflights, then that
     // check won't be safe any more.
     preInternal->ForceNoIntercept();
   }
   
   // Set up listener which will start the original channel
   nsCOMPtr<nsIStreamListener> preflightListener =
     new nsCORSPreflightListener(aRequestChannel, aListener, nullptr, aPrincipal,
-                                method, aWithCredentials);
+                                aCallback, aWithCredentials);
   NS_ENSURE_TRUE(preflightListener, NS_ERROR_OUT_OF_MEMORY);
 
   // Start preflight
   if (securityMode == nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS) {
     rv = preflightChannel->AsyncOpen2(preflightListener);
   }
   else {
     nsRefPtr<nsCORSListenerProxy> corsListener =
--- a/netwerk/protocol/http/nsCORSListenerProxy.h
+++ b/netwerk/protocol/http/nsCORSListenerProxy.h
@@ -17,21 +17,23 @@
 #include "nsIChannelEventSink.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "nsIThreadRetargetableStreamListener.h"
 #include "mozilla/Attributes.h"
 
 class nsIURI;
 class nsIPrincipal;
 class nsINetworkInterceptController;
+class nsICorsPreflightCallback;
 
 nsresult
 NS_StartCORSPreflight(nsIChannel* aRequestChannel,
                       nsIStreamListener* aListener,
                       nsIPrincipal* aPrincipal,
+                      nsICorsPreflightCallback* aCallback,
                       bool aWithCredentials,
                       nsTArray<nsCString>& aACUnsafeHeaders,
                       nsIChannel** aPreflightChannel);
 
 enum class DataURIHandling
 {
   Allow,
   Disallow
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/http/nsICorsPreflightCallback.h
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsICorsPreflightCallback_h__
+#define nsICorsPreflightCallback_h__
+
+#include "nsISupports.h"
+#include "nsID.h"
+#include "nsError.h"
+
+#define NS_ICORSPREFLIGHTCALLBACK_IID \
+  { 0x3758cfbb, 0x259f, 0x4074, \
+      { 0xa8, 0xc0, 0x98, 0xe0, 0x4b, 0x3c, 0xc0, 0xe3 } }
+
+class nsICorsPreflightCallback : public nsISupports
+{
+public:
+  NS_DECLARE_STATIC_IID_ACCESSOR(nsICorsPreflightCallback);
+  NS_IMETHOD OnPreflightSucceeded() = 0;
+  NS_IMETHOD OnPreflightFailed(nsresult aError) = 0;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsICorsPreflightCallback, NS_ICORSPREFLIGHTCALLBACK_IID);
+
+#endif