diff --git a/dom/base/EventSource.cpp b/dom/base/EventSource.cpp index f287e74e5b8d..6b2139ca18c4 100644 --- a/dom/base/EventSource.cpp +++ b/dom/base/EventSource.cpp @@ -678,7 +678,7 @@ EventSource::InitChannelAndRequestEventSource() nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS; if (mWithCredentials) { - securityFlags |= nsILoadInfo::SEC_REQUIRE_CORS_WITH_CREDENTIALS; + securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE; } nsCOMPtr channel; diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp index bd289776aef1..e04ec7d25466 100644 --- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -1205,7 +1205,7 @@ Navigator::SendBeacon(const nsAString& aUrl, 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)) { diff --git a/dom/base/nsScriptLoader.cpp b/dom/base/nsScriptLoader.cpp index d80574247a91..d7c2182d3d49 100644 --- a/dom/base/nsScriptLoader.cpp +++ b/dom/base/nsScriptLoader.cpp @@ -298,7 +298,7 @@ nsScriptLoader::StartLoad(nsScriptLoadRequest *aRequest, const nsAString &aType, ? 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; diff --git a/dom/base/nsXMLHttpRequest.cpp b/dom/base/nsXMLHttpRequest.cpp index fd62f01c8dab..74cc2fd5cd0f 100644 --- a/dom/base/nsXMLHttpRequest.cpp +++ b/dom/base/nsXMLHttpRequest.cpp @@ -1691,6 +1691,10 @@ nsXMLHttpRequest::Open(const nsACString& inMethod, const nsACString& url, 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. @@ -2794,18 +2798,17 @@ nsXMLHttpRequest::Send(nsIVariant* aVariant, const Nullable& aBody) 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 loadInfo = mChannel->GetLoadInfo(); - static_cast(loadInfo.get())->SetWithCredentialsSecFlag(); + static_cast(loadInfo.get())->SetIncludeCookiesSecFlag(); } // Blocking gets are common enough out of XHR that we should mark @@ -2827,10 +2830,7 @@ nsXMLHttpRequest::Send(nsIVariant* aVariant, const Nullable& aBody) internalHttpChannel->SetResponseTimeoutEnabled(false); } - if (mIsAnon) { - AddLoadFlags(mChannel, nsIRequest::LOAD_ANONYMOUS); - } - else { + if (!mIsAnon) { AddLoadFlags(mChannel, nsIChannel::LOAD_EXPLICIT_CREDENTIALS); } @@ -3250,8 +3250,9 @@ 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; } diff --git a/dom/base/test/test_bug338583.html b/dom/base/test/test_bug338583.html index a8d054d22ca7..bbf2abe216a5 100644 --- a/dom/base/test/test_bug338583.html +++ b/dom/base/test/test_bug338583.html @@ -466,7 +466,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=338583 { // 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(); @@ -495,7 +494,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=338583 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() { @@ -523,7 +521,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=338583 { // 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() { @@ -551,7 +548,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=338583 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() { diff --git a/dom/fetch/FetchDriver.cpp b/dom/fetch/FetchDriver.cpp index 7bce60ecb351..a5e17ccb48da 100644 --- a/dom/fetch/FetchDriver.cpp +++ b/dom/fetch/FetchDriver.cpp @@ -43,7 +43,7 @@ namespace mozilla { namespace dom { NS_IMPL_ISUPPORTS(FetchDriver, - nsIStreamListener, nsIChannelEventSink, nsIInterfaceRequestor, + nsIStreamListener, nsIInterfaceRequestor, nsIThreadRetargetableStreamListener) FetchDriver::FetchDriver(InternalRequest* aRequest, nsIPrincipal* aPrincipal, @@ -98,16 +98,6 @@ FetchDriver::ContinueFetch() 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. @@ -168,17 +158,13 @@ FetchDriver::HttpFetch() 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; @@ -188,6 +174,20 @@ FetchDriver::HttpFetch() 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); @@ -200,8 +200,7 @@ FetchDriver::HttpFetch() rv = NS_NewChannel(getter_AddRefs(chan), uri, mDocument, - secFlags | - nsILoadInfo::SEC_ABOUT_BLANK_INHERITS, + secFlags, mRequest->ContentPolicyType(), mLoadGroup, nullptr, /* aCallbacks */ @@ -211,8 +210,7 @@ FetchDriver::HttpFetch() rv = NS_NewChannel(getter_AddRefs(chan), uri, mPrincipal, - secFlags | - nsILoadInfo::SEC_ABOUT_BLANK_INHERITS, + secFlags, mRequest->ContentPolicyType(), mLoadGroup, nullptr, /* aCallbacks */ @@ -223,28 +221,6 @@ FetchDriver::HttpFetch() mLoadGroup = nullptr; - // Insert ourselves into the notification callbacks chain so we can handle - // cross-origin redirects. -#ifdef DEBUG - { - nsCOMPtr 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`, @@ -698,84 +674,6 @@ FetchDriver::OnStopRequest(nsIRequest* aRequest, 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() { @@ -785,12 +683,6 @@ FetchDriver::CheckListenerChain() NS_IMETHODIMP FetchDriver::GetInterface(const nsIID& aIID, void **aResult) { - if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) { - *aResult = static_cast(this); - NS_ADDREF_THIS(); - return NS_OK; - } - if (aIID.Equals(NS_GET_IID(nsIStreamListener))) { *aResult = static_cast(this); NS_ADDREF_THIS(); diff --git a/dom/fetch/FetchDriver.h b/dom/fetch/FetchDriver.h index 97ffeafcf6f6..1652192c2506 100644 --- a/dom/fetch/FetchDriver.h +++ b/dom/fetch/FetchDriver.h @@ -55,7 +55,6 @@ private: }; class FetchDriver final : public nsIStreamListener, - public nsIChannelEventSink, public nsIInterfaceRequestor, public nsIThreadRetargetableStreamListener { @@ -63,7 +62,6 @@ public: NS_DECL_ISUPPORTS NS_DECL_NSIREQUESTOBSERVER NS_DECL_NSISTREAMLISTENER - NS_DECL_NSICHANNELEVENTSINK NS_DECL_NSIINTERFACEREQUESTOR NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index 9b02eca3fa35..2febd8fbdd67 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -1289,7 +1289,7 @@ nsresult HTMLMediaElement::LoadResource() 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)); diff --git a/dom/security/nsContentSecurityManager.cpp b/dom/security/nsContentSecurityManager.cpp index ecabb7f33bd9..a73d7d9a3035 100644 --- a/dom/security/nsContentSecurityManager.cpp +++ b/dom/security/nsContentSecurityManager.cpp @@ -26,12 +26,6 @@ ValidateSecurityFlags(nsILoadInfo* aLoadInfo) 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; } @@ -115,7 +109,8 @@ DoCORSChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo, RefPtr 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 @@ -422,6 +417,15 @@ nsContentSecurityManager::AsyncOnChannelRedirect(nsIChannel* aOldChannel, 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. @@ -432,6 +436,26 @@ nsContentSecurityManager::CheckChannel(nsIChannel* aChannel) nsCOMPtr loadInfo = aChannel->GetLoadInfo(); MOZ_ASSERT(loadInfo); + nsCOMPtr 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 @@ -442,11 +466,6 @@ nsContentSecurityManager::CheckChannel(nsIChannel* aChannel) return NS_OK; } - nsCOMPtr 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)) { diff --git a/netwerk/base/LoadInfo.cpp b/netwerk/base/LoadInfo.cpp index aaefcb67ac71..d0ed2eef48dc 100644 --- a/netwerk/base/LoadInfo.cpp +++ b/netwerk/base/LoadInfo.cpp @@ -269,14 +269,6 @@ LoadInfo::GetSecurityFlags(nsSecurityFlags* aResult) 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) { @@ -296,14 +288,36 @@ LoadInfo::GetIsInThirdPartyContext(bool* aIsInThirdPartyContext) 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) { diff --git a/netwerk/base/LoadInfo.h b/netwerk/base/LoadInfo.h index e83b5269138c..edece211cddd 100644 --- a/netwerk/base/LoadInfo.h +++ b/netwerk/base/LoadInfo.h @@ -101,7 +101,7 @@ private: // 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 diff --git a/netwerk/base/nsILoadInfo.idl b/netwerk/base/nsILoadInfo.idl index ec205bd50a1f..1ca7ef7e3028 100644 --- a/netwerk/base/nsILoadInfo.idl +++ b/netwerk/base/nsILoadInfo.idl @@ -29,7 +29,7 @@ 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 { /** @@ -89,11 +89,21 @@ interface nsILoadInfo : nsISupports 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 @@ -110,7 +120,7 @@ interface nsILoadInfo : nsISupports * * 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 @@ -122,17 +132,17 @@ interface nsILoadInfo : nsISupports * * 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 @@ -145,7 +155,7 @@ interface nsILoadInfo : nsISupports * 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. @@ -244,10 +254,12 @@ interface nsILoadInfo : nsISupports [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 diff --git a/netwerk/protocol/http/nsCORSListenerProxy.cpp b/netwerk/protocol/http/nsCORSListenerProxy.cpp index c23faa0d6da9..cdecf0093124 100644 --- a/netwerk/protocol/http/nsCORSListenerProxy.cpp +++ b/netwerk/protocol/http/nsCORSListenerProxy.cpp @@ -821,6 +821,8 @@ nsCORSListenerProxy::UpdateChannel(nsIChannel* aChannel, rv = aChannel->GetOriginalURI(getter_AddRefs(originalURI)); NS_ENSURE_SUCCESS(rv, rv); + nsCOMPtr loadInfo = aChannel->GetLoadInfo(); + // exempt data URIs from the same origin check. if (aAllowDataURI == DataURIHandling::Allow && originalURI == uri) { bool dataScheme = false; @@ -829,8 +831,6 @@ nsCORSListenerProxy::UpdateChannel(nsIChannel* aChannel, if (dataScheme) { return NS_OK; } - nsCOMPtr loadInfo; - aChannel->GetLoadInfo(getter_AddRefs(loadInfo)); if (loadInfo && loadInfo->GetAboutBlankInherits() && NS_IsAboutBlank(uri)) { return NS_OK; @@ -904,8 +904,11 @@ nsCORSListenerProxy::UpdateChannel(nsIChannel* aChannel, 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); @@ -1337,7 +1340,8 @@ nsCORSListenerProxy::StartCORSPreflight(nsIChannel* aRequestChannel, "how did we end up here?"); nsCOMPtr principal = originalLoadInfo->LoadingPrincipal(); - bool withCredentials = originalLoadInfo->GetRequireCorsWithCredentials(); + bool withCredentials = originalLoadInfo->GetCookiePolicy() == + nsILoadInfo::SEC_COOKIES_INCLUDE; nsPreflightCache::CacheEntry* entry = sPreflightCache ? diff --git a/uriloader/prefetch/nsPrefetchService.cpp b/uriloader/prefetch/nsPrefetchService.cpp index f068ce55cfd3..c1b56c8e6912 100644 --- a/uriloader/prefetch/nsPrefetchService.cpp +++ b/uriloader/prefetch/nsPrefetchService.cpp @@ -106,7 +106,7 @@ nsPrefetchNode::OpenChannel() } 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),