/* -*- 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/. */
class NoOpDNSListener final : public nsIDNSListener { // This class exists to give a safe callback no-op DNSListener public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIDNSLISTENER
// This is just a (size) optimization and could be avoided by storing the // SupportsDNSPrefetch pointer of the element in the prefetch queue, but given // we need this for GetURIForDNSPrefetch... static SupportsDNSPrefetch& ToSupportsDNSPrefetch(Element& aElement) { if (auto* link = HTMLLinkElement::FromNode(aElement)) { return *link;
} auto* anchor = HTMLAnchorElement::FromNode(aElement);
MOZ_DIAGNOSTIC_ASSERT(anchor); return *anchor;
}
class DeferredDNSPrefetches final : public nsIWebProgressListener, public nsSupportsWeakReference, public nsIObserver { public:
NS_DECL_ISUPPORTS
NS_DECL_NSIWEBPROGRESSLISTENER
NS_DECL_NSIOBSERVER
bool HTMLDNSPrefetch::IsAllowed(Document* aDocument) { // Do not use prefetch if the document's node principal is the system // principal.
nsCOMPtr<nsIPrincipal> principal = aDocument->NodePrincipal(); if (principal->IsSystemPrincipal()) { returnfalse;
}
// There is no need to do prefetch on non UI scenarios such as XMLHttpRequest. return aDocument->IsDNSPrefetchAllowed() && aDocument->GetWindow();
}
nsresult HTMLDNSPrefetch::CancelPrefetch( const nsAString& hostname, bool isHttps, const OriginAttributes& aPartitionedPrincipalOriginAttributes,
nsIDNSService::DNSFlags flags, nsresult aReason) { // Forward this request to Necko Parent if we're a child process if (IsNeckoChild()) { // We need to check IsEmpty() because net_IsValidDNSHost() // considers empty strings to be valid hostnames if (!hostname.IsEmpty() &&
net_IsValidDNSHost(NS_ConvertUTF16toUTF8(hostname))) { // during shutdown gNeckoChild might be null if (gNeckoChild && gNeckoChild->CanSend()) {
gNeckoChild->SendCancelHTMLDNSPrefetch(
hostname, isHttps, aPartitionedPrincipalOriginAttributes, flags,
aReason);
}
} return NS_OK;
}
void HTMLDNSPrefetch::ElementDestroyed(Element& aElement,
SupportsDNSPrefetch& aSupports) {
MOZ_ASSERT(&ToSupportsDNSPrefetch(aElement) == &aSupports);
MOZ_ASSERT(aSupports.IsInDNSPrefetch()); if (sPrefetches) { // Clean up all the possible links at once.
sPrefetches->RemoveUnboundLinks();
}
}
void SupportsDNSPrefetch::CancelDNSPrefetch(Element& aOwner) { // If prefetch was deferred, clear flag and move on if (mDNSPrefetchDeferred) {
mDNSPrefetchDeferred = false; // Else if prefetch was requested, clear flag and send cancellation
} elseif (mDNSPrefetchRequested) {
mDNSPrefetchRequested = false; // Possible that hostname could have changed since binding, but since this // covers common cases, most DNS prefetch requests will be canceled
HTMLDNSPrefetch::CancelPrefetch(
*this, aOwner, HTMLDNSPrefetch::Priority::Low, NS_ERROR_ABORT);
}
}
void DeferredDNSPrefetches::Flush() { for (; mHead != mTail; mTail = (mTail + 1) & sMaxDeferredMask) {
Element* element = mEntries[mTail].mElement; if (element) {
ToSupportsDNSPrefetch(*element).ClearIsInDNSPrefetch();
}
mEntries[mTail].mElement = nullptr;
}
}
nsresult DeferredDNSPrefetches::Add(nsIDNSService::DNSFlags flags,
SupportsDNSPrefetch& aSupports,
Element& aElement) { // The FIFO has no lock, so it can only be accessed on main thread
NS_ASSERTION(NS_IsMainThread(), "DeferredDNSPrefetches::Add must be on main thread");
void DeferredDNSPrefetches::SubmitQueue() {
NS_ASSERTION(NS_IsMainThread(), "DeferredDNSPrefetches::SubmitQueue must be on main thread"); if (!EnsureDNSService()) { return;
}
for (; mHead != mTail; mTail = (mTail + 1) & sMaxDeferredMask) {
Element* element = mEntries[mTail].mElement; if (!element) { continue;
}
SubmitQueueEntry(*element, mEntries[mTail].mFlags);
mEntries[mTail].mElement = nullptr;
}
if (mTimerArmed) {
mTimerArmed = false;
mTimer->Cancel();
}
}
// Only prefetch here if request was deferred and deferral not cancelled if (!supports.IsDNSPrefetchRequestDeferred()) { return;
}
HTMLDNSPrefetch::SendRequest(aElement, aFlags);
}
void DeferredDNSPrefetches::Activate() { // Register as an observer for the document loader
nsCOMPtr<nsIWebProgress> progress = components::DocLoader::Service(); if (progress)
progress->AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_DOCUMENT);
// Register as an observer for xpcom shutdown events so we can drop any // element refs
nsCOMPtr<nsIObserverService> observerService =
mozilla::services::GetObserverService(); if (observerService)
observerService->AddObserver(this, "xpcom-shutdown", true);
}
NS_ASSERTION(NS_IsMainThread(), "DeferredDNSPrefetches::Tick must be on main thread");
NS_ASSERTION(self->mTimerArmed, "Timer is not armed");
self->mTimerArmed = false;
// If the queue is not submitted here because there are outstanding pages // being loaded, there is no need to rearm the timer as the queue will be // submtited when those loads complete. if (!self->mActiveLoaderCount) {
self->SubmitQueue();
}
}
//////////// nsIWebProgressListener methods
NS_IMETHODIMP
DeferredDNSPrefetches::OnStateChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
uint32_t progressStateFlags,
nsresult aStatus) { // The FIFO has no lock, so it can only be accessed on main thread
NS_ASSERTION(NS_IsMainThread(), "DeferredDNSPrefetches::OnStateChange must be on main thread");
if (progressStateFlags & STATE_IS_DOCUMENT) { if (progressStateFlags & STATE_STOP) { // Initialization may have missed a STATE_START notification, so do // not go negative if (mActiveLoaderCount) mActiveLoaderCount--;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.