Bug 1596935 - Separate rel=dns-prefetch behaviour from html anchor dns prefetch r=dom-core,necko-reviewers,sefeng

Split the rel=dns-prefetch behaviour from the Dom's speculative DNS prefetch for all anchor elements.
This will allow us to independently enable rel=dns-prefetch for https document without prefetching DNS for anchors.

This patch does not change the behaviour for either source of DNS prefetch.

Differential Revision: https://phabricator.services.mozilla.com/D205630
This commit is contained in:
Andrew Creskey 2024-04-17 13:54:05 +00:00
Родитель 735c8471c7
Коммит 1312eb3dff
6 изменённых файлов: 126 добавлений и 69 удалений

Просмотреть файл

@ -68,10 +68,7 @@ nsresult HTMLAnchorElement::BindToTree(BindContext& aContext,
Link::BindToTree(aContext);
// Prefetch links
if (IsInComposedDoc()) {
TryDNSPrefetch(*this);
}
MaybeTryDNSPrefetch();
return rv;
}
@ -194,8 +191,8 @@ void HTMLAnchorElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
if (aNamespaceID == kNameSpaceID_None) {
if (aName == nsGkAtoms::href) {
Link::ResetLinkState(aNotify, !!aValue);
if (aValue && IsInComposedDoc()) {
TryDNSPrefetch(*this);
if (aValue) {
MaybeTryDNSPrefetch();
}
}
}
@ -210,4 +207,22 @@ void HTMLAnchorElement::AddSizeOfExcludingThis(nsWindowSizes& aSizes,
*aNodeSize += Link::SizeOfExcludingThis(aSizes.mState);
}
void HTMLAnchorElement::MaybeTryDNSPrefetch() {
if (IsInComposedDoc()) {
nsIURI* docURI = OwnerDoc()->GetDocumentURI();
if (!docURI) {
return;
}
bool docIsHttps = docURI->SchemeIs("https");
if ((docIsHttps &&
StaticPrefs::dom_prefetch_dns_for_anchor_https_document()) ||
(!docIsHttps &&
StaticPrefs::dom_prefetch_dns_for_anchor_http_document())) {
TryDNSPrefetch(
*this, HTMLDNSPrefetch::PrefetchSource::AnchorSpeculativePrefetch);
}
}
}
} // namespace mozilla::dom

Просмотреть файл

@ -189,6 +189,8 @@ class HTMLAnchorElement final : public nsGenericHTMLElement,
protected:
virtual ~HTMLAnchorElement();
void MaybeTryDNSPrefetch();
JSObject* WrapNode(JSContext*, JS::Handle<JSObject*> aGivenProto) override;
RefPtr<nsDOMTokenList> mRelList;
};

Просмотреть файл

@ -105,7 +105,7 @@ class DeferredDNSPrefetches final : public nsIWebProgressListener,
void Flush();
void SubmitQueue();
void SubmitQueueEntry(Element&, nsIDNSService::DNSFlags aFlags);
void SubmitQueueEntry(Element& aElement, nsIDNSService::DNSFlags aFlags);
uint16_t mHead;
uint16_t mTail;
@ -206,8 +206,8 @@ nsIDNSService::DNSFlags HTMLDNSPrefetch::PriorityToDNSServiceFlags(
return nsIDNSService::RESOLVE_DEFAULT_FLAGS;
}
nsresult HTMLDNSPrefetch::Prefetch(SupportsDNSPrefetch& aSupports,
Element& aElement, Priority aPriority) {
nsresult HTMLDNSPrefetch::DeferPrefetch(SupportsDNSPrefetch& aSupports,
Element& aElement, Priority aPriority) {
MOZ_ASSERT(&ToSupportsDNSPrefetch(aElement) == &aSupports);
if (!(sInitialized && sPrefetches && sDNSListener) || !EnsureDNSService()) {
return NS_ERROR_NOT_AVAILABLE;
@ -362,10 +362,84 @@ void HTMLDNSPrefetch::ElementDestroyed(Element& aElement,
}
}
void SupportsDNSPrefetch::TryDNSPrefetch(Element& aOwner) {
void HTMLDNSPrefetch::SendRequest(Element& aElement,
nsIDNSService::DNSFlags aFlags) {
auto& supports = ToSupportsDNSPrefetch(aElement);
nsIURI* uri = supports.GetURIForDNSPrefetch(aElement);
if (!uri) {
return;
}
nsAutoCString hostName;
uri->GetAsciiHost(hostName);
if (hostName.IsEmpty()) {
return;
}
bool isLocalResource = false;
nsresult rv = NS_URIChainHasFlags(
uri, nsIProtocolHandler::URI_IS_LOCAL_RESOURCE, &isLocalResource);
if (NS_FAILED(rv) || isLocalResource) {
return;
}
OriginAttributes oa;
StoragePrincipalHelper::GetOriginAttributesForNetworkState(
aElement.OwnerDoc(), oa);
bool isHttps = uri->SchemeIs("https");
if (IsNeckoChild()) {
// during shutdown gNeckoChild might be null
if (gNeckoChild) {
gNeckoChild->SendHTMLDNSPrefetch(NS_ConvertUTF8toUTF16(hostName), isHttps,
oa, aFlags);
}
} else {
nsCOMPtr<nsICancelable> tmpOutstanding;
rv = sDNSService->AsyncResolveNative(
hostName, nsIDNSService::RESOLVE_TYPE_DEFAULT,
aFlags | nsIDNSService::RESOLVE_SPECULATE, nullptr, sDNSListener,
nullptr, oa, getter_AddRefs(tmpOutstanding));
if (NS_FAILED(rv)) {
return;
}
// Fetch HTTPS RR if needed.
if (StaticPrefs::network_dns_upgrade_with_https_rr() ||
StaticPrefs::network_dns_use_https_rr_as_altsvc()) {
sDNSService->AsyncResolveNative(
hostName, nsIDNSService::RESOLVE_TYPE_HTTPSSVC,
aFlags | nsIDNSService::RESOLVE_SPECULATE, nullptr, sDNSListener,
nullptr, oa, getter_AddRefs(tmpOutstanding));
}
}
// Tell element that deferred prefetch was requested.
supports.DNSPrefetchRequestStarted();
}
void SupportsDNSPrefetch::TryDNSPrefetch(
Element& aOwner, HTMLDNSPrefetch::PrefetchSource aSource) {
MOZ_ASSERT(aOwner.IsInComposedDoc());
if (HTMLDNSPrefetch::IsAllowed(aOwner.OwnerDoc())) {
HTMLDNSPrefetch::Prefetch(*this, aOwner, HTMLDNSPrefetch::Priority::Low);
if (!(sInitialized && sDNSListener) || !EnsureDNSService()) {
return;
}
if (aSource == HTMLDNSPrefetch::PrefetchSource::AnchorSpeculativePrefetch) {
HTMLDNSPrefetch::DeferPrefetch(*this, aOwner,
HTMLDNSPrefetch::Priority::Low);
} else if (aSource == HTMLDNSPrefetch::PrefetchSource::LinkDnsPrefetch) {
HTMLDNSPrefetch::SendRequest(
aOwner, GetDNSFlagsFromElement(aOwner) |
HTMLDNSPrefetch::PriorityToDNSServiceFlags(
HTMLDNSPrefetch::Priority::High));
} else {
MOZ_ASSERT_UNREACHABLE("Unknown DNS prefetch type");
}
}
}
@ -470,59 +544,7 @@ void DeferredDNSPrefetches::SubmitQueueEntry(Element& aElement,
return;
}
nsIURI* uri = supports.GetURIForDNSPrefetch(aElement);
if (!uri) {
return;
}
nsAutoCString hostName;
uri->GetAsciiHost(hostName);
if (hostName.IsEmpty()) {
return;
}
bool isLocalResource = false;
nsresult rv = NS_URIChainHasFlags(
uri, nsIProtocolHandler::URI_IS_LOCAL_RESOURCE, &isLocalResource);
if (NS_FAILED(rv) || isLocalResource) {
return;
}
OriginAttributes oa;
StoragePrincipalHelper::GetOriginAttributesForNetworkState(
aElement.OwnerDoc(), oa);
bool isHttps = uri->SchemeIs("https");
if (IsNeckoChild()) {
// during shutdown gNeckoChild might be null
if (gNeckoChild) {
gNeckoChild->SendHTMLDNSPrefetch(NS_ConvertUTF8toUTF16(hostName), isHttps,
oa, mEntries[mTail].mFlags);
}
} else {
nsCOMPtr<nsICancelable> tmpOutstanding;
rv = sDNSService->AsyncResolveNative(
hostName, nsIDNSService::RESOLVE_TYPE_DEFAULT,
mEntries[mTail].mFlags | nsIDNSService::RESOLVE_SPECULATE, nullptr,
sDNSListener, nullptr, oa, getter_AddRefs(tmpOutstanding));
if (NS_FAILED(rv)) {
return;
}
// Fetch HTTPS RR if needed.
if (StaticPrefs::network_dns_upgrade_with_https_rr() ||
StaticPrefs::network_dns_use_https_rr_as_altsvc()) {
sDNSService->AsyncResolveNative(
hostName, nsIDNSService::RESOLVE_TYPE_HTTPSSVC,
mEntries[mTail].mFlags | nsIDNSService::RESOLVE_SPECULATE, nullptr,
sDNSListener, nullptr, oa, getter_AddRefs(tmpOutstanding));
}
}
// Tell element that deferred prefetch was requested.
supports.DNSPrefetchRequestStarted();
HTMLDNSPrefetch::SendRequest(aElement, aFlags);
}
void DeferredDNSPrefetches::Activate() {

Просмотреть файл

@ -55,7 +55,13 @@ class HTMLDNSPrefetch {
Medium,
High,
};
static nsresult Prefetch(SupportsDNSPrefetch&, Element&, Priority);
enum class PrefetchSource {
LinkDnsPrefetch,
AnchorSpeculativePrefetch,
};
static nsresult DeferPrefetch(SupportsDNSPrefetch& aSupports,
Element& aElement, Priority aPriority);
static void SendRequest(Element& aElement, nsIDNSService::DNSFlags aFlags);
static nsresult Prefetch(
const nsAString& host, bool isHttps,
const OriginAttributes& aPartitionedPrincipalOriginAttributes,
@ -68,9 +74,9 @@ class HTMLDNSPrefetch {
nsresult aReason);
static void ElementDestroyed(Element&, SupportsDNSPrefetch&);
private:
static nsIDNSService::DNSFlags PriorityToDNSServiceFlags(Priority);
private:
static nsresult Prefetch(
const nsAString& host, bool isHttps,
const OriginAttributes& aPartitionedPrincipalOriginAttributes,
@ -114,8 +120,8 @@ class SupportsDNSPrefetch {
mDNSPrefetchDeferred(false),
mDestroyedCalled(false) {}
void CancelDNSPrefetch(Element&);
void TryDNSPrefetch(Element&);
void CancelDNSPrefetch(Element& aOwner);
void TryDNSPrefetch(Element& aOwner, HTMLDNSPrefetch::PrefetchSource aSource);
// This MUST be called on the destructor of the Element subclass.
// Our own destructor ensures that.

Просмотреть файл

@ -555,7 +555,7 @@ void HTMLLinkElement::
}
if (linkTypes & eDNS_PREFETCH) {
TryDNSPrefetch(*this);
TryDNSPrefetch(*this, HTMLDNSPrefetch::PrefetchSource::LinkDnsPrefetch);
}
}

Просмотреть файл

@ -3295,6 +3295,18 @@
value: false
mirror: always
# Should we speculatively prefetch dns for anchor elements on http documents
- name: dom.prefetch_dns_for_anchor_http_document
type: bool
value: true
mirror: always
# Should we speculatively prefetch dns for anchor elements on https documents
- name: dom.prefetch_dns_for_anchor_https_document
type: bool
value: false
mirror: always
# This currently only affects XHTML. For XUL the cache is always allowed.
- name: dom.prototype_document_cache.enabled
type: bool