зеркало из https://github.com/mozilla/gecko-dev.git
bug 1135160 - implement link rel=preconnect r=smaug
--HG-- extra : rebase_source : 445d77480f9cd6ca8ce0bfd9e6596f92d459323a
This commit is contained in:
Родитель
3e9f2476b0
Коммит
0110ebbcda
|
@ -33,6 +33,7 @@
|
|||
#include "nsIApplicationCacheContainer.h"
|
||||
#include "nsIApplicationCacheChannel.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsISpeculativeConnect.h"
|
||||
#include "nsICookieService.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsNodeInfoManager.h"
|
||||
|
@ -686,6 +687,10 @@ nsContentSink::ProcessLink(const nsSubstring& aAnchor, const nsSubstring& aHref,
|
|||
PrefetchDNS(aHref);
|
||||
}
|
||||
|
||||
if (!aHref.IsEmpty() && (linkTypes & nsStyleLinkElement::ePRECONNECT)) {
|
||||
Preconnect(aHref);
|
||||
}
|
||||
|
||||
// is it a stylesheet link?
|
||||
if (!(linkTypes & nsStyleLinkElement::eSTYLESHEET)) {
|
||||
return NS_OK;
|
||||
|
@ -857,6 +862,26 @@ nsContentSink::PrefetchDNS(const nsAString &aHref)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsContentSink::Preconnect(const nsAString &aHref)
|
||||
{
|
||||
nsCOMPtr<nsISpeculativeConnect>
|
||||
speculator(do_QueryInterface(nsContentUtils::GetIOService()));
|
||||
if (!speculator) {
|
||||
return;
|
||||
}
|
||||
|
||||
// construct URI using document charset
|
||||
const nsACString& charset = mDocument->GetDocumentCharacterSet();
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
NS_NewURI(getter_AddRefs(uri), aHref,
|
||||
charset.IsEmpty() ? nullptr : PromiseFlatCString(charset).get(),
|
||||
mDocument->GetDocBaseURI());
|
||||
if (uri) {
|
||||
speculator->SpeculativeConnect(uri, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsContentSink::SelectDocAppCache(nsIApplicationCache *aLoadApplicationCache,
|
||||
nsIURI *aManifestURI,
|
||||
|
|
|
@ -164,9 +164,10 @@ protected:
|
|||
void PrefetchHref(const nsAString &aHref, nsINode *aSource,
|
||||
bool aExplicit);
|
||||
|
||||
// aHref can either be the usual URI format or of the form "//www.hostname.com"
|
||||
// without a scheme.
|
||||
// For both PrefetchDNS() and Preconnect() aHref can either be the usual
|
||||
// URI format or of the form "//www.hostname.com" without a scheme.
|
||||
void PrefetchDNS(const nsAString &aHref);
|
||||
void Preconnect(const nsAString &aHref);
|
||||
|
||||
// Gets the cache key (used to identify items in a cache) of the channel.
|
||||
nsresult GetChannelCacheKey(nsIChannel* aChannel, nsACString& aCacheKey);
|
||||
|
|
|
@ -150,6 +150,8 @@ static uint32_t ToLinkMask(const nsAString& aLink, nsIPrincipal* aPrincipal)
|
|||
else if (aLink.EqualsLiteral("import") &&
|
||||
nsStyleLinkElement::IsImportEnabled())
|
||||
return nsStyleLinkElement::eHTMLIMPORT;
|
||||
else if (aLink.EqualsLiteral("preconnect"))
|
||||
return nsStyleLinkElement::ePRECONNECT;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -59,7 +59,8 @@ public:
|
|||
eSTYLESHEET = 0x00000004,
|
||||
eNEXT = 0x00000008,
|
||||
eALTERNATE = 0x00000010,
|
||||
eHTMLIMPORT = 0x00000020
|
||||
eHTMLIMPORT = 0x00000020,
|
||||
ePRECONNECT = 0x00000040
|
||||
};
|
||||
|
||||
// The return value is a bitwise or of 0 or more RelValues.
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "nsIDOMEvent.h"
|
||||
#include "nsIDOMStyleSheet.h"
|
||||
#include "nsINode.h"
|
||||
#include "nsISpeculativeConnect.h"
|
||||
#include "nsIStyleSheet.h"
|
||||
#include "nsIStyleSheetLinkingElement.h"
|
||||
#include "nsIURL.h"
|
||||
|
@ -147,6 +148,10 @@ HTMLLinkElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
|
|||
aDocument->RegisterPendingLinkUpdate(this);
|
||||
}
|
||||
|
||||
if (IsInComposedDoc()) {
|
||||
UpdatePreconnect();
|
||||
}
|
||||
|
||||
void (HTMLLinkElement::*update)() = &HTMLLinkElement::UpdateStyleSheetInternal;
|
||||
nsContentUtils::AddScriptRunner(NS_NewRunnableMethod(this, update));
|
||||
|
||||
|
@ -292,6 +297,30 @@ 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;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISpeculativeConnect>
|
||||
speculator(do_QueryInterface(nsContentUtils::GetIOService()));
|
||||
if (speculator) {
|
||||
nsCOMPtr<nsIURI> uri = GetHrefURI();
|
||||
if (uri) {
|
||||
speculator->SpeculativeConnect(uri, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
HTMLLinkElement::SetAttr(int32_t aNameSpaceID, nsIAtom* aName,
|
||||
nsIAtom* aPrefix, const nsAString& aValue,
|
||||
|
@ -326,11 +355,16 @@ HTMLLinkElement::SetAttr(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();
|
||||
}
|
||||
}
|
||||
|
||||
UpdateStyleSheetInternal(nullptr, nullptr,
|
||||
|
|
|
@ -43,6 +43,7 @@ public:
|
|||
void LinkRemoved();
|
||||
|
||||
void UpdateImport();
|
||||
void UpdatePreconnect();
|
||||
|
||||
// nsIDOMEventTarget
|
||||
virtual nsresult PreHandleEvent(EventChainPreVisitor& aVisitor) MOZ_OVERRIDE;
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "nsPrincipal.h"
|
||||
#include "nsIOService.h"
|
||||
#include "mozilla/net/OfflineObserver.h"
|
||||
#include "nsISpeculativeConnect.h"
|
||||
|
||||
using mozilla::dom::ContentParent;
|
||||
using mozilla::dom::TabContext;
|
||||
|
@ -668,6 +669,17 @@ NeckoParent::DeallocPRemoteOpenFileParent(PRemoteOpenFileParent* actor)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
NeckoParent::RecvSpeculativeConnect(const URIParams &aURI)
|
||||
{
|
||||
nsCOMPtr<nsISpeculativeConnect> speculator(gIOService);
|
||||
nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
|
||||
if (uri && speculator) {
|
||||
speculator->SpeculativeConnect(uri, nullptr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
NeckoParent::RecvHTMLDNSPrefetch(const nsString& hostname,
|
||||
const uint16_t& flags)
|
||||
|
|
|
@ -160,6 +160,7 @@ protected:
|
|||
const uint32_t& flags,
|
||||
const nsCString& aNetworkInterface) MOZ_OVERRIDE;
|
||||
virtual bool DeallocPDNSRequestParent(PDNSRequestParent*) MOZ_OVERRIDE;
|
||||
virtual bool RecvSpeculativeConnect(const URIParams& aURI) MOZ_OVERRIDE;
|
||||
virtual bool RecvHTMLDNSPrefetch(const nsString& hostname,
|
||||
const uint16_t& flags) MOZ_OVERRIDE;
|
||||
virtual bool RecvCancelHTMLDNSPrefetch(const nsString& hostname,
|
||||
|
|
|
@ -73,6 +73,7 @@ parent:
|
|||
URIParams fileuri,
|
||||
OptionalURIParams appuri);
|
||||
|
||||
SpeculativeConnect(URIParams uri);
|
||||
HTMLDNSPrefetch(nsString hostname, uint16_t flags);
|
||||
CancelHTMLDNSPrefetch(nsString hostname, uint16_t flags, nsresult reason);
|
||||
PRtspController();
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include "nsINetworkLinkService.h"
|
||||
|
||||
#include "mozilla/net/NeckoChild.h"
|
||||
#include "mozilla/ipc/URIUtils.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
||||
#if defined(XP_UNIX)
|
||||
|
@ -1989,6 +1990,13 @@ NS_IMETHODIMP
|
|||
nsHttpHandler::SpeculativeConnect(nsIURI *aURI,
|
||||
nsIInterfaceRequestor *aCallbacks)
|
||||
{
|
||||
if (IsNeckoChild()) {
|
||||
ipc::URIParams params;
|
||||
SerializeURI(aURI, params);
|
||||
gNeckoChild->SendSpeculativeConnect(params);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!mHandlerActive)
|
||||
return NS_OK;
|
||||
|
||||
|
|
|
@ -4,11 +4,13 @@ skip-if = buildapp == 'b2g' || e10s || toolkit == 'android' # Android: Bug 11111
|
|||
support-files =
|
||||
method.sjs
|
||||
partial_content.sjs
|
||||
rel_preconnect.sjs
|
||||
user_agent.sjs
|
||||
user_agent_update.sjs
|
||||
|
||||
[test_arraybufferinputstream.html]
|
||||
[test_partially_cached_content.html]
|
||||
[test_rel_preconnect.html]
|
||||
[test_uri_scheme.html]
|
||||
[test_user_agent_overrides.html]
|
||||
[test_user_agent_updates.html]
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
// Generate response header "Link: <HREF>; rel=preconnect"
|
||||
// HREF is provided by the request header X-Link
|
||||
|
||||
function handleRequest(request, response)
|
||||
{
|
||||
response.setHeader("Cache-Control", "no-cache", false);
|
||||
response.setHeader("Link", "<" +
|
||||
request.getHeader('X-Link') +
|
||||
">; rel=preconnect");
|
||||
response.write("check that header");
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
-->
|
||||
<head>
|
||||
<title>Test for link rel=preconnect</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
|
||||
<script type="text/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const Cc = SpecialPowers.Cc, Ci = SpecialPowers.Ci, Cr = SpecialPowers.Cr;
|
||||
var srv;
|
||||
|
||||
function TestServer(nextTest) {
|
||||
this.listener= Cc["@mozilla.org/network/server-socket;1"]
|
||||
.createInstance(Ci.nsIServerSocket);
|
||||
this.listener.init(-1, true, -1);
|
||||
this.listener.asyncListen(SpecialPowers.wrapCallbackObject(this));
|
||||
this.nextTest = nextTest;
|
||||
}
|
||||
|
||||
TestServer.prototype = {
|
||||
QueryInterface: function(iid) {
|
||||
iid = SpecialPowers.wrap(iid);
|
||||
if (iid.equals(Ci.nsIServerSocketListener) ||
|
||||
iid.equals(Ci.nsISupports))
|
||||
return this;
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
onSocketAccepted: function(socket, trans) {
|
||||
try { socket.close(); } catch(e) {}
|
||||
try { trans.close(); } catch(e) {}
|
||||
ok(true, "received connect");
|
||||
setTimeout(srv.nextTest, 0);
|
||||
},
|
||||
onStopListening: function(socket) {}
|
||||
};
|
||||
|
||||
var originalLimit = SpecialPowers.getIntPref("network.http.speculative-parallel-limit");
|
||||
|
||||
function testElement()
|
||||
{
|
||||
// test the link rel=preconnect element in the head
|
||||
srv = new TestServer(testHeader);
|
||||
SpecialPowers.setIntPref("network.http.speculative-parallel-limit", 1);
|
||||
var link = document.createElement("link");
|
||||
link.rel = "preconnect";
|
||||
link.href = "//localhost:" + srv.listener.port;
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
|
||||
function testHeader()
|
||||
{
|
||||
// test the http link response header
|
||||
srv.listener.close();
|
||||
srv = new TestServer(testDone);
|
||||
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');
|
||||
}
|
||||
|
||||
function testDone()
|
||||
{
|
||||
SpecialPowers.setIntPref("network.http.speculative-parallel-limit",
|
||||
originalLimit);
|
||||
srv.listener.close();
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="testElement();">
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
Загрузка…
Ссылка в новой задаче