Bug 1771867 - Early Hints Phase 2 - Part 2: Pass early hint preloads to preloader from IPC r=necko-reviewers,valentin

Differential Revision: https://phabricator.services.mozilla.com/D161173
This commit is contained in:
Manuel Bucher 2022-12-02 09:45:24 +00:00
Родитель a61c8650f9
Коммит 808529a4e4
13 изменённых файлов: 118 добавлений и 31 удалений

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

@ -6747,6 +6747,11 @@ void Document::SetHeaderData(nsAtom* aHeaderField, const nsAString& aData) {
}
}
void Document::SetEarlyHints(
nsTArray<net::EarlyHintConnectArgs>&& aEarlyHints) {
mEarlyHints = std::move(aEarlyHints);
}
void Document::TryChannelCharset(nsIChannel* aChannel, int32_t& aCharsetSource,
NotNull<const Encoding*>& aEncoding,
nsHtml5TreeOpExecutor* aExecutor) {

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

@ -322,6 +322,7 @@ enum BFCacheStatus {
namespace mozilla::net {
class ChannelEventQueue;
class EarlyHintConnectArgs;
} // namespace mozilla::net
// Must be kept in sync with xpcom/rust/xpcom/src/interfaces/nonidl.rs
@ -1168,6 +1169,15 @@ class Document : public nsINode,
void GetHeaderData(nsAtom* aHeaderField, nsAString& aData) const;
void SetHeaderData(nsAtom* aheaderField, const nsAString& aData);
/**
* Set Early Hint data, moves the arrays into the function, leaving the
* passed variables empty
*/
void SetEarlyHints(nsTArray<net::EarlyHintConnectArgs>&& aEarlyHints);
const nsTArray<net::EarlyHintConnectArgs>& GetEarlyHints() const {
return mEarlyHints;
}
/**
* Create a new presentation shell that will use aContext for its
* presentation context (presentation contexts <b>must not</b> be
@ -5117,6 +5127,8 @@ class Document : public nsINode,
class HeaderData;
UniquePtr<HeaderData> mHeaderData;
nsTArray<net::EarlyHintConnectArgs> mEarlyHints;
nsRevocableEventPtr<nsRunnableMethod<Document, void, false>>
mPendingTitleChangeEvent;

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

@ -569,6 +569,7 @@ LOCAL_INCLUDES += [
"/layout/style",
"/layout/xul",
"/netwerk/base",
"/netwerk/protocol/http",
"/netwerk/url-classifier",
"/parser/htmlparser",
"/security/manager/ssl",

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

@ -20,6 +20,8 @@
#include "mozilla/dom/MutationObservers.h"
#include "mozilla/dom/SRILogHelper.h"
#include "mozilla/StoragePrincipalHelper.h"
#include "mozilla/net/HttpBaseChannel.h"
#include "mozilla/net/NeckoChannelParams.h"
#include "nsIDocShell.h"
#include "nsILoadContext.h"
#include "nsIPrefetchService.h"
@ -222,16 +224,27 @@ nsresult nsContentSink::ProcessHTTPHeaders(nsIChannel* aChannel) {
return NS_OK;
}
bool gotEarlyHints = false;
if (nsCOMPtr<mozilla::net::HttpBaseChannel> baseChannel =
do_QueryInterface(aChannel)) {
nsTArray<mozilla::net::EarlyHintConnectArgs> earlyHints =
baseChannel->TakeEarlyHints();
gotEarlyHints = !earlyHints.IsEmpty();
mDocument->SetEarlyHints(std::move(earlyHints));
}
// Note that the only header we care about is the "link" header, since we
// have all the infrastructure for kicking off stylesheet loads.
nsAutoCString linkHeader;
nsresult rv = httpchannel->GetResponseHeader("link"_ns, linkHeader);
if (NS_SUCCEEDED(rv) && !linkHeader.IsEmpty()) {
bool gotLinkHeader = NS_SUCCEEDED(rv) && !linkHeader.IsEmpty();
if (gotLinkHeader) {
mDocument->SetHeaderData(nsGkAtoms::link,
NS_ConvertASCIItoUTF16(linkHeader));
}
if (gotLinkHeader || gotEarlyHints) {
NS_ASSERTION(!mProcessLinkHeaderEvent.get(),
"Already dispatched an event?");
@ -248,11 +261,15 @@ nsresult nsContentSink::ProcessHTTPHeaders(nsIChannel* aChannel) {
}
void nsContentSink::DoProcessLinkHeader() {
for (const auto& earlyHint : mDocument->GetEarlyHints()) {
ProcessLinkFromHeader(earlyHint.link(), earlyHint.earlyHintPreloaderId());
}
nsAutoString value;
mDocument->GetHeaderData(nsGkAtoms::link, value);
auto linkHeaders = net::ParseLinkHeader(value);
for (const auto& linkHeader : linkHeaders) {
ProcessLinkFromHeader(linkHeader);
ProcessLinkFromHeader(linkHeader, 0);
}
}
@ -297,7 +314,8 @@ bool nsContentSink::LinkContextIsOurDocument(const nsAString& aAnchor) {
return same;
}
nsresult nsContentSink::ProcessLinkFromHeader(const net::LinkHeader& aHeader) {
nsresult nsContentSink::ProcessLinkFromHeader(const net::LinkHeader& aHeader,
uint64_t aEarlyHintPreloaderId) {
uint32_t linkTypes = LinkStyle::ParseLinkTypes(aHeader.mRel);
// The link relation may apply to a different resource, specified
@ -325,7 +343,8 @@ nsresult nsContentSink::ProcessLinkFromHeader(const net::LinkHeader& aHeader) {
if (linkTypes & LinkStyle::ePRELOAD) {
PreloadHref(aHeader.mHref, aHeader.mAs, aHeader.mType, aHeader.mMedia,
aHeader.mIntegrity, aHeader.mSrcset, aHeader.mSizes,
aHeader.mCrossOrigin, aHeader.mReferrerPolicy);
aHeader.mCrossOrigin, aHeader.mReferrerPolicy,
aEarlyHintPreloaderId);
}
if ((linkTypes & LinkStyle::eMODULE_PRELOAD) &&
@ -435,7 +454,8 @@ void nsContentSink::PreloadHref(const nsAString& aHref, const nsAString& aAs,
const nsAString& aIntegrity,
const nsAString& aSrcset,
const nsAString& aSizes, const nsAString& aCORS,
const nsAString& aReferrerPolicy) {
const nsAString& aReferrerPolicy,
uint64_t aEarlyHintPreloaderId) {
auto encoding = mDocument->GetDocumentCharacterSet();
nsCOMPtr<nsIURI> uri;
NS_NewURI(getter_AddRefs(uri), aHref, encoding, mDocument->GetDocBaseURI());
@ -459,9 +479,9 @@ void nsContentSink::PreloadHref(const nsAString& aHref, const nsAString& aAs,
return;
}
mDocument->Preloads().PreloadLinkHeader(uri, aHref, policyType, aAs, aType,
aIntegrity, aSrcset, aSizes, aCORS,
aReferrerPolicy);
mDocument->Preloads().PreloadLinkHeader(
uri, aHref, policyType, aAs, aType, aIntegrity, aSrcset, aSizes, aCORS,
aReferrerPolicy, aEarlyHintPreloaderId);
}
void nsContentSink::PrefetchDNS(const nsAString& aHref) {

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

@ -125,7 +125,9 @@ class nsContentSink : public nsICSSLoaderObserver,
nsIChannel* aChannel);
nsresult ProcessHTTPHeaders(nsIChannel* aChannel);
nsresult ProcessLinkFromHeader(const mozilla::net::LinkHeader& aHeader);
// aEarlyHintPreloaderId zero means no early hint channel to connect back
nsresult ProcessLinkFromHeader(const mozilla::net::LinkHeader& aHeader,
uint64_t aEarlyHintPreloaderId);
virtual nsresult ProcessStyleLinkFromHeader(
const nsAString& aHref, bool aAlternate, const nsAString& aTitle,
@ -138,7 +140,8 @@ class nsContentSink : public nsICSSLoaderObserver,
const nsAString& aType, const nsAString& aMedia,
const nsAString& aIntegrity, const nsAString& aSrcset,
const nsAString& aSizes, const nsAString& aCORS,
const nsAString& aReferrerPolicy);
const nsAString& aReferrerPolicy,
uint64_t aEarlyHintPreloaderId);
// For PrefetchDNS() aHref can either be the usual
// URI format or of the form "//www.hostname.com" without a scheme.

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

@ -3550,6 +3550,10 @@ mozilla::ipc::IPCResult ContentChild::RecvCrossProcessRedirect(
getter_AddRefs(newChannel), aArgs.uri(), loadInfo, nullptr,
aArgs.newLoadFlags(), aArgs.srcdocData(), aArgs.baseUri());
if (RefPtr<HttpBaseChannel> httpChannel = do_QueryObject(newChannel)) {
httpChannel->SetEarlyHints(std::move(aArgs.earlyHints()));
}
// This is used to report any errors back to the parent by calling
// CrossProcessRedirectFinished.
RefPtr<HttpChannelChild> httpChild = do_QueryObject(newChannel);

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

@ -267,6 +267,10 @@ IPCResult DocumentChannelChild::RecvRedirectToRealChannel(
newChannel->SetLoadGroup(mLoadGroup);
}
if (RefPtr<HttpBaseChannel> httpChannel = do_QueryObject(newChannel)) {
httpChannel->SetEarlyHints(std::move(aArgs.earlyHints()));
}
// This is used to report any errors back to the parent by calling
// CrossProcessRedirectFinished.
auto scopeExit = MakeScopeExit([&]() {

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

@ -5945,6 +5945,15 @@ void HttpBaseChannel::SetDummyChannelForImageCache() {
mResponseHead = MakeUnique<nsHttpResponseHead>();
}
void HttpBaseChannel::SetEarlyHints(
nsTArray<EarlyHintConnectArgs>&& aEarlyHints) {
mEarlyHints = std::move(aEarlyHints);
}
nsTArray<EarlyHintConnectArgs>&& HttpBaseChannel::TakeEarlyHints() {
return std::move(mEarlyHints);
}
void HttpBaseChannel::SetConnectionInfo(nsHttpConnectionInfo* aCI) {
mConnectionInfo = aCI ? aCI->Clone() : nullptr;
}

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

@ -14,6 +14,7 @@
#include "mozilla/Atomics.h"
#include "mozilla/dom/DOMTypes.h"
#include "mozilla/net/DNS.h"
#include "mozilla/net/NeckoChannelParams.h"
#include "mozilla/net/NeckoCommon.h"
#include "mozilla/net/PrivateBrowsingChannel.h"
#include "nsCOMPtr.h"
@ -785,6 +786,18 @@ class HttpBaseChannel : public nsHashPropertyBag,
ClassOfService mClassOfService;
public:
void SetEarlyHints(
nsTArray<mozilla::net::EarlyHintConnectArgs>&& aEarlyHints);
nsTArray<mozilla::net::EarlyHintConnectArgs>&& TakeEarlyHints();
protected:
// Storing Http 103 Early Hint preloads. The parent process is responsible to
// start the early hint preloads, but the http child needs to be able to look
// them up. They are sent via IPC and stored in this variable. This is set on
// main document channel
nsTArray<EarlyHintConnectArgs> mEarlyHints;
// clang-format off
MOZ_ATOMIC_BITFIELDS(mAtomicBitfields1, 32, (
(uint32_t, UpgradeToSecure, 1),

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

@ -15,6 +15,7 @@ class TimeStamp;
namespace net {
class nsHttpConnectionInfo;
class WebSocketConnectionBase;
class EarlyHintConnectArgs;
}
namespace dom {
enum class RequestMode : uint8_t;

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

@ -1285,7 +1285,7 @@ void nsHtml5TreeOpExecutor::PreloadFont(const nsAString& aURL,
return;
}
mDocument->Preloads().PreloadFont(uri, aCrossOrigin, aReferrerPolicy);
mDocument->Preloads().PreloadFont(uri, aCrossOrigin, aReferrerPolicy, 0);
}
void nsHtml5TreeOpExecutor::PreloadFetch(const nsAString& aURL,
@ -1297,7 +1297,7 @@ void nsHtml5TreeOpExecutor::PreloadFetch(const nsAString& aURL,
return;
}
mDocument->Preloads().PreloadFetch(uri, aCrossOrigin, aReferrerPolicy);
mDocument->Preloads().PreloadFetch(uri, aCrossOrigin, aReferrerPolicy, 0);
}
void nsHtml5TreeOpExecutor::PreloadOpenPicture() {

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

@ -87,7 +87,7 @@ already_AddRefed<PreloaderBase> PreloadService::PreloadLinkElement(
auto result = PreloadOrCoalesce(uri, url, aPolicyType, as, type, charset,
srcset, sizes, integrity, crossOrigin,
referrerPolicy, /* aFromHeader = */ false);
referrerPolicy, /* aFromHeader = */ false, 0);
if (!result.mPreloader) {
NotifyNodeEvent(aLinkElement, result.mAlreadyComplete);
@ -102,7 +102,7 @@ void PreloadService::PreloadLinkHeader(
nsIURI* aURI, const nsAString& aURL, nsContentPolicyType aPolicyType,
const nsAString& aAs, const nsAString& aType, const nsAString& aIntegrity,
const nsAString& aSrcset, const nsAString& aSizes, const nsAString& aCORS,
const nsAString& aReferrerPolicy) {
const nsAString& aReferrerPolicy, uint64_t aEarlyHintPreloaderId) {
if (aPolicyType == nsIContentPolicy::TYPE_INVALID) {
MOZ_ASSERT_UNREACHABLE("Caller should check");
return;
@ -114,7 +114,7 @@ void PreloadService::PreloadLinkHeader(
PreloadOrCoalesce(aURI, aURL, aPolicyType, aAs, aType, u""_ns, aSrcset,
aSizes, aIntegrity, aCORS, aReferrerPolicy,
/* aFromHeader = */ true);
/* aFromHeader = */ true, aEarlyHintPreloaderId);
}
PreloadService::PreloadOrCoalesceResult PreloadService::PreloadOrCoalesce(
@ -122,7 +122,8 @@ PreloadService::PreloadOrCoalesceResult PreloadService::PreloadOrCoalesce(
const nsAString& aAs, const nsAString& aType, const nsAString& aCharset,
const nsAString& aSrcset, const nsAString& aSizes,
const nsAString& aIntegrity, const nsAString& aCORS,
const nsAString& aReferrerPolicy, bool aFromHeader) {
const nsAString& aReferrerPolicy, bool aFromHeader,
uint64_t aEarlyHintPreloaderId) {
if (!aURI) {
MOZ_ASSERT_UNREACHABLE("Should not pass null nsIURI");
return {nullptr, false};
@ -163,7 +164,7 @@ PreloadService::PreloadOrCoalesceResult PreloadService::PreloadOrCoalesce(
if (aAs.LowerCaseEqualsASCII("script")) {
PreloadScript(uri, aType, aCharset, aCORS, aReferrerPolicy, aIntegrity,
true /* isInHead - TODO */);
true /* isInHead - TODO */, aEarlyHintPreloaderId);
} else if (aAs.LowerCaseEqualsASCII("style")) {
auto status = mDocument->PreloadStyle(
aURI, Encoding::ForLabel(aCharset), aCORS,
@ -178,11 +179,11 @@ PreloadService::PreloadOrCoalesceResult PreloadService::PreloadOrCoalesce(
break;
}
} else if (aAs.LowerCaseEqualsASCII("image")) {
PreloadImage(uri, aCORS, aReferrerPolicy, isImgSet);
PreloadImage(uri, aCORS, aReferrerPolicy, isImgSet, aEarlyHintPreloaderId);
} else if (aAs.LowerCaseEqualsASCII("font")) {
PreloadFont(uri, aCORS, aReferrerPolicy);
PreloadFont(uri, aCORS, aReferrerPolicy, aEarlyHintPreloaderId);
} else if (aAs.LowerCaseEqualsASCII("fetch")) {
PreloadFetch(uri, aCORS, aReferrerPolicy);
PreloadFetch(uri, aCORS, aReferrerPolicy, aEarlyHintPreloaderId);
}
return {LookupPreload(preloadKey), false};
@ -193,7 +194,8 @@ void PreloadService::PreloadScript(nsIURI* aURI, const nsAString& aType,
const nsAString& aCrossOrigin,
const nsAString& aReferrerPolicy,
const nsAString& aIntegrity,
bool aScriptFromHead) {
bool aScriptFromHead,
uint64_t aEarlyHintPreloaderId) {
mDocument->ScriptLoader()->PreloadURI(
aURI, aCharset, aType, aCrossOrigin, aIntegrity, aScriptFromHead, false,
false, false, true, PreloadReferrerPolicy(aReferrerPolicy));
@ -201,14 +203,16 @@ void PreloadService::PreloadScript(nsIURI* aURI, const nsAString& aType,
void PreloadService::PreloadImage(nsIURI* aURI, const nsAString& aCrossOrigin,
const nsAString& aImageReferrerPolicy,
bool aIsImgSet) {
bool aIsImgSet,
uint64_t aEarlyHintPreloaderId) {
mDocument->PreLoadImage(aURI, aCrossOrigin,
PreloadReferrerPolicy(aImageReferrerPolicy),
aIsImgSet, true);
}
void PreloadService::PreloadFont(nsIURI* aURI, const nsAString& aCrossOrigin,
const nsAString& aReferrerPolicy) {
const nsAString& aReferrerPolicy,
uint64_t aEarlyHintPreloaderId) {
CORSMode cors = dom::Element::StringToCORSMode(aCrossOrigin);
auto key = PreloadHashKey::CreateAsFont(aURI, cors);
@ -221,7 +225,8 @@ void PreloadService::PreloadFont(nsIURI* aURI, const nsAString& aCrossOrigin,
}
void PreloadService::PreloadFetch(nsIURI* aURI, const nsAString& aCrossOrigin,
const nsAString& aReferrerPolicy) {
const nsAString& aReferrerPolicy,
uint64_t aEarlyHintPreloaderId) {
CORSMode cors = dom::Element::StringToCORSMode(aCrossOrigin);
auto key = PreloadHashKey::CreateAsFetch(aURI, cors);

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

@ -66,26 +66,35 @@ class PreloadService {
already_AddRefed<PreloaderBase> PreloadLinkElement(
dom::HTMLLinkElement* aLink, nsContentPolicyType aPolicyType);
// a non-zero aEarlyHintPreloaderId tells this service that a preload for this
// link was started by the EarlyHintPreloader and the preloaders should
// connect back by setting earlyHintPreloaderId in nsIChannelInternal before
// AsyncOpen.
void PreloadLinkHeader(nsIURI* aURI, const nsAString& aURL,
nsContentPolicyType aPolicyType, const nsAString& aAs,
const nsAString& aType, const nsAString& aIntegrity,
const nsAString& aSrcset, const nsAString& aSizes,
const nsAString& aCORS,
const nsAString& aReferrerPolicy);
const nsAString& aReferrerPolicy,
uint64_t aEarlyHintPreloaderId);
void PreloadScript(nsIURI* aURI, const nsAString& aType,
const nsAString& aCharset, const nsAString& aCrossOrigin,
const nsAString& aReferrerPolicy,
const nsAString& aIntegrity, bool aScriptFromHead);
const nsAString& aIntegrity, bool aScriptFromHead,
uint64_t aEarlyHintPreloaderId);
void PreloadImage(nsIURI* aURI, const nsAString& aCrossOrigin,
const nsAString& aImageReferrerPolicy, bool aIsImgSet);
const nsAString& aImageReferrerPolicy, bool aIsImgSet,
uint64_t aEarlyHintPreloaderId);
void PreloadFont(nsIURI* aURI, const nsAString& aCrossOrigin,
const nsAString& aReferrerPolicy);
const nsAString& aReferrerPolicy,
uint64_t aEarlyHintPreloaderId);
void PreloadFetch(nsIURI* aURI, const nsAString& aCrossOrigin,
const nsAString& aReferrerPolicy);
const nsAString& aReferrerPolicy,
uint64_t aEarlyHintPreloaderId);
static void NotifyNodeEvent(nsINode* aNode, bool aSuccess);
@ -103,7 +112,8 @@ class PreloadService {
const nsAString& aAs, const nsAString& aType, const nsAString& aCharset,
const nsAString& aSrcset, const nsAString& aSizes,
const nsAString& aIntegrity, const nsAString& aCORS,
const nsAString& aReferrerPolicy, bool aFromHeader);
const nsAString& aReferrerPolicy, bool aFromHeader,
uint64_t aEarlyHintPreloaderId);
private:
nsRefPtrHashtable<PreloadHashKey, PreloaderBase> mPreloads;