diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 9b1bafc3c8ac..1c32faf53fc3 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -318,43 +318,6 @@ PingsEnabled(int32_t* aMaxPerLink, bool* aRequireSameHost) return allow; } -static bool -CheckPingURI(nsIURI* aURI, nsIContent* aContent) -{ - if (!aURI) { - return false; - } - - // Check with nsIScriptSecurityManager - nsCOMPtr ssmgr = - do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID); - NS_ENSURE_TRUE(ssmgr, false); - - nsresult rv = ssmgr->CheckLoadURIWithPrincipal( - aContent->NodePrincipal(), aURI, nsIScriptSecurityManager::STANDARD); - if (NS_FAILED(rv)) { - return false; - } - - // Ignore non-HTTP(S) - bool match; - if ((NS_FAILED(aURI->SchemeIs("http", &match)) || !match) && - (NS_FAILED(aURI->SchemeIs("https", &match)) || !match)) { - return false; - } - - // Check with contentpolicy - int16_t shouldLoad = nsIContentPolicy::ACCEPT; - rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_PING, - aURI, - aContent->NodePrincipal(), - aContent, - EmptyCString(), // mime hint - nullptr, // extra - &shouldLoad); - return NS_SUCCEEDED(rv) && NS_CP_ACCEPTED(shouldLoad); -} - typedef void (*ForEachPingCallback)(void* closure, nsIContent* content, nsIURI* uri, nsIIOService* ios); @@ -405,7 +368,12 @@ ForEachPing(nsIContent* aContent, ForEachPingCallback aCallback, void* aClosure) ios->NewURI(NS_ConvertUTF16toUTF8(tokenizer.nextToken()), doc->GetDocumentCharacterSet().get(), baseURI, getter_AddRefs(uri)); - if (CheckPingURI(uri, aContent)) { + + // Explicitly not allow loading data: URIs + bool isDataScheme = + (NS_SUCCEEDED(uri->SchemeIs("data", &isDataScheme)) && isDataScheme); + + if (!isDataScheme) { aCallback(aClosure, aContent, uri, ios); } } @@ -425,55 +393,32 @@ OnPingTimeout(nsITimer* aTimer, void* aClosure) } } -// Check to see if two URIs have the same host or not -static bool -IsSameHost(nsIURI* aUri1, nsIURI* aUri2) -{ - nsAutoCString host1, host2; - aUri1->GetAsciiHost(host1); - aUri2->GetAsciiHost(host2); - return host1.Equals(host2); -} - class nsPingListener final : public nsIStreamListener - , public nsIInterfaceRequestor - , public nsIChannelEventSink { public: NS_DECL_ISUPPORTS NS_DECL_NSIREQUESTOBSERVER NS_DECL_NSISTREAMLISTENER - NS_DECL_NSIINTERFACEREQUESTOR - NS_DECL_NSICHANNELEVENTSINK - nsPingListener(bool aRequireSameHost, nsIContent* aContent, - nsILoadGroup* aLoadGroup) - : mRequireSameHost(aRequireSameHost) - , mContent(aContent) - , mLoadGroup(aLoadGroup) + nsPingListener() { } + void SetLoadGroup(nsILoadGroup* aLoadGroup) { + mLoadGroup = aLoadGroup; + } + nsresult StartTimeout(); - void SetInterceptController(nsINetworkInterceptController* aInterceptController) - { - mInterceptController = aInterceptController; - } - private: ~nsPingListener(); - bool mRequireSameHost; - nsCOMPtr mContent; nsCOMPtr mLoadGroup; nsCOMPtr mTimer; - nsCOMPtr mInterceptController; }; -NS_IMPL_ISUPPORTS(nsPingListener, nsIStreamListener, nsIRequestObserver, - nsIInterfaceRequestor, nsIChannelEventSink) +NS_IMPL_ISUPPORTS(nsPingListener, nsIStreamListener, nsIRequestObserver) nsPingListener::~nsPingListener() { @@ -530,57 +475,6 @@ nsPingListener::OnStopRequest(nsIRequest* aRequest, nsISupports* aContext, return NS_OK; } -NS_IMETHODIMP -nsPingListener::GetInterface(const nsIID& aIID, void** aResult) -{ - if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) { - nsCOMPtr copy(this); - *aResult = copy.forget().take(); - return NS_OK; - } - - if (aIID.Equals(NS_GET_IID(nsINetworkInterceptController)) && - mInterceptController) { - nsCOMPtr copy(mInterceptController); - *aResult = copy.forget().take(); - return NS_OK; - } - - return NS_ERROR_NO_INTERFACE; -} - -NS_IMETHODIMP -nsPingListener::AsyncOnChannelRedirect(nsIChannel* aOldChan, - nsIChannel* aNewChan, - uint32_t aFlags, - nsIAsyncVerifyRedirectCallback* aCallback) -{ - nsCOMPtr newURI; - aNewChan->GetURI(getter_AddRefs(newURI)); - - if (!CheckPingURI(newURI, mContent)) { - return NS_ERROR_ABORT; - } - - if (!mRequireSameHost) { - aCallback->OnRedirectVerifyCallback(NS_OK); - return NS_OK; - } - - // XXXbz should this be using something more like the nsContentUtils - // same-origin checker? - nsCOMPtr oldURI; - aOldChan->GetURI(getter_AddRefs(oldURI)); - NS_ENSURE_STATE(oldURI && newURI); - - if (!IsSameHost(oldURI, newURI)) { - return NS_ERROR_ABORT; - } - - aCallback->OnRedirectVerifyCallback(NS_OK); - return NS_OK; -} - struct MOZ_STACK_CLASS SendPingInfo { int32_t numPings; @@ -601,21 +495,15 @@ SendPing(void* aClosure, nsIContent* aContent, nsIURI* aURI, return; } - if (info->requireSameHost) { - // Make sure the referrer and the given uri share the same origin. We - // only require the same hostname. The scheme and port may differ. - if (!IsSameHost(aURI, info->referrer)) { - return; - } - } - nsIDocument* doc = aContent->OwnerDoc(); nsCOMPtr chan; NS_NewChannel(getter_AddRefs(chan), aURI, doc, - nsILoadInfo::SEC_NORMAL, + info->requireSameHost + ? nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED + : nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL, nsIContentPolicy::TYPE_PING, nullptr, // aLoadGroup nullptr, // aCallbacks @@ -714,25 +602,12 @@ SendPing(void* aClosure, nsIContent* aContent, nsIURI* aURI, if (!loadGroup) { return; } + nsCOMPtr callbacks = do_QueryInterface(info->docShell); + loadGroup->SetNotificationCallbacks(callbacks); chan->SetLoadGroup(loadGroup); - // Construct a listener that merely discards any response. If successful at - // opening the channel, then it is not necessary to hold a reference to the - // channel. The networking subsystem will take care of that for us. - nsPingListener* pingListener = - new nsPingListener(info->requireSameHost, aContent, loadGroup); - - nsCOMPtr interceptController = - do_QueryInterface(info->docShell); - pingListener->SetInterceptController(interceptController); - nsCOMPtr listener(pingListener); - - // Observe redirects as well: - nsCOMPtr callbacks = do_QueryInterface(listener); - NS_ASSERTION(callbacks, "oops"); - loadGroup->SetNotificationCallbacks(callbacks); - - chan->AsyncOpen(listener, nullptr); + nsRefPtr pingListener = new nsPingListener(); + chan->AsyncOpen2(pingListener); // Even if AsyncOpen failed, we still count this as a successful ping. It's // possible that AsyncOpen may have failed after triggering some background @@ -744,7 +619,11 @@ SendPing(void* aClosure, nsIContent* aContent, nsIURI* aURI, // If we failed to setup the timer, then we should just cancel the channel // because we won't be able to ensure that it goes away in a timely manner. chan->Cancel(NS_ERROR_ABORT); + return; } + // if the channel openend successfully, then make the pingListener hold + // a strong reference to the loadgroup which is released in ::OnStopRequest + pingListener->SetLoadGroup(loadGroup); } // Spec: http://whatwg.org/specs/web-apps/current-work/#ping diff --git a/dom/security/nsContentSecurityManager.cpp b/dom/security/nsContentSecurityManager.cpp index 376041d84ef7..6a74d53a56b5 100644 --- a/dom/security/nsContentSecurityManager.cpp +++ b/dom/security/nsContentSecurityManager.cpp @@ -145,12 +145,17 @@ DoContentSecurityChecks(nsIURI* aURI, nsILoadInfo* aLoadInfo) } case nsIContentPolicy::TYPE_REFRESH: - case nsIContentPolicy::TYPE_XBL: - case nsIContentPolicy::TYPE_PING: { + case nsIContentPolicy::TYPE_XBL: { MOZ_ASSERT(false, "contentPolicyType not supported yet"); break; } + case nsIContentPolicy::TYPE_PING: { + mimeTypeGuess = EmptyCString(); + requestingContext = aLoadInfo->LoadingNode(); + break; + } + case nsIContentPolicy::TYPE_XMLHTTPREQUEST: { // alias nsIContentPolicy::TYPE_DATAREQUEST: requestingContext = aLoadInfo->LoadingNode();