mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 580313 - New resource hints for link. r=smaug
This commit is contained in:
parent
d99562513c
commit
155721f0d8
@ -11,6 +11,9 @@
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "nsIURL.h"
|
||||
#include "nsISizeOf.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIPrefetchService.h"
|
||||
#include "nsCPrefetchService.h"
|
||||
|
||||
#include "nsEscape.h"
|
||||
#include "nsGkAtoms.h"
|
||||
@ -72,6 +75,70 @@ Link::CancelDNSPrefetch(nsWrapperCache::FlagsType aDeferredFlag,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Link::TryDNSPrefetchPreconnectOrPrefetch()
|
||||
{
|
||||
MOZ_ASSERT(mElement->IsInComposedDoc());
|
||||
if (!ElementHasHref()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoString rel;
|
||||
if (!mElement->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, rel)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!nsContentUtils::PrefetchEnabled(mElement->OwnerDoc()->GetDocShell())) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t linkTypes = nsStyleLinkElement::ParseLinkTypes(rel,
|
||||
mElement->NodePrincipal());
|
||||
|
||||
if ((linkTypes & nsStyleLinkElement::ePREFETCH) ||
|
||||
(linkTypes & nsStyleLinkElement::eNEXT)){
|
||||
nsCOMPtr<nsIPrefetchService> prefetchService(do_GetService(NS_PREFETCHSERVICE_CONTRACTID));
|
||||
if (prefetchService) {
|
||||
nsCOMPtr<nsIURI> uri(GetURI());
|
||||
if (uri) {
|
||||
nsCOMPtr<nsIDOMNode> domNode = GetAsDOMNode(mElement);
|
||||
prefetchService->PrefetchURI(uri,
|
||||
mElement->OwnerDoc()->GetDocumentURI(),
|
||||
domNode, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (linkTypes & nsStyleLinkElement::ePRECONNECT) {
|
||||
nsCOMPtr<nsIURI> uri(GetURI());
|
||||
if (uri && mElement->OwnerDoc()) {
|
||||
mElement->OwnerDoc()->MaybePreconnect(uri,
|
||||
mElement->AttrValueToCORSMode(mElement->GetParsedAttr(nsGkAtoms::crossorigin)));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (linkTypes & nsStyleLinkElement::eDNS_PREFETCH) {
|
||||
if (nsHTMLDNSPrefetch::IsAllowed(mElement->OwnerDoc())) {
|
||||
nsHTMLDNSPrefetch::PrefetchLow(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Link::CancelPrefetch()
|
||||
{
|
||||
nsCOMPtr<nsIPrefetchService> prefetchService(do_GetService(NS_PREFETCHSERVICE_CONTRACTID));
|
||||
if (prefetchService) {
|
||||
nsCOMPtr<nsIURI> uri(GetURI());
|
||||
if (uri) {
|
||||
nsCOMPtr<nsIDOMNode> domNode = GetAsDOMNode(mElement);
|
||||
prefetchService->CancelPrefetchURI(uri, domNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Link::SetLinkState(nsLinkState aState)
|
||||
{
|
||||
|
@ -111,11 +111,15 @@ public:
|
||||
|
||||
bool ElementHasHref() const;
|
||||
|
||||
// This is called by HTMLAnchorElement.
|
||||
void TryDNSPrefetch();
|
||||
|
||||
void CancelDNSPrefetch(nsWrapperCache::FlagsType aDeferredFlag,
|
||||
nsWrapperCache::FlagsType aRequestedFlag);
|
||||
|
||||
// This is called by HTMLLinkElement.
|
||||
void TryDNSPrefetchPreconnectOrPrefetch();
|
||||
void CancelPrefetch();
|
||||
|
||||
protected:
|
||||
virtual ~Link();
|
||||
|
||||
|
@ -692,7 +692,11 @@ nsContentSink::ProcessLink(const nsSubstring& aAnchor, const nsSubstring& aHref,
|
||||
if (!LinkContextIsOurDocument(aAnchor)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
if (!nsContentUtils::PrefetchEnabled(mDocShell)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool hasPrefetch = linkTypes & nsStyleLinkElement::ePREFETCH;
|
||||
// prefetch href if relation is "next" or "prefetch"
|
||||
if (hasPrefetch || (linkTypes & nsStyleLinkElement::eNEXT)) {
|
||||
@ -827,35 +831,6 @@ nsContentSink::PrefetchHref(const nsAString &aHref,
|
||||
nsINode *aSource,
|
||||
bool aExplicit)
|
||||
{
|
||||
//
|
||||
// SECURITY CHECK: disable prefetching from mailnews!
|
||||
//
|
||||
// walk up the docshell tree to see if any containing
|
||||
// docshell are of type MAIL.
|
||||
//
|
||||
if (!mDocShell)
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsIDocShell> docshell = mDocShell;
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeItem> parentItem;
|
||||
do {
|
||||
uint32_t appType = 0;
|
||||
nsresult rv = docshell->GetAppType(&appType);
|
||||
if (NS_FAILED(rv) || appType == nsIDocShell::APP_TYPE_MAIL)
|
||||
return; // do not prefetch from mailnews
|
||||
docshell->GetParent(getter_AddRefs(parentItem));
|
||||
if (parentItem) {
|
||||
docshell = do_QueryInterface(parentItem);
|
||||
if (!docshell) {
|
||||
NS_ERROR("cannot get a docshell from a treeItem!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
} while (parentItem);
|
||||
|
||||
// OK, we passed the security check...
|
||||
|
||||
nsCOMPtr<nsIPrefetchService> prefetchService(do_GetService(NS_PREFETCHSERVICE_CONTRACTID));
|
||||
if (prefetchService) {
|
||||
// construct URI using document charset
|
||||
|
@ -7233,6 +7233,43 @@ nsContentUtils::GenerateUUIDInPlace(nsID& aUUID)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
nsContentUtils::PrefetchEnabled(nsIDocShell* aDocShell)
|
||||
{
|
||||
//
|
||||
// SECURITY CHECK: disable prefetching from mailnews!
|
||||
//
|
||||
// walk up the docshell tree to see if any containing
|
||||
// docshell are of type MAIL.
|
||||
//
|
||||
|
||||
if (!aDocShell) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocShell> docshell = aDocShell;
|
||||
nsCOMPtr<nsIDocShellTreeItem> parentItem;
|
||||
|
||||
do {
|
||||
uint32_t appType = 0;
|
||||
nsresult rv = docshell->GetAppType(&appType);
|
||||
if (NS_FAILED(rv) || appType == nsIDocShell::APP_TYPE_MAIL) {
|
||||
return false; // do not prefetch, preconnect from mailnews
|
||||
}
|
||||
|
||||
docshell->GetParent(getter_AddRefs(parentItem));
|
||||
if (parentItem) {
|
||||
docshell = do_QueryInterface(parentItem);
|
||||
if (!docshell) {
|
||||
NS_ERROR("cannot get a docshell from a treeItem!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} while (parentItem);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
nsContentUtils::GetInnerWindowID(nsIRequest* aRequest)
|
||||
{
|
||||
|
@ -917,6 +917,7 @@ public:
|
||||
*/
|
||||
static nsresult GenerateUUIDInPlace(nsID& aUUID);
|
||||
|
||||
static bool PrefetchEnabled(nsIDocShell* aDocShell);
|
||||
|
||||
/**
|
||||
* Fill (with the parameters given) the localized string named |aKey| in
|
||||
|
134
dom/base/test/unit/test_cancelPrefetch.js
Normal file
134
dom/base/test/unit/test_cancelPrefetch.js
Normal file
@ -0,0 +1,134 @@
|
||||
//Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
var prefetch = Cc["@mozilla.org/prefetch-service;1"].
|
||||
getService(Ci.nsIPrefetchService);
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(Ci.nsIIOService);
|
||||
var prefs = Cc["@mozilla.org/preferences-service;1"].
|
||||
getService(Ci.nsIPrefBranch);
|
||||
|
||||
var parser = Cc["@mozilla.org/xmlextras/domparser;1"].
|
||||
createInstance(Ci.nsIDOMParser);
|
||||
|
||||
var doc;
|
||||
|
||||
var docbody = '<html xmlns="http://www.w3.org/1999/xhtml"><head></head><body>' +
|
||||
'<link id="node1"/><link id="node2"/>' +
|
||||
'</body></html>';
|
||||
|
||||
var node1;
|
||||
var node2;
|
||||
|
||||
function run_test() {
|
||||
prefs.setBoolPref("network.prefetch-next", true);
|
||||
|
||||
parser.init();
|
||||
doc = parser.parseFromString(docbody, "text/html");
|
||||
|
||||
node1 = doc.getElementById("node1");
|
||||
node2 = doc.getElementById("node2");
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_test(function test_cancel1() {
|
||||
|
||||
var uri = ios.newURI("http://localhost/1", null, null);
|
||||
prefetch.prefetchURI(uri, uri, node1, true);
|
||||
|
||||
do_check_true(prefetch.hasMoreElements(), 'There is a request in the queue');
|
||||
|
||||
// Trying to prefetch again the same uri with the same node will fail.
|
||||
var didFail = 0;
|
||||
|
||||
try {
|
||||
prefetch.prefetchURI(uri, uri, node1, true);
|
||||
} catch(e) {
|
||||
didFail = 1;
|
||||
}
|
||||
|
||||
do_check_true(didFail == 1, 'Prefetching the same request with the same ' +
|
||||
'node fails.');
|
||||
|
||||
do_check_true(prefetch.hasMoreElements(), 'There is still request in ' +
|
||||
'the queue');
|
||||
|
||||
prefetch.cancelPrefetchURI(uri, node1);
|
||||
|
||||
do_check_false(prefetch.hasMoreElements(), 'There is no request in the ' +
|
||||
'queue');
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_cancel2() {
|
||||
// Prefetch a uri with 2 different nodes. There should be 2 request
|
||||
// in the queue and canceling one will not cancel the other.
|
||||
|
||||
var uri = ios.newURI("http://localhost/1", null, null);
|
||||
prefetch.prefetchURI(uri, uri, node1, true);
|
||||
prefetch.prefetchURI(uri, uri, node2, true);
|
||||
|
||||
do_check_true(prefetch.hasMoreElements(), 'There are requests in the queue');
|
||||
|
||||
prefetch.cancelPrefetchURI(uri, node1);
|
||||
|
||||
do_check_true(prefetch.hasMoreElements(), 'There is still one more request ' +
|
||||
'in the queue');
|
||||
|
||||
prefetch.cancelPrefetchURI(uri, node2);
|
||||
|
||||
do_check_false(prefetch.hasMoreElements(), 'There is no request in the queue');
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_cancel3() {
|
||||
// Request a prefetch of a uri. Trying to cancel a prefetch for the same uri
|
||||
// with a different node will fail.
|
||||
var uri = ios.newURI("http://localhost/1", null, null);
|
||||
prefetch.prefetchURI(uri, uri, node1, true);
|
||||
|
||||
do_check_true(prefetch.hasMoreElements(), 'There is a request in the queue');
|
||||
|
||||
var didFail = 0;
|
||||
|
||||
try {
|
||||
prefetch.cancelPrefetchURI(uri, node2);
|
||||
} catch(e) {
|
||||
didFail = 1;
|
||||
}
|
||||
do_check_true(didFail == 1, 'Canceling the request failed');
|
||||
|
||||
do_check_true(prefetch.hasMoreElements(), 'There is still a request ' +
|
||||
'in the queue');
|
||||
|
||||
prefetch.cancelPrefetchURI(uri, node1);
|
||||
do_check_false(prefetch.hasMoreElements(), 'There is no request in the queue');
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_cancel4() {
|
||||
// Request a prefetch of a uri. Trying to cancel a prefetch for a different uri
|
||||
// with the same node will fail.
|
||||
var uri1 = ios.newURI("http://localhost/1", null, null);
|
||||
var uri2 = ios.newURI("http://localhost/2", null, null);
|
||||
prefetch.prefetchURI(uri1, uri1, node1, true);
|
||||
|
||||
do_check_true(prefetch.hasMoreElements(), 'There is a request in the queue');
|
||||
|
||||
var didFail = 0;
|
||||
|
||||
try {
|
||||
prefetch.cancelPrefetchURI(uri2, node1);
|
||||
} catch(e) {
|
||||
didFail = 1;
|
||||
}
|
||||
do_check_true(didFail == 1, 'Canceling the request failed');
|
||||
|
||||
do_check_true(prefetch.hasMoreElements(), 'There is still a request ' +
|
||||
'in the queue');
|
||||
|
||||
prefetch.cancelPrefetchURI(uri1, node1);
|
||||
do_check_false(prefetch.hasMoreElements(), 'There is no request in the queue');
|
||||
run_next_test();
|
||||
});
|
@ -50,3 +50,4 @@ head = head_xml.js
|
||||
[test_xml_serializer.js]
|
||||
head = head_xml.js
|
||||
[test_xmlserializer.js]
|
||||
[test_cancelPrefetch.js]
|
||||
|
@ -180,10 +180,7 @@ HTMLLinkElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
||||
}
|
||||
|
||||
if (IsInComposedDoc()) {
|
||||
UpdatePreconnect();
|
||||
if (HasDNSPrefetchRel()) {
|
||||
TryDNSPrefetch();
|
||||
}
|
||||
TryDNSPrefetchPreconnectOrPrefetch();
|
||||
}
|
||||
|
||||
void (HTMLLinkElement::*update)() = &HTMLLinkElement::UpdateStyleSheetInternal;
|
||||
@ -217,6 +214,7 @@ HTMLLinkElement::UnbindFromTree(bool aDeep, bool aNullParent)
|
||||
// mCachedURI based on data that is invalid - due to a call to GetHostname.
|
||||
CancelDNSPrefetch(HTML_LINK_DNS_PREFETCH_DEFERRED,
|
||||
HTML_LINK_DNS_PREFETCH_REQUESTED);
|
||||
CancelPrefetch();
|
||||
|
||||
// If this link is ever reinserted into a document, it might
|
||||
// be under a different xml:base, so forget the cached state now.
|
||||
@ -344,41 +342,6 @@ HTMLLinkElement::UpdateImport()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
HTMLLinkElement::UpdatePreconnect()
|
||||
{
|
||||
// rel type should be preconnect
|
||||
nsAutoString rel;
|
||||
if (!GetAttr(kNameSpaceID_None, nsGkAtoms::rel, rel)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t linkTypes = nsStyleLinkElement::ParseLinkTypes(rel, NodePrincipal());
|
||||
if (!(linkTypes & ePRECONNECT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsIDocument *owner = OwnerDoc();
|
||||
if (owner) {
|
||||
nsCOMPtr<nsIURI> uri = GetHrefURI();
|
||||
if (uri) {
|
||||
owner->MaybePreconnect(uri, GetCORSMode());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
HTMLLinkElement::HasDNSPrefetchRel()
|
||||
{
|
||||
nsAutoString rel;
|
||||
if (GetAttr(kNameSpaceID_None, nsGkAtoms::rel, rel)) {
|
||||
return !!(ParseLinkTypes(rel, NodePrincipal()) &
|
||||
nsStyleLinkElement::eDNS_PREFETCH);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLLinkElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsAttrValueOrString* aValue, bool aNotify)
|
||||
@ -387,6 +350,7 @@ HTMLLinkElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
(aName == nsGkAtoms::href || aName == nsGkAtoms::rel)) {
|
||||
CancelDNSPrefetch(HTML_LINK_DNS_PREFETCH_DEFERRED,
|
||||
HTML_LINK_DNS_PREFETCH_REQUESTED);
|
||||
CancelPrefetch();
|
||||
}
|
||||
|
||||
return nsGenericHTMLElement::BeforeSetAttr(aNameSpaceID, aName,
|
||||
@ -427,21 +391,16 @@ HTMLLinkElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
dropSheet = !(linkTypes & nsStyleLinkElement::eSTYLESHEET);
|
||||
} else if (linkTypes & eHTMLIMPORT) {
|
||||
UpdateImport();
|
||||
} else if ((linkTypes & ePRECONNECT) && IsInComposedDoc()) {
|
||||
UpdatePreconnect();
|
||||
}
|
||||
}
|
||||
|
||||
if (aName == nsGkAtoms::href) {
|
||||
UpdateImport();
|
||||
if (IsInComposedDoc()) {
|
||||
UpdatePreconnect();
|
||||
}
|
||||
}
|
||||
|
||||
if ((aName == nsGkAtoms::rel || aName == nsGkAtoms::href) &&
|
||||
HasDNSPrefetchRel() && IsInComposedDoc()) {
|
||||
TryDNSPrefetch();
|
||||
IsInComposedDoc()) {
|
||||
TryDNSPrefetchPreconnectOrPrefetch();
|
||||
}
|
||||
|
||||
UpdateStyleSheetInternal(nullptr, nullptr,
|
||||
|
@ -44,7 +44,6 @@ public:
|
||||
void LinkRemoved();
|
||||
|
||||
void UpdateImport();
|
||||
void UpdatePreconnect();
|
||||
|
||||
// nsIDOMEventTarget
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) override;
|
||||
@ -174,8 +173,6 @@ protected:
|
||||
virtual void GetItemValueText(DOMString& text) override;
|
||||
virtual void SetItemValueText(const nsAString& text) override;
|
||||
|
||||
bool HasDNSPrefetchRel();
|
||||
|
||||
RefPtr<nsDOMTokenList > mRelList;
|
||||
private:
|
||||
RefPtr<ImportLoader> mImportLoader;
|
||||
|
@ -41,3 +41,4 @@ support-files =
|
||||
[test_shadowroot_youngershadowroot.html]
|
||||
[test_style_fallback_content.html]
|
||||
[test_unresolved_pseudo_class.html]
|
||||
[test_link_prefetch.html]
|
||||
|
110
dom/tests/mochitest/webcomponents/test_link_prefetch.html
Normal file
110
dom/tests/mochitest/webcomponents/test_link_prefetch.html
Normal file
@ -0,0 +1,110 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=580313
|
||||
-->
|
||||
<head>
|
||||
<title>Test Prefetch (bug 580313)</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=580313">Mozilla Bug 580313</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var prefetch = SpecialPowers.Cc["@mozilla.org/prefetch-service;1"].
|
||||
getService(SpecialPowers.Ci.nsIPrefetchService);
|
||||
var ios = SpecialPowers.Cc["@mozilla.org/network/io-service;1"].
|
||||
getService(SpecialPowers.Ci.nsIIOService);
|
||||
|
||||
is(prefetch.hasMoreElements(), false, "No prefetches at the test start.");
|
||||
|
||||
var linkElem = document.createElement('link');
|
||||
linkElem.rel = "prefetch";
|
||||
|
||||
// Href is empty.
|
||||
document.head.appendChild(linkElem);
|
||||
is(prefetch.hasMoreElements(), false,
|
||||
"If href is not a valid uri, a prefetch has not been started.");
|
||||
|
||||
// Change uri of an existing link. Now it is a valid uri and
|
||||
// a prefetch should start.
|
||||
linkElem.href = "https://example.com/1";
|
||||
is(prefetch.hasMoreElements(), true,
|
||||
"Setting the href to a valid uri has started a new prefetch.");
|
||||
|
||||
// Removing a link, removes its prefetch.
|
||||
document.head.removeChild(linkElem);
|
||||
is(prefetch.hasMoreElements(), false,
|
||||
"Removing the link has canceled the prefetch.");
|
||||
|
||||
// Add link again.
|
||||
document.head.appendChild(linkElem);
|
||||
is(prefetch.hasMoreElements(), true,
|
||||
"Adding link again, has started the prefetch again.");
|
||||
|
||||
// Changing the href should cancel the current prefetch.
|
||||
linkElem.href = "https://example.com/2";
|
||||
is(prefetch.hasMoreElements(), true,
|
||||
"Changing href, a new prefetch has been started.");
|
||||
// To check if "https://example.com/1" prefetch has been canceled, we try to
|
||||
// cancel it using PrefetService. Since the prefetch for
|
||||
// "https://example.com/1" does not exist, the cancel will throw.
|
||||
var cancelError = 0;
|
||||
try {
|
||||
var uri = ios.newURI("https://example.com/1", null, null);
|
||||
prefetch.cancelPrefetchURI(uri, linkElem);
|
||||
} catch(e) {
|
||||
cancelError = 1;
|
||||
}
|
||||
is(cancelError, 1, "This prefetch has aleady been canceled");
|
||||
|
||||
// Now cancel the right uri.
|
||||
cancelError = 0;
|
||||
try {
|
||||
var uri = ios.newURI("https://example.com/2", null, null);
|
||||
prefetch.cancelPrefetchURI(uri, linkElem);
|
||||
} catch(e) {
|
||||
cancelError = 1;
|
||||
}
|
||||
is(cancelError, 0, "This prefetch has been canceled successfully");
|
||||
|
||||
is(prefetch.hasMoreElements(), false, "The prefetch has already been canceled.");
|
||||
|
||||
// Removing the link will do nothing regarding prefetch service.
|
||||
document.head.removeChild(linkElem);
|
||||
|
||||
// Adding two links to the same uri and removing one will not remove the other.
|
||||
document.head.appendChild(linkElem);
|
||||
is(prefetch.hasMoreElements(), true,
|
||||
"Added one prefetch for 'https://example.com/2'.");
|
||||
|
||||
var linkElem2 = document.createElement('link');
|
||||
linkElem2.rel = "prefetch";
|
||||
linkElem2.href = "https://example.com/2";
|
||||
document.head.appendChild(linkElem2);
|
||||
is(prefetch.hasMoreElements(), true,
|
||||
"Added second prefetch for 'https://example.com/2'.");
|
||||
|
||||
// Remove first link element. This should not remove the prefetch.
|
||||
document.head.removeChild(linkElem);
|
||||
is(prefetch.hasMoreElements(), true,
|
||||
"The prefetch for 'https://example.com/2' is still present.");
|
||||
|
||||
// Remove the second link element. This should remove the prefetch.
|
||||
document.head.removeChild(linkElem2);
|
||||
is(prefetch.hasMoreElements(), false,
|
||||
"There is no prefetch.");
|
||||
|
||||
SimpleTest.finish();
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -595,24 +595,6 @@ nsXMLContentSink::CloseElement(nsIContent* aContent)
|
||||
mScriptLoader->AddExecuteBlocker();
|
||||
}
|
||||
}
|
||||
// Look for <link rel="dns-prefetch" href="hostname">
|
||||
// and look for <link rel="next" href="hostname"> like in HTML sink
|
||||
if (nodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML)) {
|
||||
nsAutoString relVal;
|
||||
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, relVal);
|
||||
if (!relVal.IsEmpty()) {
|
||||
uint32_t linkTypes =
|
||||
nsStyleLinkElement::ParseLinkTypes(relVal, aContent->NodePrincipal());
|
||||
bool hasPrefetch = linkTypes & nsStyleLinkElement::ePREFETCH;
|
||||
if (hasPrefetch || (linkTypes & nsStyleLinkElement::eNEXT)) {
|
||||
nsAutoString hrefVal;
|
||||
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
|
||||
if (!hrefVal.IsEmpty()) {
|
||||
PrefetchHref(hrefVal, aContent, hasPrefetch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
@ -5,10 +5,10 @@ function handleRequest(request, response)
|
||||
{
|
||||
response.setHeader("Cache-Control", "no-cache", false);
|
||||
response.setHeader("Link", "<" +
|
||||
request.getHeader('X-Link') +
|
||||
request.queryString +
|
||||
">; rel=preconnect" + ", " +
|
||||
"<" +
|
||||
request.getHeader('X-Link') +
|
||||
request.queryString +
|
||||
">; rel=preconnect; crossOrigin=anonymous");
|
||||
response.write("check that header");
|
||||
}
|
||||
|
@ -70,11 +70,10 @@ function doTest()
|
||||
|
||||
// test the http link response header - the test contains both a
|
||||
// normal and anonymous preconnect link header
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", 'rel_preconnect.sjs', false);
|
||||
xhr.setRequestHeader("X-Link", "//localhost:" + srv.listener.port);
|
||||
xhr.send();
|
||||
is(xhr.status, 200, 'xhr cool');
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.src = 'rel_preconnect.sjs?//localhost:' + srv.listener.port;
|
||||
|
||||
document.body.appendChild(iframe);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
@ -81,24 +81,6 @@ nsHtml5DocumentBuilder::UpdateStyleSheet(nsIContent* aElement)
|
||||
mScriptLoader->AddExecuteBlocker();
|
||||
}
|
||||
|
||||
if (aElement->IsHTMLElement(nsGkAtoms::link)) {
|
||||
// look for <link rel="next" href="url">
|
||||
nsAutoString relVal;
|
||||
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, relVal);
|
||||
if (!relVal.IsEmpty()) {
|
||||
uint32_t linkTypes =
|
||||
nsStyleLinkElement::ParseLinkTypes(relVal, aElement->NodePrincipal());
|
||||
bool hasPrefetch = linkTypes & nsStyleLinkElement::ePREFETCH;
|
||||
if (hasPrefetch || (linkTypes & nsStyleLinkElement::eNEXT)) {
|
||||
nsAutoString hrefVal;
|
||||
aElement->GetAttr(kNameSpaceID_None, nsGkAtoms::href, hrefVal);
|
||||
if (!hrefVal.IsEmpty()) {
|
||||
PrefetchHref(hrefVal, aElement, hasPrefetch);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Re-open update
|
||||
BeginDocUpdate();
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ interface nsIURI;
|
||||
interface nsIDOMNode;
|
||||
interface nsISimpleEnumerator;
|
||||
|
||||
[scriptable, uuid(2df8b475-f536-4a1a-afea-b39843df8005)]
|
||||
[scriptable, uuid(422a1807-4e7f-463d-b8d7-ca2ceb9b5d53)]
|
||||
interface nsIPrefetchService : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -30,5 +30,8 @@ interface nsIPrefetchService : nsISupports
|
||||
*/
|
||||
boolean hasMoreElements();
|
||||
|
||||
// XXX do we need a way to cancel prefetch requests?
|
||||
/**
|
||||
* Cancel prefetch
|
||||
*/
|
||||
void cancelPrefetchURI(in nsIURI aURI, in nsIDOMNode aSource);
|
||||
};
|
||||
|
@ -82,16 +82,29 @@ nsPrefetchNode::nsPrefetchNode(nsPrefetchService *aService,
|
||||
, mChannel(nullptr)
|
||||
, mBytesRead(0)
|
||||
{
|
||||
mSource = do_GetWeakReference(aSource);
|
||||
nsCOMPtr<nsIWeakReference> source = do_GetWeakReference(aSource);
|
||||
mSources.AppendElement(source);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsPrefetchNode::OpenChannel()
|
||||
{
|
||||
nsCOMPtr<nsINode> source = do_QueryReferent(mSource);
|
||||
if (mSources.IsEmpty()) {
|
||||
// Don't attempt to prefetch if we don't have a source node
|
||||
// (which should never happen).
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsCOMPtr<nsINode> source;
|
||||
while (!mSources.IsEmpty() && !(source = do_QueryReferent(mSources.ElementAt(0)))) {
|
||||
// If source is null remove it.
|
||||
// (which should never happen).
|
||||
mSources.RemoveElementAt(0);
|
||||
}
|
||||
|
||||
if (!source) {
|
||||
// Don't attempt to prefetch if we don't have a source node
|
||||
// (which should never happen).
|
||||
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsCOMPtr<nsILoadGroup> loadGroup = source->OwnerDoc()->GetDocumentLoadGroup();
|
||||
@ -595,25 +608,46 @@ nsPrefetchService::Prefetch(nsIURI *aURI,
|
||||
}
|
||||
|
||||
//
|
||||
// cancel if being prefetched
|
||||
// Check whether it is being prefetched.
|
||||
//
|
||||
for (uint32_t i = 0; i < mCurrentNodes.Length(); ++i) {
|
||||
bool equals;
|
||||
if (NS_SUCCEEDED(mCurrentNodes[i]->mURI->Equals(aURI, &equals)) && equals) {
|
||||
LOG(("rejected: URL is already being prefetched\n"));
|
||||
return NS_ERROR_ABORT;
|
||||
if (NS_SUCCEEDED(mCurrentNodes[i]->mURI->Equals(aURI, &equals)) &&
|
||||
equals) {
|
||||
nsCOMPtr<nsIWeakReference> source = do_GetWeakReference(aSource);
|
||||
if (mCurrentNodes[i]->mSources.IndexOf(source) ==
|
||||
mCurrentNodes[i]->mSources.NoIndex) {
|
||||
LOG(("URL is already being prefetched, add a new reference "
|
||||
"document\n"));
|
||||
mCurrentNodes[i]->mSources.AppendElement(source);
|
||||
return NS_OK;
|
||||
} else {
|
||||
LOG(("URL is already being prefetched by this document"));
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// cancel if already on the prefetch queue
|
||||
// Check whether it is on the prefetch queue.
|
||||
//
|
||||
for (std::deque<RefPtr<nsPrefetchNode>>::iterator node = mQueue.begin();
|
||||
node != mQueue.end(); node++) {
|
||||
for (std::deque<RefPtr<nsPrefetchNode>>::iterator nodeIt = mQueue.begin();
|
||||
nodeIt != mQueue.end(); nodeIt++) {
|
||||
bool equals;
|
||||
if (NS_SUCCEEDED(node->get()->mURI->Equals(aURI, &equals)) && equals) {
|
||||
LOG(("rejected: URL is already on prefetch queue\n"));
|
||||
return NS_ERROR_ABORT;
|
||||
RefPtr<nsPrefetchNode> node = nodeIt->get();
|
||||
if (NS_SUCCEEDED(node->mURI->Equals(aURI, &equals)) && equals) {
|
||||
nsCOMPtr<nsIWeakReference> source = do_GetWeakReference(aSource);
|
||||
if (node->mSources.IndexOf(source) ==
|
||||
node->mSources.NoIndex) {
|
||||
LOG(("URL is already being prefetched, add a new reference "
|
||||
"document\n"));
|
||||
node->mSources.AppendElement(do_GetWeakReference(aSource));
|
||||
return NS_OK;
|
||||
} else {
|
||||
LOG(("URL is already being prefetched by this document"));
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -632,6 +666,72 @@ nsPrefetchService::Prefetch(nsIURI *aURI,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrefetchService::CancelPrefetchURI(nsIURI* aURI,
|
||||
nsIDOMNode* aSource)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aURI);
|
||||
|
||||
if (LOG_ENABLED()) {
|
||||
nsAutoCString spec;
|
||||
aURI->GetSpec(spec);
|
||||
LOG(("CancelPrefetchURI [%s]\n", spec.get()));
|
||||
}
|
||||
|
||||
//
|
||||
// look in current prefetches
|
||||
//
|
||||
for (uint32_t i = 0; i < mCurrentNodes.Length(); ++i) {
|
||||
bool equals;
|
||||
if (NS_SUCCEEDED(mCurrentNodes[i]->mURI->Equals(aURI, &equals)) &&
|
||||
equals) {
|
||||
nsCOMPtr<nsIWeakReference> source = do_GetWeakReference(aSource);
|
||||
if (mCurrentNodes[i]->mSources.IndexOf(source) !=
|
||||
mCurrentNodes[i]->mSources.NoIndex) {
|
||||
mCurrentNodes[i]->mSources.RemoveElement(source);
|
||||
if (mCurrentNodes[i]->mSources.IsEmpty()) {
|
||||
mCurrentNodes[i]->CancelChannel(NS_BINDING_ABORTED);
|
||||
mCurrentNodes.RemoveElementAt(i);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// look into the prefetch queue
|
||||
//
|
||||
for (std::deque<RefPtr<nsPrefetchNode>>::iterator nodeIt = mQueue.begin();
|
||||
nodeIt != mQueue.end(); nodeIt++) {
|
||||
bool equals;
|
||||
RefPtr<nsPrefetchNode> node = nodeIt->get();
|
||||
if (NS_SUCCEEDED(node->mURI->Equals(aURI, &equals)) && equals) {
|
||||
nsCOMPtr<nsIWeakReference> source = do_GetWeakReference(aSource);
|
||||
if (node->mSources.IndexOf(source) !=
|
||||
node->mSources.NoIndex) {
|
||||
|
||||
#ifdef DEBUG
|
||||
int32_t inx = node->mSources.IndexOf(source);
|
||||
nsCOMPtr<nsIDOMNode> domNode =
|
||||
do_QueryReferent(node->mSources.ElementAt(inx));
|
||||
MOZ_ASSERT(domNode);
|
||||
#endif
|
||||
|
||||
node->mSources.RemoveElement(source);
|
||||
if (node->mSources.IsEmpty()) {
|
||||
mQueue.erase(nodeIt);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// not found!
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrefetchService::PrefetchURI(nsIURI *aURI,
|
||||
nsIURI *aReferrerURI,
|
||||
|
@ -97,9 +97,9 @@ public:
|
||||
nsresult OpenChannel();
|
||||
nsresult CancelChannel(nsresult error);
|
||||
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
nsCOMPtr<nsIURI> mReferrerURI;
|
||||
nsCOMPtr<nsIWeakReference> mSource;
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
nsCOMPtr<nsIURI> mReferrerURI;
|
||||
nsTArray<nsCOMPtr<nsIWeakReference>> mSources;
|
||||
|
||||
private:
|
||||
~nsPrefetchNode() {}
|
||||
|
Loading…
Reference in New Issue
Block a user