зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1740692 - Establish a speculative connection when receiving rel=preconnect in 103 response, r=necko-reviewers,manuel,valentin
Differential Revision: https://phabricator.services.mozilla.com/D163572
This commit is contained in:
Родитель
d0d17578a8
Коммит
4273a3fbb7
|
@ -11221,6 +11221,12 @@
|
|||
value: false
|
||||
mirror: always
|
||||
|
||||
# Enable `Link: rel=preconnect` in 103 Early Hint response.
|
||||
- name: network.early-hints.preconnect.enabled
|
||||
type: RelaxedAtomicBool
|
||||
value: false
|
||||
mirror: always
|
||||
|
||||
# Whether to use the network process or not
|
||||
# Start a separate socket process. Performing networking on the socket process
|
||||
# is control by a sepparate pref
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/* 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/. */
|
||||
|
||||
#include "EarlyHintPreconnect.h"
|
||||
|
||||
#include "mozilla/CORSMode.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/StaticPrefs_network.h"
|
||||
#include "nsIOService.h"
|
||||
#include "nsIURI.h"
|
||||
|
||||
namespace mozilla::net {
|
||||
|
||||
void EarlyHintPreconnect::MaybePreconnect(const LinkHeader& aHeader,
|
||||
nsIURI* aBaseURI,
|
||||
nsIPrincipal* aPrincipal) {
|
||||
if (!StaticPrefs::network_early_hints_preconnect_enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!gIOService) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
if (NS_FAILED(aHeader.NewResolveHref(getter_AddRefs(uri), aBaseURI))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// only preconnect secure context urls
|
||||
if (!uri->SchemeIs("https")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Note that the http connection manager will limit the number of connections
|
||||
// we can make, so it should be fine we don't check duplicate preconnect
|
||||
// attempts here.
|
||||
CORSMode corsMode = dom::Element::StringToCORSMode(aHeader.mCrossOrigin);
|
||||
if (corsMode == CORS_ANONYMOUS) {
|
||||
gIOService->SpeculativeAnonymousConnect(uri, aPrincipal, nullptr);
|
||||
} else {
|
||||
gIOService->SpeculativeConnect(uri, aPrincipal, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla::net
|
|
@ -0,0 +1,24 @@
|
|||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_net_EarlyHintPreconnect_h
|
||||
#define mozilla_net_EarlyHintPreconnect_h
|
||||
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
namespace mozilla::net {
|
||||
|
||||
class EarlyHintPreconnect final {
|
||||
public:
|
||||
static void MaybePreconnect(const LinkHeader& aHeader, nsIURI* aBaseURI,
|
||||
nsIPrincipal* aPrincipal);
|
||||
|
||||
EarlyHintPreconnect() = delete;
|
||||
EarlyHintPreconnect(const EarlyHintPreconnect&) = delete;
|
||||
EarlyHintPreconnect& operator=(const EarlyHintPreconnect&) = delete;
|
||||
};
|
||||
|
||||
} // namespace mozilla::net
|
||||
|
||||
#endif // mozilla_net_EarlyHintPreconnect_h
|
|
@ -190,10 +190,6 @@ void EarlyHintPreloader::MaybeCreateAndInsertPreload(
|
|||
nsIURI* aBaseURI, nsIPrincipal* aPrincipal,
|
||||
nsICookieJarSettings* aCookieJarSettings,
|
||||
const nsACString& aResponseReferrerPolicy) {
|
||||
if (!aLinkHeader.mRel.LowerCaseEqualsASCII("preload")) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAttrValue as;
|
||||
ParseAsValue(aLinkHeader.mAs, as);
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "EarlyHintsService.h"
|
||||
#include "EarlyHintPreconnect.h"
|
||||
#include "EarlyHintPreloader.h"
|
||||
#include "mozilla/PreloadHashKey.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
@ -85,9 +86,13 @@ void EarlyHintsService::EarlyHint(const nsACString& aLinkHeader,
|
|||
|
||||
for (auto& linkHeader : linkHeaders) {
|
||||
CollectLinkTypeTelemetry(linkHeader.mRel);
|
||||
if (linkHeader.mRel.LowerCaseEqualsLiteral("preconnect")) {
|
||||
EarlyHintPreconnect::MaybePreconnect(linkHeader, aBaseURI, principal);
|
||||
} else if (linkHeader.mRel.LowerCaseEqualsLiteral("preload")) {
|
||||
EarlyHintPreloader::MaybeCreateAndInsertPreload(
|
||||
mOngoingEarlyHints, linkHeader, aBaseURI, principal, cookieJarSettings,
|
||||
aReferrerPolicy);
|
||||
mOngoingEarlyHints, linkHeader, aBaseURI, principal,
|
||||
cookieJarSettings, aReferrerPolicy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -98,6 +98,7 @@ UNIFIED_SOURCES += [
|
|||
"ConnectionEntry.cpp",
|
||||
"ConnectionHandle.cpp",
|
||||
"DnsAndConnectSocket.cpp",
|
||||
"EarlyHintPreconnect.cpp",
|
||||
"EarlyHintPreloader.cpp",
|
||||
"EarlyHintRegistrar.cpp",
|
||||
"EarlyHintsService.cpp",
|
||||
|
|
|
@ -2262,8 +2262,12 @@ nsresult nsHttpHandler::SpeculativeConnectInternal(
|
|||
if (mDebugObservations && obsService) {
|
||||
// this is basically used for test coverage of an otherwise 'hintable'
|
||||
// feature
|
||||
|
||||
// This is used to test if the `crossOrigin` attribute is parsed correctly.
|
||||
nsPrintfCString debugURL("%s%s", aURI->GetSpecOrDefault().get(),
|
||||
anonymous ? "anonymous" : "use-credentials");
|
||||
obsService->NotifyObservers(nullptr, "speculative-connect-request",
|
||||
nullptr);
|
||||
NS_ConvertUTF8toUTF16(debugURL).get());
|
||||
for (auto* cp :
|
||||
dom::ContentParent::AllProcesses(dom::ContentParent::eLive)) {
|
||||
PNeckoParent* neckoParent =
|
||||
|
|
|
@ -11,6 +11,7 @@ support-files =
|
|||
early_hint_error.sjs
|
||||
early_hint_asset.sjs
|
||||
early_hint_asset_html.sjs
|
||||
early_hint_preconnect_html.sjs
|
||||
post.html
|
||||
res.css
|
||||
res.css^headers^
|
||||
|
@ -146,3 +147,4 @@ skip-if =
|
|||
support-files =
|
||||
early_hint_referrer_policy_html.sjs
|
||||
early_hint_preload_test_helper.jsm
|
||||
[browser_103_preconnect.js]
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/* 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/. */
|
||||
|
||||
Services.prefs.setBoolPref("network.early-hints.enabled", true);
|
||||
Services.prefs.setBoolPref("network.early-hints.preconnect.enabled", true);
|
||||
Services.prefs.setBoolPref("network.http.debug-observations", true);
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
Services.prefs.clearUserPref("network.early-hints.enabled");
|
||||
Services.prefs.clearUserPref("network.early-hints.preconnect.enabled");
|
||||
Services.prefs.clearUserPref("network.http.debug-observations");
|
||||
});
|
||||
|
||||
// Test steps:
|
||||
// 1. Load early_hint_preconnect_html.sjs
|
||||
// 2. In early_hint_preconnect_html.sjs, a 103 response with
|
||||
// "rel=preconnect" is returned.
|
||||
// 3. We use "speculative-connect-request" topic to observe whether the
|
||||
// speculative connection is attempted.
|
||||
// 4. Finally, we check if the observed URL is the same as the expected.
|
||||
async function test_hint_preconnect(href, crossOrigin) {
|
||||
let requestUrl = `https://example.com/browser/netwerk/test/browser/early_hint_preconnect_html.sjs?href=${href}&crossOrigin=${crossOrigin}`;
|
||||
|
||||
let observed = "";
|
||||
let observer = {
|
||||
QueryInterface: ChromeUtils.generateQI(["nsIObserver"]),
|
||||
observe(aSubject, aTopic, aData) {
|
||||
if (aTopic == "speculative-connect-request") {
|
||||
Services.obs.removeObserver(observer, "speculative-connect-request");
|
||||
observed = aData;
|
||||
}
|
||||
},
|
||||
};
|
||||
Services.obs.addObserver(observer, "speculative-connect-request");
|
||||
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
url: requestUrl,
|
||||
waitForLoad: true,
|
||||
},
|
||||
async function() {}
|
||||
);
|
||||
|
||||
if (!crossOrigin) {
|
||||
crossOrigin = "anonymous";
|
||||
}
|
||||
|
||||
Assert.equal(observed, `${href}/${crossOrigin}`);
|
||||
}
|
||||
|
||||
add_task(async function test_103_preconnect() {
|
||||
await test_hint_preconnect("https://localhost", "use-credentials");
|
||||
await test_hint_preconnect("https://localhost", "");
|
||||
await test_hint_preconnect("https://localhost", "anonymous");
|
||||
});
|
|
@ -0,0 +1,33 @@
|
|||
"use strict";
|
||||
|
||||
function handleRequest(request, response) {
|
||||
Cu.importGlobalProperties(["URLSearchParams"]);
|
||||
let qs = new URLSearchParams(request.queryString);
|
||||
let href = qs.get("href");
|
||||
let crossOrigin = qs.get("crossOrigin");
|
||||
|
||||
// write to raw socket
|
||||
response.seizePower();
|
||||
|
||||
response.write("HTTP/1.1 103 Early Hint\r\n");
|
||||
response.write(
|
||||
`Link: <${href}>; rel=preconnect; crossOrigin=${crossOrigin}\r\n`
|
||||
);
|
||||
response.write("\r\n");
|
||||
|
||||
let body = `<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<h1>Test rel=preconnect<h1>
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
response.write("HTTP/1.1 200 OK\r\n");
|
||||
response.write("Content-Type: text/html;charset=utf-8\r\n");
|
||||
response.write("Cache-Control: no-cache\r\n");
|
||||
response.write(`Content-Length: ${body.length}\r\n`);
|
||||
response.write("\r\n");
|
||||
response.write(body);
|
||||
|
||||
response.finish();
|
||||
}
|
Загрузка…
Ссылка в новой задаче