Bug 1216687: Add nsILoadInfo flags for cookie policies. r=ckerschb
☠☠ backed out by e648ed99a3a2 ☠ ☠
authorJonas Sicking <jonas@sicking.cc>
Sat, 05 Dec 2015 01:46:21 -0800
changeset 297257 09d64535bcda005593b0e29fcfe813f07e128b79
parent 297256 a7f1a289dd7824cf9bfdd7be92770fe8a1a55b04
child 297258 3ca0a1e37264624f4304aec23918fb9e0f4910e2
push id5513
push userraliiev@mozilla.com
push dateMon, 25 Jan 2016 13:55:34 +0000
treeherdermozilla-esr52@5ee97dd05b5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersckerschb
bugs1216687
milestone45.0a1
Bug 1216687: Add nsILoadInfo flags for cookie policies. r=ckerschb
dom/base/EventSource.cpp
dom/base/Navigator.cpp
dom/base/nsScriptLoader.cpp
dom/base/nsXMLHttpRequest.cpp
dom/base/test/test_bug338583.html
dom/fetch/FetchDriver.cpp
dom/fetch/FetchDriver.h
dom/html/HTMLMediaElement.cpp
dom/security/nsContentSecurityManager.cpp
netwerk/base/LoadInfo.cpp
netwerk/base/LoadInfo.h
netwerk/base/nsILoadInfo.idl
netwerk/protocol/http/nsCORSListenerProxy.cpp
uriloader/prefetch/nsPrefetchService.cpp
--- a/dom/base/EventSource.cpp
+++ b/dom/base/EventSource.cpp
@@ -673,17 +673,17 @@ EventSource::InitChannelAndRequestEventS
   nsIScriptContext* sc = GetContextForEventHandlers(&rv);
   nsCOMPtr<nsIDocument> doc =
     nsContentUtils::GetDocumentFromScriptContext(sc);
 
   nsSecurityFlags securityFlags =
     nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS;
 
   if (mWithCredentials) {
-    securityFlags |= nsILoadInfo::SEC_REQUIRE_CORS_WITH_CREDENTIALS;
+    securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
   }
 
   nsCOMPtr<nsIChannel> channel;
   // If we have the document, use it
   if (doc) {
     rv = NS_NewChannel(getter_AddRefs(channel),
                        mSrc,
                        doc,
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1200,17 +1200,17 @@ Navigator::SendBeacon(const nsAString& a
     return false;
   }
 
   nsCOMPtr<nsIChannel> channel;
   rv = NS_NewChannel(getter_AddRefs(channel),
                      uri,
                      doc,
                      nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS |
-                     nsILoadInfo::SEC_REQUIRE_CORS_WITH_CREDENTIALS,
+                       nsILoadInfo::SEC_COOKIES_INCLUDE,
                      nsIContentPolicy::TYPE_BEACON);
 
   if (NS_FAILED(rv)) {
     aRv.Throw(rv);
     return false;
   }
 
   nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
--- a/dom/base/nsScriptLoader.cpp
+++ b/dom/base/nsScriptLoader.cpp
@@ -293,17 +293,17 @@ nsScriptLoader::StartLoad(nsScriptLoadRe
   nsIDocShell *docshell = window->GetDocShell();
   nsCOMPtr<nsIInterfaceRequestor> prompter(do_QueryInterface(docshell));
 
   nsSecurityFlags securityFlags =
     aRequest->mCORSMode == CORS_NONE
     ? nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL
     : nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS;
   if (aRequest->mCORSMode == CORS_USE_CREDENTIALS) {
-    securityFlags |= nsILoadInfo::SEC_REQUIRE_CORS_WITH_CREDENTIALS;
+    securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
   }
   securityFlags |= nsILoadInfo::SEC_ALLOW_CHROME;
 
   nsCOMPtr<nsIChannel> channel;
   nsresult rv = NS_NewChannel(getter_AddRefs(channel),
                               aRequest->mURI,
                               context,
                               securityFlags,
--- a/dom/base/nsXMLHttpRequest.cpp
+++ b/dom/base/nsXMLHttpRequest.cpp
@@ -1686,16 +1686,20 @@ nsXMLHttpRequest::Open(const nsACString&
   }
   else {
     // Otherwise use CORS. Again, make sure that potential result documents
     // use the same principal as the loader.
     secFlags = nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS |
                nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
   }
 
+  if (mIsAnon) {
+    secFlags |= nsILoadInfo::SEC_COOKIES_OMIT;
+  }
+
   // If we have the document, use it. Unfortunately, for dedicated workers
   // 'doc' ends up being the parent document, which is not the document
   // that we want to use. So make sure to avoid using 'doc' in that situation.
   if (doc && doc->NodePrincipal() == mPrincipal) {
     rv = NS_NewChannel(getter_AddRefs(mChannel),
                        uri,
                        doc,
                        secFlags,
@@ -2789,28 +2793,27 @@ nsXMLHttpRequest::Send(nsIVariant* aVari
         // Reset the method to its original value
         httpChannel->SetRequestMethod(method);
       }
     }
   }
 
   ResetResponse();
 
-  bool withCredentials = !!(mState & XML_HTTP_REQUEST_AC_WITH_CREDENTIALS);
-
-  if (!IsSystemXHR() && withCredentials) {
+  if (!IsSystemXHR() && !mIsAnon &&
+      (mState & XML_HTTP_REQUEST_AC_WITH_CREDENTIALS)) {
     // This is quite sad. We have to create the channel in .open(), since the
     // chrome-only xhr.channel API depends on that. However .withCredentials
     // can be modified after, so we don't know what to set the
-    // SEC_REQUIRE_CORS_WITH_CREDENTIALS flag to when the channel is
+    // SEC_COOKIES_INCLUDE flag to when the channel is
     // created. So set it here using a hacky internal API.
 
     // Not doing this for system XHR uses since those don't use CORS.
     nsCOMPtr<nsILoadInfo> loadInfo = mChannel->GetLoadInfo();
-    static_cast<LoadInfo*>(loadInfo.get())->SetWithCredentialsSecFlag();
+    static_cast<LoadInfo*>(loadInfo.get())->SetIncludeCookiesSecFlag();
   }
 
   // Blocking gets are common enough out of XHR that we should mark
   // the channel slow by default for pipeline purposes
   AddLoadFlags(mChannel, nsIRequest::INHIBIT_PIPELINE);
 
   nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(mChannel));
   if (cos) {
@@ -2822,20 +2825,17 @@ nsXMLHttpRequest::Send(nsIVariant* aVari
 
   nsCOMPtr<nsIHttpChannelInternal>
     internalHttpChannel(do_QueryInterface(mChannel));
   if (internalHttpChannel) {
     // Disable Necko-internal response timeouts.
     internalHttpChannel->SetResponseTimeoutEnabled(false);
   }
 
-  if (mIsAnon) {
-    AddLoadFlags(mChannel, nsIRequest::LOAD_ANONYMOUS);
-  }
-  else {
+  if (!mIsAnon) {
     AddLoadFlags(mChannel, nsIChannel::LOAD_EXPLICIT_CREDENTIALS);
   }
 
   // When we are sync loading, we need to bypass the local cache when it would
   // otherwise block us waiting for exclusive access to the cache.  If we don't
   // do this, then we could dead lock in some cases (see bug 309424).
   //
   // Also don't block on the cache entry on async if it is busy - favoring parallelism
@@ -3245,18 +3245,19 @@ nsXMLHttpRequest::SetWithCredentials(boo
 }
 
 void
 nsXMLHttpRequest::SetWithCredentials(bool aWithCredentials, ErrorResult& aRv)
 {
   // Return error if we're already processing a request.  Note that we can't use
   // ReadyState() here, because it can't differentiate between "opened" and
   // "sent", so we use mState directly.
-  if (!(mState & XML_HTTP_REQUEST_UNSENT) &&
-      !(mState & XML_HTTP_REQUEST_OPENED)) {
+  if ((!(mState & XML_HTTP_REQUEST_UNSENT) &&
+       !(mState & XML_HTTP_REQUEST_OPENED)) ||
+      mIsAnon) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
   // sync request is not allowed setting withCredentials in window context
   if (HasOrHasHadOwner() &&
       !(mState & (XML_HTTP_REQUEST_UNSENT | XML_HTTP_REQUEST_ASYNC))) {
     LogMessage("WithCredentialsSyncXHRWarning", GetOwner());
--- a/dom/base/test/test_bug338583.html
+++ b/dom/base/test/test_bug338583.html
@@ -461,17 +461,16 @@ https://bugzilla.mozilla.org/show_bug.cg
       setTestHasFinished(test_id);
     }, parseInt(3000*stress_factor));
   }
 
   function doTest5_c(test_id)
   {
     // credentials using the auth cache
     var xhr = new XMLHttpRequest({mozAnon: true, mozSystem: true});
-    xhr.withCredentials = true;
     // also, test mixed mode UI
     xhr.open("GET", "https://example.com/tests/dom/base/test/file_restrictedEventSource.sjs?test=user1_xhr", true, "user 1", "password 1");
     xhr.send();
     xhr.onloadend = function() {
       ok(xhr.status == 200, "Failed to set credentials in test 5.c");
 
       gEventSourceObj5_c = new EventSource("https://example.com/tests/dom/base/test/file_restrictedEventSource.sjs?test=user1_evtsrc",
                                            { withCredentials: true } );
@@ -490,17 +489,16 @@ https://bugzilla.mozilla.org/show_bug.cg
         doTest5_d(test_id);
       }, parseInt(3000*stress_factor));
     };
   }
 
   function doTest5_d(test_id)
   {
     var xhr = new XMLHttpRequest({mozAnon: true, mozSystem: true});
-    xhr.withCredentials = true;
     xhr.open("GET", "https://example.com/tests/dom/base/test/file_restrictedEventSource.sjs?test=user2_xhr", true, "user 2", "password 2");
     xhr.send();
     xhr.onloadend = function() {
       ok(xhr.status == 200, "Failed to set credentials in test 5.d");
   
       gEventSourceObj5_d = new EventSource("https://example.com/tests/dom/base/test/file_restrictedEventSource.sjs?test=user2_evtsrc");
       ok(!gEventSourceObj5_d.withCredentials, "Wrong withCredentials in test 5.d");
   
@@ -518,17 +516,16 @@ https://bugzilla.mozilla.org/show_bug.cg
       }, parseInt(3000*stress_factor));
     };
   }
 
   function doTest5_e(test_id)
   {
     // credentials using the auth cache
     var xhr = new XMLHttpRequest({mozAnon: true, mozSystem: true});
-    xhr.withCredentials = true;
     xhr.open("GET", "http://example.org/tests/dom/base/test/file_restrictedEventSource.sjs?test=user1_xhr", true, "user 1", "password 1");
     xhr.send();
     xhr.onloadend = function() {
       ok(xhr.status == 200, "Failed to set credentials in test 5.e");
 
       gEventSourceObj5_e = new EventSource("http://example.org/tests/dom/base/test/file_restrictedEventSource.sjs?test=user1_evtsrc",
                                            { get withCredentials() { return true; } } );
       ok(gEventSourceObj5_e.withCredentials, "Wrong withCredentials in test 5.e");
@@ -546,17 +543,16 @@ https://bugzilla.mozilla.org/show_bug.cg
         doTest5_f(test_id);
       }, parseInt(5000*stress_factor));
     };
   }
 
   function doTest5_f(test_id)
   {
     var xhr = new XMLHttpRequest({mozAnon: true, mozSystem: true});
-    xhr.withCredentials = true;
     xhr.open("GET", "http://example.org/tests/dom/base/test/file_restrictedEventSource.sjs?test=user2_xhr", true, "user 2", "password 2");
     xhr.send();
     xhr.onloadend = function() {
       ok(xhr.status == 200, "Failed to set credentials in test 5.f");
 
       gEventSourceObj5_f = new EventSource("http://example.org/tests/dom/base/test/file_restrictedEventSource.sjs?test=user2_evtsrc",
                                            { });
       ok(!gEventSourceObj5_f.withCredentials, "Wrong withCredentials in test 5.f");
--- a/dom/fetch/FetchDriver.cpp
+++ b/dom/fetch/FetchDriver.cpp
@@ -38,17 +38,17 @@
 #include "Fetch.h"
 #include "InternalRequest.h"
 #include "InternalResponse.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_ISUPPORTS(FetchDriver,
-                  nsIStreamListener, nsIChannelEventSink, nsIInterfaceRequestor,
+                  nsIStreamListener, nsIInterfaceRequestor,
                   nsIThreadRetargetableStreamListener)
 
 FetchDriver::FetchDriver(InternalRequest* aRequest, nsIPrincipal* aPrincipal,
                          nsILoadGroup* aLoadGroup)
   : mPrincipal(aPrincipal)
   , mLoadGroup(aLoadGroup)
   , mRequest(aRequest)
   , mResponseAvailableCalled(false)
@@ -93,26 +93,16 @@ FetchDriver::ContinueFetch()
   nsresult rv = HttpFetch();
   if (NS_FAILED(rv)) {
     FailWithNetworkError();
   }
  
   return rv;
 }
 
-static void
-AddLoadFlags(nsIRequest *aRequest, nsLoadFlags aNewFlags)
-{
-  MOZ_ASSERT(aRequest);
-  nsLoadFlags flags;
-  aRequest->GetLoadFlags(&flags);
-  flags |= aNewFlags;
-  aRequest->SetLoadFlags(flags);
-}
-
 // This function implements the "HTTP Fetch" algorithm from the Fetch spec.
 // Functionality is often split between here, the CORS listener proxy and the
 // Necko HTTP implementation.
 nsresult
 FetchDriver::HttpFetch()
 {
   // Step 1. "Let response be null."
   mResponse = nullptr;
@@ -163,93 +153,79 @@ FetchDriver::HttpFetch()
   // is true, and unset otherwise."
 
   // Set skip serviceworker flag.
   // While the spec also gates on the client being a ServiceWorker, we can't
   // infer that here. Instead we rely on callers to set the flag correctly.
   const nsLoadFlags bypassFlag = mRequest->SkipServiceWorker() ?
                                  nsIChannel::LOAD_BYPASS_SERVICE_WORKER : 0;
 
-  nsSecurityFlags secFlags;
-  if (mRequest->Mode() == RequestMode::Cors &&
-      mRequest->GetCredentialsMode() == RequestCredentials::Include) {
-    secFlags = nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS |
-               nsILoadInfo::SEC_REQUIRE_CORS_WITH_CREDENTIALS;
-  } else if (mRequest->Mode() == RequestMode::Cors) {
-    secFlags = nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS;
+  nsSecurityFlags secFlags = nsILoadInfo::SEC_ABOUT_BLANK_INHERITS;
+  if (mRequest->Mode() == RequestMode::Cors) {
+    secFlags |= nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS;
   } else if (mRequest->Mode() == RequestMode::Same_origin) {
-    secFlags = nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS;
+    secFlags |= nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS;
   } else if (mRequest->Mode() == RequestMode::No_cors) {
-    secFlags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS;
+    secFlags |= nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS;
   } else {
     MOZ_ASSERT_UNREACHABLE("Unexpected request mode!");
     return NS_ERROR_UNEXPECTED;
   }
 
   if (mRequest->GetRedirectMode() != RequestRedirect::Follow) {
     secFlags |= nsILoadInfo::SEC_DONT_FOLLOW_REDIRECTS;
   }
 
+  // This is handles the use credentials flag in "HTTP
+  // network or cache fetch" in the spec and decides whether to transmit
+  // cookies and other identifying information.
+  if (mRequest->GetCredentialsMode() == RequestCredentials::Include) {
+    secFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
+  } else if (mRequest->GetCredentialsMode() == RequestCredentials::Omit) {
+    secFlags |= nsILoadInfo::SEC_COOKIES_OMIT;
+  } else if (mRequest->GetCredentialsMode() == RequestCredentials::Same_origin) {
+    secFlags |= nsILoadInfo::SEC_COOKIES_SAME_ORIGIN;
+  } else {
+    MOZ_ASSERT_UNREACHABLE("Unexpected credentials mode!");
+    return NS_ERROR_UNEXPECTED;
+  }
+
   // From here on we create a channel and set its properties with the
   // information from the InternalRequest. This is an implementation detail.
   MOZ_ASSERT(mLoadGroup);
   nsCOMPtr<nsIChannel> chan;
 
   nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL |
     bypassFlag | nsIChannel::LOAD_CLASSIFY_URI;
   if (mDocument) {
     MOZ_ASSERT(mDocument->NodePrincipal() == mPrincipal);
     rv = NS_NewChannel(getter_AddRefs(chan),
                        uri,
                        mDocument,
-                       secFlags |
-                         nsILoadInfo::SEC_ABOUT_BLANK_INHERITS,
+                       secFlags,
                        mRequest->ContentPolicyType(),
                        mLoadGroup,
                        nullptr, /* aCallbacks */
                        loadFlags,
                        ios);
   } else {
     rv = NS_NewChannel(getter_AddRefs(chan),
                        uri,
                        mPrincipal,
-                       secFlags |
-                         nsILoadInfo::SEC_ABOUT_BLANK_INHERITS,
+                       secFlags,
                        mRequest->ContentPolicyType(),
                        mLoadGroup,
                        nullptr, /* aCallbacks */
                        loadFlags,
                        ios);
   }
   NS_ENSURE_SUCCESS(rv, rv);
 
   mLoadGroup = nullptr;
 
-  // Insert ourselves into the notification callbacks chain so we can handle
-  // cross-origin redirects.
-#ifdef DEBUG
-  {
-    nsCOMPtr<nsIInterfaceRequestor> notificationCallbacks;
-    chan->GetNotificationCallbacks(getter_AddRefs(notificationCallbacks));
-    MOZ_ASSERT(!notificationCallbacks);
-  }
-#endif
-  chan->SetNotificationCallbacks(this);
-
-  // This is effectivetly the opposite of the use credentials flag in "HTTP
-  // network or cache fetch" in the spec and decides whether to transmit
-  // cookies and other identifying information. LOAD_ANONYMOUS also prevents
-  // new cookies sent by the server from being stored.  This value will
-  // propagate across redirects, which is what we want.
-  if (mRequest->GetCredentialsMode() == RequestCredentials::Omit ||
-      (mRequest->GetCredentialsMode() == RequestCredentials::Same_origin &&
-       NS_HasBeenCrossOrigin(chan))) {
-    AddLoadFlags(chan, nsIRequest::LOAD_ANONYMOUS);
-  }
-
   // FIXME(nsm): Bug 1120715.
   // Step 3.4 "If request's cache mode is default and request's header list
   // contains a header named `If-Modified-Since`, `If-None-Match`,
   // `If-Unmodified-Since`, `If-Match`, or `If-Range`, set request's cache mode
   // to no-store."
 
   // Step 3.5 begins "HTTP network or cache fetch".
   // HTTP network or cache fetch
@@ -693,109 +669,25 @@ FetchDriver::OnStopRequest(nsIRequest* a
   if (mObserver) {
     mObserver->OnResponseEnd();
     mObserver = nullptr;
   }
 
   return NS_OK;
 }
 
-// This is called when the channel is redirected.
-NS_IMETHODIMP
-FetchDriver::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
-                                    nsIChannel* aNewChannel,
-                                    uint32_t aFlags,
-                                    nsIAsyncVerifyRedirectCallback *aCallback)
-{
-  NS_PRECONDITION(aNewChannel, "Redirect without a channel?");
-
-  // We should only ever get here if we use a "follow" redirect policy,
-  // or if if we set an "error" policy as a result of a CORS policy.
-  MOZ_ASSERT(NS_IsInternalSameURIRedirect(aOldChannel, aNewChannel, aFlags) ||
-             NS_IsHSTSUpgradeRedirect(aOldChannel, aNewChannel, aFlags) ||
-             mRequest->GetRedirectMode() == RequestRedirect::Follow);
-
-  // HTTP Fetch step 5, "redirect status", step 1 is done by necko
-
-  // HTTP Fetch step 5, "redirect status", steps 2 through 6 are automatically
-  // handled by necko before calling AsyncOnChannelRedirect() with the new
-  // nsIChannel.
-
-  // HTTP Fetch step 5, "redirect status", steps 7 and 8 enforcing a redirect
-  // count are done by Necko.  The pref used is "network.http.redirection-limit"
-  // which is set to 20 by default.
-
-  // HTTP Fetch Step 9, "redirect status". This is enforced by the
-  // nsCORSListenerProxy. It forbids redirecting to data:
-
-  // HTTP Fetch step 5, "redirect status", step 10 requires us to halt the
-  // redirect, but successfully return an opaqueredirect Response to the
-  // initiating Fetch.
-
-  // The following steps are from HTTP Fetch step 5, "redirect status", step 11
-  // which requires the RequestRedirect to be "follow". We asserted that we're
-  // in either "follow" or "error" mode here.
-
-  // HTTP Fetch step 5, "redirect status", steps 11.1 and 11.2 block redirecting
-  // to a URL with credentials in CORS mode.  This is implemented in
-  // nsCORSListenerProxy.
-
-  // Implement Main Fetch step 8 again on redirect.
-
-  // Requests that require preflight are not permitted to redirect.
-  // Fetch spec section 4.2 "HTTP Fetch", step 4.9 just uses the manual
-  // redirect flag to decide whether to execute step 4.10 or not. We do not
-  // represent it in our implementation.
-  // This is handled by nsCORSListenerProxy.
-
-  // Otherwise, we rely on necko and the CORS proxy to do the right thing
-  // as the redirect is followed.  In general this means http
-  // fetch.  If we've ever been CORS, we need to stay CORS.
-
-  // Possibly set the LOAD_ANONYMOUS flag on the channel.
-  if (mRequest->GetCredentialsMode() == RequestCredentials::Same_origin &&
-      NS_HasBeenCrossOrigin(aNewChannel)) {
-    AddLoadFlags(aNewChannel, nsIRequest::LOAD_ANONYMOUS);
-  }
-
-#ifdef DEBUG
-  {
-    // Make sure nothing in the redirect chain screws up our credentials
-    // settings. LOAD_ANONYMOUS must be set if we RequestCredentials is "omit"
-    // or "same-origin".
-    nsLoadFlags flags;
-    aNewChannel->GetLoadFlags(&flags);
-    bool shouldBeAnon =
-      mRequest->GetCredentialsMode() == RequestCredentials::Omit ||
-      (NS_HasBeenCrossOrigin(aNewChannel) &&
-       mRequest->GetCredentialsMode() == RequestCredentials::Same_origin);
-    MOZ_ASSERT(!!(flags & nsIRequest::LOAD_ANONYMOUS) == shouldBeAnon);
-  }
-#endif
-
-  aCallback->OnRedirectVerifyCallback(NS_OK);
-
-  return NS_OK;
-}
-
 NS_IMETHODIMP
 FetchDriver::CheckListenerChain()
 {
   return NS_OK;
 }
 
 NS_IMETHODIMP
 FetchDriver::GetInterface(const nsIID& aIID, void **aResult)
 {
-  if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
-    *aResult = static_cast<nsIChannelEventSink*>(this);
-    NS_ADDREF_THIS();
-    return NS_OK;
-  }
-
   if (aIID.Equals(NS_GET_IID(nsIStreamListener))) {
     *aResult = static_cast<nsIStreamListener*>(this);
     NS_ADDREF_THIS();
     return NS_OK;
   }
   if (aIID.Equals(NS_GET_IID(nsIRequestObserver))) {
     *aResult = static_cast<nsIRequestObserver*>(this);
     NS_ADDREF_THIS();
--- a/dom/fetch/FetchDriver.h
+++ b/dom/fetch/FetchDriver.h
@@ -50,25 +50,23 @@ protected:
 
   virtual void OnResponseAvailableInternal(InternalResponse* aResponse) = 0;
 
 private:
   bool mGotResponseAvailable;
 };
 
 class FetchDriver final : public nsIStreamListener,
-                          public nsIChannelEventSink,
                           public nsIInterfaceRequestor,
                           public nsIThreadRetargetableStreamListener
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSISTREAMLISTENER
-  NS_DECL_NSICHANNELEVENTSINK
   NS_DECL_NSIINTERFACEREQUESTOR
   NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
 
   explicit FetchDriver(InternalRequest* aRequest, nsIPrincipal* aPrincipal,
                        nsILoadGroup* aLoadGroup);
   NS_IMETHOD Fetch(FetchDriverObserver* aObserver);
 
   void
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -1284,17 +1284,17 @@ nsresult HTMLMediaElement::LoadResource(
   }
 
   // determine what security checks need to be performed in AsyncOpen2().
   nsSecurityFlags securityFlags =
     ShouldCheckAllowOrigin() ? nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS :
                                nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS;
 
   if (GetCORSMode() == CORS_USE_CREDENTIALS) {
-    securityFlags |= nsILoadInfo::SEC_REQUIRE_CORS_WITH_CREDENTIALS;
+    securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
   }
 
   MOZ_ASSERT(IsAnyOfHTMLElements(nsGkAtoms::audio, nsGkAtoms::video));
   nsContentPolicyType contentPolicyType = IsHTMLElement(nsGkAtoms::audio) ?
     nsIContentPolicy::TYPE_INTERNAL_AUDIO : nsIContentPolicy::TYPE_INTERNAL_VIDEO;
 
   nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
   nsCOMPtr<nsIChannel> channel;
--- a/dom/security/nsContentSecurityManager.cpp
+++ b/dom/security/nsContentSecurityManager.cpp
@@ -21,22 +21,16 @@ ValidateSecurityFlags(nsILoadInfo* aLoad
       securityMode != nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED &&
       securityMode != nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS &&
       securityMode != nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL &&
       securityMode != nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS) {
     MOZ_ASSERT(false, "need one securityflag from nsILoadInfo to perform security checks");
     return NS_ERROR_FAILURE;
   }
 
-  // make sure that cors-with-credentials is only used in combination with CORS.
-  if (aLoadInfo->GetRequireCorsWithCredentials() &&
-      securityMode != nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS) {
-    MOZ_ASSERT(false, "can not use cors-with-credentials without cors");
-    return NS_ERROR_FAILURE;
-  }
   // all good, found the right security flags
   return NS_OK;
 }
 
 static bool SchemeIs(nsIURI* aURI, const char* aScheme)
 {
   nsCOMPtr<nsIURI> baseURI = NS_GetInnermostURI(aURI);
   NS_ENSURE_TRUE(baseURI, false);
@@ -110,17 +104,18 @@ static nsresult
 DoCORSChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo,
              nsCOMPtr<nsIStreamListener>& aInAndOutListener)
 {
   MOZ_RELEASE_ASSERT(aInAndOutListener, "can not perform CORS checks without a listener");
   nsIPrincipal* loadingPrincipal = aLoadInfo->LoadingPrincipal();
   RefPtr<nsCORSListenerProxy> corsListener =
     new nsCORSListenerProxy(aInAndOutListener,
                             loadingPrincipal,
-                            aLoadInfo->GetRequireCorsWithCredentials());
+                            aLoadInfo->GetCookiePolicy() ==
+                              nsILoadInfo::SEC_COOKIES_INCLUDE);
   // XXX: @arg: DataURIHandling::Allow
   // lets use  DataURIHandling::Allow for now and then decide on callsite basis. see also:
   // http://mxr.mozilla.org/mozilla-central/source/dom/security/nsCORSListenerProxy.h#33
   nsresult rv = corsListener->Init(aChannel, DataURIHandling::Allow);
   NS_ENSURE_SUCCESS(rv, rv);
   aInAndOutListener = corsListener;
   return NS_OK;
 }
@@ -417,41 +412,65 @@ nsContentSecurityManager::AsyncOnChannel
         CheckLoadURIWithPrincipal(oldPrincipal, newOriginalURI, flags);
   }
   NS_ENSURE_SUCCESS(rv, rv);  
 
   aCb->OnRedirectVerifyCallback(NS_OK);
   return NS_OK;
 }
 
+static void
+AddLoadFlags(nsIRequest *aRequest, nsLoadFlags aNewFlags)
+{
+  nsLoadFlags flags;
+  aRequest->GetLoadFlags(&flags);
+  flags |= aNewFlags;
+  aRequest->SetLoadFlags(flags);
+}
+
 /*
  * Check that this channel passes all security checks. Returns an error code
  * if this requesst should not be permitted.
  */
 nsresult
 nsContentSecurityManager::CheckChannel(nsIChannel* aChannel)
 {
   nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
   MOZ_ASSERT(loadInfo);
 
+  nsCOMPtr<nsIURI> uri;
+  nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Handle cookie policies
+  uint32_t cookiePolicy = loadInfo->GetCookiePolicy();
+  if (cookiePolicy == nsILoadInfo::SEC_COOKIES_SAME_ORIGIN) {
+    nsIPrincipal* loadingPrincipal = loadInfo->LoadingPrincipal();
+
+    // It doesn't matter what we pass for the third, data-inherits, argument.
+    // Any protocol which inherits won't pay attention to cookies anyway.
+    rv = loadingPrincipal->CheckMayLoad(uri, false, false);
+    if (NS_FAILED(rv)) {
+      AddLoadFlags(aChannel, nsIRequest::LOAD_ANONYMOUS);
+    }
+  }
+  else if (cookiePolicy == nsILoadInfo::SEC_COOKIES_OMIT) {
+    AddLoadFlags(aChannel, nsIRequest::LOAD_ANONYMOUS);
+  }
+
   nsSecurityFlags securityMode = loadInfo->GetSecurityMode();
 
   // CORS mode is handled by nsCORSListenerProxy
   if (securityMode == nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS) {
     if (NS_HasBeenCrossOrigin(aChannel)) {
       loadInfo->MaybeIncreaseTainting(LoadTainting::CORS);
     }
     return NS_OK;
   }
 
-  nsCOMPtr<nsIURI> uri;
-  nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-
   // if none of the REQUIRE_SAME_ORIGIN flags are set, then SOP does not apply
   if ((securityMode == nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS) ||
       (securityMode == nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED)) {
     rv = DoSOPChecks(uri, loadInfo, aChannel);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   if ((securityMode == nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS) ||
--- a/netwerk/base/LoadInfo.cpp
+++ b/netwerk/base/LoadInfo.cpp
@@ -264,24 +264,16 @@ LoadInfo::LoadingNode()
 
 NS_IMETHODIMP
 LoadInfo::GetSecurityFlags(nsSecurityFlags* aResult)
 {
   *aResult = mSecurityFlags;
   return NS_OK;
 }
 
-void
-LoadInfo::SetWithCredentialsSecFlag()
-{
-  MOZ_ASSERT(!mEnforceSecurity,
-             "Request should not have been opened yet");
-  mSecurityFlags |= nsILoadInfo::SEC_REQUIRE_CORS_WITH_CREDENTIALS;
-}
-
 NS_IMETHODIMP
 LoadInfo::GetSecurityMode(uint32_t* aFlags)
 {
   *aFlags = (mSecurityFlags &
               (nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_INHERITS |
                nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED |
                nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS |
                nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL |
@@ -291,24 +283,46 @@ LoadInfo::GetSecurityMode(uint32_t* aFla
 
 NS_IMETHODIMP
 LoadInfo::GetIsInThirdPartyContext(bool* aIsInThirdPartyContext)
 {
   *aIsInThirdPartyContext = mIsThirdPartyContext;
   return NS_OK;
 }
 
+static const uint32_t sCookiePolicyMask =
+  nsILoadInfo::SEC_COOKIES_DEFAULT |
+  nsILoadInfo::SEC_COOKIES_INCLUDE |
+  nsILoadInfo::SEC_COOKIES_SAME_ORIGIN |
+  nsILoadInfo::SEC_COOKIES_OMIT;
+
 NS_IMETHODIMP
-LoadInfo::GetRequireCorsWithCredentials(bool* aResult)
+LoadInfo::GetCookiePolicy(uint32_t *aResult)
 {
-  *aResult =
-    (mSecurityFlags & nsILoadInfo::SEC_REQUIRE_CORS_WITH_CREDENTIALS);
+  uint32_t policy = mSecurityFlags & sCookiePolicyMask;
+  if (policy == nsILoadInfo::SEC_COOKIES_DEFAULT) {
+    policy = (mSecurityFlags & SEC_REQUIRE_CORS_DATA_INHERITS) ?
+      nsILoadInfo::SEC_COOKIES_SAME_ORIGIN : nsILoadInfo::SEC_COOKIES_INCLUDE;
+  }
+
+  *aResult = policy;
   return NS_OK;
 }
 
+void
+LoadInfo::SetIncludeCookiesSecFlag()
+{
+  MOZ_ASSERT(!mEnforceSecurity,
+             "Request should not have been opened yet");
+  MOZ_ASSERT((mSecurityFlags & sCookiePolicyMask) ==
+             nsILoadInfo::SEC_COOKIES_DEFAULT);
+  mSecurityFlags = (mSecurityFlags & ~sCookiePolicyMask) |
+                   nsILoadInfo::SEC_COOKIES_INCLUDE;
+}
+
 NS_IMETHODIMP
 LoadInfo::GetForceInheritPrincipal(bool* aInheritPrincipal)
 {
   *aInheritPrincipal =
     (mSecurityFlags & nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL);
   return NS_OK;
 }
 
--- a/netwerk/base/LoadInfo.h
+++ b/netwerk/base/LoadInfo.h
@@ -96,17 +96,17 @@ private:
 
   ~LoadInfo();
 
   void ComputeIsThirdPartyContext(nsPIDOMWindow* aOuterWindow);
 
   // This function is the *only* function which can change the securityflags
   // of a loadinfo. It only exists because of the XHR code. Don't call it
   // from anywhere else!
-  void SetWithCredentialsSecFlag();
+  void SetIncludeCookiesSecFlag();
   friend class ::nsXMLHttpRequest;
 
   // if you add a member, please also update the copy constructor
   nsCOMPtr<nsIPrincipal>           mLoadingPrincipal;
   nsCOMPtr<nsIPrincipal>           mTriggeringPrincipal;
   nsWeakPtr                        mLoadingContext;
   nsSecurityFlags                  mSecurityFlags;
   nsContentPolicyType              mInternalContentPolicyType;
--- a/netwerk/base/nsILoadInfo.idl
+++ b/netwerk/base/nsILoadInfo.idl
@@ -24,17 +24,17 @@ native NeckoOriginAttributes(mozilla::Ne
 [ref] native const_OriginAttributesRef(const mozilla::NeckoOriginAttributes);
 [ref] native StringArrayRef(const nsTArray<nsCString>);
 
 typedef unsigned long nsSecurityFlags;
 
 /**
  * An nsILoadOwner represents per-load information about who started the load.
  */
-[scriptable, builtinclass, uuid(b7b9830e-013e-4ba0-b6c6-a0fc669f4980)]
+[scriptable, builtinclass, uuid(41e311d0-5894-4aaa-80b5-5b7099dfc404)]
 interface nsILoadInfo : nsISupports
 {
   /**
    * No special security flags:
    */
   const unsigned long SEC_NORMAL = 0;
 
   /**
@@ -84,73 +84,83 @@ interface nsILoadInfo : nsISupports
    * loads. Loads from data: are allowed and the result will inherit
    * the principal of the origin that triggered the load.
    * Commonly used by <img crossorigin>, <video crossorigin>,
    * XHR, fetch(), etc.
    */
   const unsigned long SEC_REQUIRE_CORS_DATA_INHERITS = (1<<4);
 
   /**
-   * Use this flag in addition to SEC_REQUIRE_CORS_DATA_INHERITS
-   * to make cross-origin CORS loads happen with credentials
-   * (such as cookies and client side certs).
+   * Choose cookie policy. The default policy is equivalent to "INCLUDE" for
+   * SEC_REQUIRE_SAME_ORIGIN_* and SEC_ALLOW_CROSS_ORIGIN_* modes, and
+   * equivalent to "SAME_ORIGIN" for SEC_REQUIRE_CORS_DATA_INHERITS mode.
+   *
+   * This means that if you want to perform a CORS load with credentials, pass
+   * SEC_COOKIES_INCLUDE.
+   *
+   * Note that these flags are still subject to the user's cookie policies.
+   * For example, if the user is blocking 3rd party cookies, those cookies
+   * will be blocked no matter which of these flags are set.
    */
-  const unsigned long SEC_REQUIRE_CORS_WITH_CREDENTIALS = (1<<5);
+  const unsigned long SEC_COOKIES_DEFAULT = (0 << 5);
+  const unsigned long SEC_COOKIES_INCLUDE = (1 << 5);
+  const unsigned long SEC_COOKIES_SAME_ORIGIN = (2 << 5);
+  const unsigned long SEC_COOKIES_OMIT = (3 << 5);
 
   /**
    * Force inheriting of the Principal. The resulting resource will use the
    * principal of the document which is doing the load. Setting this flag
    * will cause GetChannelResultPrincipal to return the same principal as
    * the loading principal that's passed in when creating the channel.
    *
    * This will happen independently of the scheme of the URI that the
    * channel is loading.
    *
    * So if the loading document comes from "http://a.com/", and the channel
    * is loading the URI "http://b.com/whatever", GetChannelResultPrincipal
    * will return a principal from "http://a.com/".
    *
    * This flag can not be used together with SEC_SANDBOXED.
    */
-  const unsigned long SEC_FORCE_INHERIT_PRINCIPAL = (1<<6);
+  const unsigned long SEC_FORCE_INHERIT_PRINCIPAL = (1<<7);
 
   /**
    * Sandbox the load. The resulting resource will use a freshly created
    * null principal. So GetChannelResultPrincipal will always return a
    * null principal whenever this flag is set.
    *
    * This will happen independently of the scheme of the URI that the
    * channel is loading.
    *
    * This flag can not be used together with SEC_FORCE_INHERIT_PRINCIPAL.
    */
-  const unsigned long SEC_SANDBOXED = (1<<7);
+  const unsigned long SEC_SANDBOXED = (1<<8);
 
   /**
    * Inherit the Principal for about:blank.
    */
-  const unsigned long SEC_ABOUT_BLANK_INHERITS = (1<<8);
+  const unsigned long SEC_ABOUT_BLANK_INHERITS = (1<<9);
 
   /**
    * Allow access to chrome: packages that are content accessible.
    */
-  const unsigned long SEC_ALLOW_CHROME = (1<<9);
+  const unsigned long SEC_ALLOW_CHROME = (1<<10);
 
   /**
    * Don't follow redirects. Instead the redirect response is returned
    * as a successful response for the channel.
    *
    * Redirects not initiated by a server response, i.e. REDIRECT_INTERNAL and
    * REDIRECT_STS_UPGRADE, are still followed.
    *
    * Note: If this flag is set and the channel response is a redirect, then
    * the response body might not be available.
    * This can happen if the redirect was cached.
    */
-  const unsigned long SEC_DONT_FOLLOW_REDIRECTS = (1<<10);
+  const unsigned long SEC_DONT_FOLLOW_REDIRECTS = (1<<11);
 
   /**
    * The loadingPrincipal is the principal that is responsible for the load.
    * It is *NOT* the principal tied to the resource/URI that this
    * channel is loading, it's the principal of the resource's
    * caller or requester. For example, if this channel is loading
    * an image from http://b.com that is embedded in a document
    * who's origin is http://a.com, the loadingPrincipal is http://a.com.
@@ -239,20 +249,22 @@ interface nsILoadInfo : nsISupports
    * True if this request is embedded in a context that can't be third-party
    * (i.e. an iframe embedded in a cross-origin parent window). If this is
    * false, then this request may be third-party if it's a third-party to
    * loadingPrincipal.
    */
   [infallible] readonly attribute boolean isInThirdPartyContext;
 
   /**
-   * Determines whether credentials are sent with CORS requests.
-   * Using this flag requires SEC_REQUIRE_CORS_DATA_INHERITS also to be set.
+   * See the SEC_COOKIES_* flags above. This attribute will never return
+   * SEC_COOKIES_DEFAULT, but will instead return what the policy resolves to.
+   * I.e. SEC_COOKIES_SAME_ORIGIN for CORS mode, and SEC_COOKIES_INCLUDE
+   * otherwise.
    */
-  [infallible] readonly attribute boolean requireCorsWithCredentials;
+  [infallible] readonly attribute unsigned long cookiePolicy;
 
   /**
    * If forceInheritPrincipal is true, the data coming from the channel should
    * use loadingPrincipal for its principal, even when the data is loaded over
    * http:// or another protocol that would normally use a URI-based principal.
    * This attribute will never be true when loadingSandboxed is true.
    */
   [infallible] readonly attribute boolean forceInheritPrincipal;
--- a/netwerk/protocol/http/nsCORSListenerProxy.cpp
+++ b/netwerk/protocol/http/nsCORSListenerProxy.cpp
@@ -816,26 +816,26 @@ nsCORSListenerProxy::UpdateChannel(nsICh
                                    DataURIHandling aAllowDataURI)
 {
   nsCOMPtr<nsIURI> uri, originalURI;
   nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
   NS_ENSURE_SUCCESS(rv, rv);
   rv = aChannel->GetOriginalURI(getter_AddRefs(originalURI));
   NS_ENSURE_SUCCESS(rv, rv);
 
+  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
+
   // exempt data URIs from the same origin check.
   if (aAllowDataURI == DataURIHandling::Allow && originalURI == uri) {
     bool dataScheme = false;
     rv = uri->SchemeIs("data", &dataScheme);
     NS_ENSURE_SUCCESS(rv, rv);
     if (dataScheme) {
       return NS_OK;
     }
-    nsCOMPtr<nsILoadInfo> loadInfo;
-    aChannel->GetLoadInfo(getter_AddRefs(loadInfo));
     if (loadInfo && loadInfo->GetAboutBlankInherits() &&
         NS_IsAboutBlank(uri)) {
       return NS_OK;
     }
   }
 
   // Set CORS attributes on channel so that intercepted requests get correct
   // values. We have to do this here because the CheckMayLoad checks may lead
@@ -899,18 +899,21 @@ nsCORSListenerProxy::UpdateChannel(nsICh
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIHttpChannel> http = do_QueryInterface(aChannel);
   NS_ENSURE_TRUE(http, NS_ERROR_FAILURE);
 
   rv = http->SetRequestHeader(NS_LITERAL_CSTRING("Origin"), origin, false);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // Make cookie-less if needed
-  if (!mWithCredentials) {
+  // Make cookie-less if needed. We don't need to do anything here if the
+  // channel was opened with AsyncOpen2, since then AsyncOpen2 will take
+  // care of the cookie policy for us.
+  if (!mWithCredentials &&
+      (!loadInfo || !loadInfo->GetEnforceSecurity())) {
     nsLoadFlags flags;
     rv = http->GetLoadFlags(&flags);
     NS_ENSURE_SUCCESS(rv, rv);
 
     flags |= nsIRequest::LOAD_ANONYMOUS;
     rv = http->SetLoadFlags(flags);
     NS_ENSURE_SUCCESS(rv, rv);
   }
@@ -1332,17 +1335,18 @@ nsCORSListenerProxy::StartCORSPreflight(
     return NS_ERROR_FAILURE;
   }
 
   MOZ_ASSERT(originalLoadInfo->GetSecurityMode() ==
              nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS,
              "how did we end up here?");
 
   nsCOMPtr<nsIPrincipal> principal = originalLoadInfo->LoadingPrincipal();
-  bool withCredentials = originalLoadInfo->GetRequireCorsWithCredentials();
+  bool withCredentials = originalLoadInfo->GetCookiePolicy() ==
+    nsILoadInfo::SEC_COOKIES_INCLUDE;
 
   nsPreflightCache::CacheEntry* entry =
     sPreflightCache ?
     sPreflightCache->GetEntry(uri, principal, withCredentials, false) :
     nullptr;
 
   if (entry && entry->CheckRequest(method, aUnsafeHeaders)) {
     aCallback->OnPreflightSucceeded();
--- a/uriloader/prefetch/nsPrefetchService.cpp
+++ b/uriloader/prefetch/nsPrefetchService.cpp
@@ -101,17 +101,17 @@ nsPrefetchNode::OpenChannel()
       corsMode = static_cast<dom::HTMLLinkElement*>(source.get())->GetCORSMode();
     }
     uint32_t securityFlags;
     if (corsMode == CORS_NONE) {
       securityFlags = nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS;
     } else {
       securityFlags = nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS;
       if (corsMode == CORS_USE_CREDENTIALS) {
-        securityFlags |= nsILoadInfo::SEC_REQUIRE_CORS_WITH_CREDENTIALS;
+        securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
       }
     }
     nsresult rv = NS_NewChannelInternal(getter_AddRefs(mChannel),
                                         mURI,
                                         source,
                                         source->NodePrincipal(),
                                         nullptr,   //aTriggeringPrincipal
                                         securityFlags,