Backed out 3 changesets (bug 1753730) for causing bc failures on browser_103_preload.js.

Backed out changeset 8f27dc8dbbe0 (bug 1753730)
Backed out changeset 3c25877d2660 (bug 1753730)
Backed out changeset 47787105e3ad (bug 1753730)
This commit is contained in:
Iulian Moraru 2022-05-03 23:24:34 +03:00
Родитель 660ff47e74
Коммит f65b926595
27 изменённых файлов: 69 добавлений и 1183 удалений

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

@ -1264,10 +1264,6 @@ void CanonicalBrowsingContext::AddFinalDiscardListener(
mFullyDiscardedListeners.AppendElement(std::move(aListener));
}
net::EarlyHintsService* CanonicalBrowsingContext::GetEarlyHintsService() {
return &mEarlyHintsService;
}
void CanonicalBrowsingContext::AdjustPrivateBrowsingCount(
bool aPrivateBrowsing) {
if (IsDiscarded() || !EverAttached() || IsChrome()) {

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

@ -7,7 +7,6 @@
#ifndef mozilla_dom_CanonicalBrowsingContext_h
#define mozilla_dom_CanonicalBrowsingContext_h
#include "mozilla/net/EarlyHintsService.h"
#include "mozilla/dom/BrowsingContext.h"
#include "mozilla/dom/MediaControlKeySource.h"
#include "mozilla/dom/BrowsingContextWebProgress.h"
@ -362,8 +361,6 @@ class CanonicalBrowsingContext final : public BrowsingContext {
void AddFinalDiscardListener(std::function<void(uint64_t)>&& aListener);
net::EarlyHintsService* GetEarlyHintsService();
protected:
// Called when the browsing context is being discarded.
void CanonicalDiscard();
@ -567,8 +564,6 @@ class CanonicalBrowsingContext final : public BrowsingContext {
bool mFullyDiscarded = false;
nsTArray<std::function<void(uint64_t)>> mFullyDiscardedListeners;
net::EarlyHintsService mEarlyHintsService;
};
} // namespace dom

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

@ -10338,12 +10338,6 @@
value: true
mirror: always
# Enable 103 Early Hint status code (RFC 8297)
- name: network.early-hints.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

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

@ -1104,9 +1104,7 @@ void DocumentLoadListener::Disconnect(bool aContinueNavigating) {
httpChannelImpl->SetEarlyHintObserver(nullptr);
}
if (GetLoadingBrowsingContext()) {
GetLoadingBrowsingContext()->mEarlyHintsService.Cancel();
}
mEarlyHintsService.Cancel();
if (auto* ctx = GetDocumentBrowsingContext()) {
ctx->EndDocumentLoad(aContinueNavigating);
@ -2474,15 +2472,12 @@ DocumentLoadListener::OnStartRequest(nsIRequest* aRequest) {
}
}
if (GetLoadingBrowsingContext()) {
if (httpChannel) {
uint32_t responseStatus;
Unused << httpChannel->GetResponseStatus(&responseStatus);
GetLoadingBrowsingContext()->mEarlyHintsService.FinalResponse(
responseStatus);
} else {
GetLoadingBrowsingContext()->mEarlyHintsService.Cancel();
}
if (httpChannel) {
uint32_t responseStatus;
Unused << httpChannel->GetResponseStatus(&responseStatus);
mEarlyHintsService.FinalResponse(responseStatus);
} else {
mEarlyHintsService.Cancel();
}
// If we're going to be delivering this channel to a remote content
@ -2853,11 +2848,8 @@ NS_IMETHODIMP DocumentLoadListener::OnStatus(nsIRequest* aRequest,
NS_IMETHODIMP DocumentLoadListener::EarlyHint(const nsACString& linkHeader) {
LOG(("DocumentLoadListener::EarlyHint.\n"));
if (GetLoadingBrowsingContext()) {
nsCOMPtr<nsILoadInfo> loadInfo = mChannel->LoadInfo();
GetLoadingBrowsingContext()->mEarlyHintsService.EarlyHint(
linkHeader, GetChannelCreationURI(), loadInfo);
}
mEarlyHintsService.EarlyHint(linkHeader);
return NS_OK;
}

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

@ -619,6 +619,8 @@ class DocumentLoadListener : public nsIInterfaceRequestor,
bool mOpenPromiseResolved = false;
const bool mIsDocumentLoad;
EarlyHintsService mEarlyHintsService;
};
NS_DEFINE_STATIC_IID_ACCESSOR(DocumentLoadListener, DOCUMENT_LOAD_LISTENER_IID)

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

@ -1,314 +0,0 @@
/* 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 "EarlyHintPreloader.h"
#include "EarlyHintsService.h"
#include "ErrorList.h"
#include "mozilla/CORSMode.h"
#include "mozilla/dom/ReferrerInfo.h"
#include "mozilla/Logging.h"
#include "nsAttrValue.h"
#include "nsAttrValueInlines.h"
#include "nsContentUtils.h"
#include "nsDebug.h"
#include "nsIAsyncVerifyRedirectCallback.h"
#include "nsICacheInfoChannel.h"
#include "nsIChannel.h"
#include "nsIHttpChannel.h"
#include "nsIInputStream.h"
#include "nsIReferrerInfo.h"
#include "nsIURI.h"
#include "nsNetUtil.h"
#include "nsStreamUtils.h"
//
// To enable logging (see mozilla/Logging.h for full details):
//
// set MOZ_LOG=EarlyHint:5
// set MOZ_LOG_FILE=earlyhint.log
//
// this enables LogLevel::Debug level information and places all output in
// the file earlyhint.log
//
static mozilla::LazyLogModule gEarlyHintLog("EarlyHint");
#undef LOG
#define LOG(args) MOZ_LOG(gEarlyHintLog, mozilla::LogLevel::Debug, args)
#undef LOG_ENABLED
#define LOG_ENABLED() MOZ_LOG_TEST(gEarlyHintLog, mozilla::LogLevel::Debug)
namespace mozilla::net {
//=============================================================================
// OngoingEarlyHints
//=============================================================================
void OngoingEarlyHints::CancelAllOngoingPreloads() {
for (auto& el : mOngoingPreloads) {
el.GetData()->CancelChannel(nsresult::NS_ERROR_ABORT);
}
}
bool OngoingEarlyHints::Contains(const PreloadHashKey& aKey) {
return mOngoingPreloads.Contains(aKey);
}
bool OngoingEarlyHints::Add(const PreloadHashKey& aKey,
RefPtr<EarlyHintPreloader> aPreloader) {
return mOngoingPreloads.InsertOrUpdate(aKey, aPreloader);
}
//=============================================================================
// EarlyHintPreloader
//=============================================================================
EarlyHintPreloader::EarlyHintPreloader(nsIURI* aURI) : mURI(aURI) {}
/* static */
Maybe<PreloadHashKey> EarlyHintPreloader::GenerateHashKey(
ASDestination aAs, nsIURI* aURI, nsIPrincipal* aPrincipal) {
if (aAs == ASDestination::DESTINATION_IMAGE) {
return Some(
PreloadHashKey::CreateAsImage(aURI, aPrincipal, CORSMode::CORS_NONE));
}
return Nothing();
}
// static
void EarlyHintPreloader::MaybeCreateAndInsertPreload(
OngoingEarlyHints* aOngoingEarlyHints, const LinkHeader& aHeader,
nsIURI* aBaseURI, nsIPrincipal* aTriggeringPrincipal,
nsICookieJarSettings* aCookieJarSettings) {
if (!aHeader.mRel.LowerCaseEqualsASCII("preload")) {
return;
}
nsAttrValue as;
ParseAsValue(aHeader.mAs, as);
if (as.GetEnumValue() == ASDestination::DESTINATION_INVALID) {
// return early when it's definitly not an asset type we preload
// would be caught later as well, e.g. when creating the PreloadHashKey
return;
}
nsCOMPtr<nsIURI> uri;
// use the base uri
NS_ENSURE_SUCCESS_VOID(
NS_NewURI(getter_AddRefs(uri), aHeader.mHref, nullptr, aBaseURI));
// Only make same origin preloads, the fromPrivateWindow is only read when
// reportError is enabled, so setting both to false is safe.
if (NS_FAILED(nsContentUtils::GetSecurityManager()->CheckSameOriginURI(
aBaseURI, uri, /* reportError */ false,
/* fromPrivateWindow */ false))) {
return;
}
Maybe<PreloadHashKey> hashKey = GenerateHashKey(
static_cast<ASDestination>(as.GetEnumValue()), uri, aTriggeringPrincipal);
if (!hashKey) {
return;
}
if (aOngoingEarlyHints->Contains(*hashKey)) {
return;
}
nsContentPolicyType contentPolicyType = AsValueToContentPolicy(as);
if (contentPolicyType == nsContentPolicyType::TYPE_INVALID) {
return;
}
dom::ReferrerPolicy referrerPolicy =
dom::ReferrerInfo::ReferrerPolicyAttributeFromString(
aHeader.mReferrerPolicy);
nsCOMPtr<nsIReferrerInfo> referrerInfo =
new dom::ReferrerInfo(aBaseURI, referrerPolicy);
RefPtr<EarlyHintPreloader> earlyHintPreloader =
RefPtr(new EarlyHintPreloader(uri));
nsSecurityFlags securityFlags =
nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_INHERITS_SEC_CONTEXT;
NS_ENSURE_SUCCESS_VOID(earlyHintPreloader->OpenChannel(
aTriggeringPrincipal, securityFlags, contentPolicyType, referrerInfo,
aCookieJarSettings));
DebugOnly<bool> result =
aOngoingEarlyHints->Add(*hashKey, earlyHintPreloader);
MOZ_ASSERT(result);
}
nsresult EarlyHintPreloader::OpenChannel(
nsIPrincipal* aTriggeringPrincipal, nsSecurityFlags aSecurityFlags,
nsContentPolicyType aContentPolicyType, nsIReferrerInfo* aReferrerInfo,
nsICookieJarSettings* aCookieJarSettings) {
MOZ_ASSERT(aContentPolicyType == nsContentPolicyType::TYPE_IMAGE);
nsresult rv =
NS_NewChannel(getter_AddRefs(mChannel), mURI, aTriggeringPrincipal,
aSecurityFlags, aContentPolicyType, aCookieJarSettings,
/* aPerformanceStorage */ nullptr,
/* aLoadGroup */ nullptr,
/* aCallbacks */ this, nsIRequest::LOAD_NORMAL);
NS_ENSURE_SUCCESS(rv, rv);
// configure HTTP specific stuff
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel);
if (!httpChannel) {
mChannel = nullptr;
return NS_ERROR_ABORT;
}
DebugOnly<nsresult> success = httpChannel->SetReferrerInfo(aReferrerInfo);
MOZ_ASSERT(NS_SUCCEEDED(success));
success = httpChannel->SetRequestHeader("X-Moz"_ns, "early hint"_ns, false);
MOZ_ASSERT(NS_SUCCEEDED(success));
return mChannel->AsyncOpen(this);
}
nsresult EarlyHintPreloader::CancelChannel(nsresult aStatus) {
// clear redirect channel in case this channel is cleared between the call of
// EarlyHintPreloader::AsyncOnChannelRedirect and
// EarlyHintPreloader::OnRedirectResult
mRedirectChannel = nullptr;
if (mChannel) {
mChannel->Cancel(aStatus);
mChannel = nullptr;
}
return NS_OK;
}
//-----------------------------------------------------------------------------
// EarlyHintPreloader::nsISupports
//-----------------------------------------------------------------------------
NS_IMPL_ISUPPORTS(EarlyHintPreloader, nsIRequestObserver, nsIStreamListener,
nsIChannelEventSink, nsIInterfaceRequestor,
nsIRedirectResultListener)
//-----------------------------------------------------------------------------
// EarlyHintPreloader::nsIStreamListener
//-----------------------------------------------------------------------------
NS_IMETHODIMP
EarlyHintPreloader::OnStartRequest(nsIRequest* aRequest) {
LOG(("EarlyHintPreloader::OnStartRequest\n"));
nsCOMPtr<nsICacheInfoChannel> cacheInfoChannel = do_QueryInterface(aRequest);
if (!cacheInfoChannel) {
return NS_ERROR_ABORT;
}
// no need to prefetch an asset that is already in the cache
bool fromCache;
if (NS_SUCCEEDED(cacheInfoChannel->IsFromCache(&fromCache)) && fromCache) {
LOG(("document is already in the cache; canceling prefetch\n"));
return NS_BINDING_ABORTED;
}
return NS_OK;
}
NS_IMETHODIMP
EarlyHintPreloader::OnDataAvailable(nsIRequest* aRequest,
nsIInputStream* aStream, uint64_t aOffset,
uint32_t aCount) {
uint32_t bytesRead = 0;
nsresult rv =
aStream->ReadSegments(NS_DiscardSegment, nullptr, aCount, &bytesRead);
LOG(("prefetched %u bytes [offset=%" PRIu64 "]\n", bytesRead, aOffset));
return rv;
}
NS_IMETHODIMP
EarlyHintPreloader::OnStopRequest(nsIRequest* aRequest, nsresult aStatus) {
LOG(("EarlyHintPreloader::OnStopRequest\n"));
mChannel = nullptr;
return NS_OK;
}
//-----------------------------------------------------------------------------
// EarlyHintPreloader::nsIChannelEventSink
//-----------------------------------------------------------------------------
NS_IMETHODIMP
EarlyHintPreloader::AsyncOnChannelRedirect(
nsIChannel* aOldChannel, nsIChannel* aNewChannel, uint32_t aFlags,
nsIAsyncVerifyRedirectCallback* callback) {
nsCOMPtr<nsIURI> newURI;
nsresult rv = NS_GetFinalChannelURI(aNewChannel, getter_AddRefs(newURI));
NS_ENSURE_SUCCESS(rv, rv);
rv = aNewChannel->GetURI(getter_AddRefs(newURI));
if (NS_FAILED(rv)) {
callback->OnRedirectVerifyCallback(rv);
return NS_OK;
}
// abort the request if redirecting to cross origin resource, the
// fromPrivateWindow is only read when reportError is enabled, so setting both
// to false is safe.
if (NS_FAILED(nsContentUtils::GetSecurityManager()->CheckSameOriginURI(
mURI, newURI, /* reportError */ false,
/* fromPrivateWindow */ false))) {
callback->OnRedirectVerifyCallback(NS_ERROR_ABORT);
return NS_OK;
}
// HTTP request headers are not automatically forwarded to the new channel.
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aNewChannel);
NS_ENSURE_STATE(httpChannel);
rv = httpChannel->SetRequestHeader("X-Moz"_ns, "early hint"_ns, false);
MOZ_ASSERT(NS_SUCCEEDED(rv));
// Assign to mChannel after we get notification about success of the
// redirect in OnRedirectResult.
mRedirectChannel = aNewChannel;
callback->OnRedirectVerifyCallback(NS_OK);
return NS_OK;
}
//-----------------------------------------------------------------------------
// EarlyHintPreloader::nsIRedirectResultListener
//-----------------------------------------------------------------------------
NS_IMETHODIMP
EarlyHintPreloader::OnRedirectResult(bool aProceeding) {
if (aProceeding && mRedirectChannel) {
mChannel = mRedirectChannel;
}
mRedirectChannel = nullptr;
return NS_OK;
}
//-----------------------------------------------------------------------------
// EarlyHintPreloader::nsIInterfaceRequestor
//-----------------------------------------------------------------------------
NS_IMETHODIMP
EarlyHintPreloader::GetInterface(const nsIID& aIID, void** aResult) {
if (aIID.Equals(NS_GET_IID(nsIChannelEventSink))) {
NS_ADDREF_THIS();
*aResult = static_cast<nsIChannelEventSink*>(this);
return NS_OK;
}
if (aIID.Equals(NS_GET_IID(nsIRedirectResultListener))) {
NS_ADDREF_THIS();
*aResult = static_cast<nsIRedirectResultListener*>(this);
return NS_OK;
}
return NS_ERROR_NO_INTERFACE;
}
} // namespace mozilla::net

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

@ -1,96 +0,0 @@
/* 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_EarlyHintPreloader_h
#define mozilla_net_EarlyHintPreloader_h
#include "mozilla/Maybe.h"
#include "mozilla/PreloadHashKey.h"
#include "nsIChannelEventSink.h"
#include "nsIInterfaceRequestor.h"
#include "nsIRedirectResultListener.h"
#include "nsIStreamListener.h"
#include "nsNetUtil.h"
#include "nsRefPtrHashtable.h"
class nsAttrValue;
class nsICookieJarSettings;
class nsIPrincipal;
class nsIReferrerInfo;
namespace mozilla::net {
class EarlyHintPreloader;
struct LinkHeader;
// class keeping track of all ongoing early hints
class OngoingEarlyHints final {
public:
NS_INLINE_DECL_REFCOUNTING(OngoingEarlyHints)
MOZ_DECLARE_REFCOUNTED_TYPENAME(OngoingEarlyHints)
OngoingEarlyHints() = default;
// returns whether a preload with that key already existed
bool Contains(const PreloadHashKey& aKey);
bool Add(const PreloadHashKey& aKey, RefPtr<EarlyHintPreloader> aPreloader);
void CancelAllOngoingPreloads();
private:
~OngoingEarlyHints() = default;
nsRefPtrHashtable<PreloadHashKey, EarlyHintPreloader> mOngoingPreloads;
};
class EarlyHintPreloader final : public nsIStreamListener,
public nsIChannelEventSink,
public nsIRedirectResultListener,
public nsIInterfaceRequestor {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIREQUESTOBSERVER
NS_DECL_NSISTREAMLISTENER
NS_DECL_NSICHANNELEVENTSINK
NS_DECL_NSIREDIRECTRESULTLISTENER
NS_DECL_NSIINTERFACEREQUESTOR
public:
// Create and insert a preload into OngoingEarlyHints if the same preload
// wasn't already issued and the LinkHeader can be parsed correctly.
static void MaybeCreateAndInsertPreload(
OngoingEarlyHints* aOngoingEarlyHints, const LinkHeader& aHeader,
nsIURI* aBaseURI, nsIPrincipal* aTriggeringPrincipal,
nsICookieJarSettings* aCookieJarSettings);
// Should be called by the preloader service when the preload is not needed
// after all, because the final response returns a non-2xx status code.
nsresult CancelChannel(nsresult aStatus);
private:
explicit EarlyHintPreloader(nsIURI* aURI);
~EarlyHintPreloader() = default;
static Maybe<PreloadHashKey> GenerateHashKey(ASDestination aAs, nsIURI* aURI,
nsIPrincipal* aPrincipal);
// call to start the preload
nsresult OpenChannel(nsIPrincipal* aTriggeringPrincipal,
nsSecurityFlags aSecurityFlags,
nsContentPolicyType aContentPolicyType,
nsIReferrerInfo* aReferrerInfo,
nsICookieJarSettings* aCookieJarSettings);
// keep opening uri to not preload cross origins on redirects for now
nsCOMPtr<nsIURI> mURI;
nsCOMPtr<nsIChannel> mChannel;
nsCOMPtr<nsIChannel> mRedirectChannel;
};
inline nsISupports* ToSupports(EarlyHintPreloader* aObj) {
return static_cast<nsIInterfaceRequestor*>(aObj);
}
} // namespace mozilla::net
#endif // mozilla_net_EarlyHintPreloader_h

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

@ -6,70 +6,26 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "EarlyHintsService.h"
#include "EarlyHintPreloader.h"
#include "mozilla/PreloadHashKey.h"
#include "mozilla/Telemetry.h"
#include "nsICookieJarSettings.h"
#include "nsNetUtil.h"
#include "nsString.h"
#include "mozilla/StaticPrefs_network.h"
#include "nsIPrincipal.h"
#include "nsILoadInfo.h"
namespace mozilla::net {
EarlyHintsService::EarlyHintsService()
: mOngoingEarlyHints(new OngoingEarlyHints()) {}
// implementing the destructor in the .cpp file to allow EarlyHintsService.h
// not to include EarlyHintPreloader.h, decoupling the two files and hopefully
// allow faster compile times
EarlyHintsService::~EarlyHintsService() = default;
void EarlyHintsService::EarlyHint(const nsACString& aLinkHeader,
nsIURI* aBaseURI, nsILoadInfo* aLoadInfo) {
void EarlyHintsService::EarlyHint(const nsACString& linkHeader) {
mEarlyHintsCount++;
if (!mFirstEarlyHint) {
mFirstEarlyHint.emplace(TimeStamp::NowLoRes());
}
if (!StaticPrefs::network_early_hints_enabled()) {
return;
}
nsCOMPtr<nsIPrincipal> triggeringPrincipal = aLoadInfo->TriggeringPrincipal();
nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
if (NS_FAILED(
aLoadInfo->GetCookieJarSettings(getter_AddRefs(cookieJarSettings)))) {
return;
}
// TODO: find out why LinkHeaderParser uses utf16 and check if it can be
// changed to utf8
auto linkHeaders = ParseLinkHeader(NS_ConvertUTF8toUTF16(aLinkHeader));
for (auto& linkHeader : linkHeaders) {
EarlyHintPreloader::MaybeCreateAndInsertPreload(
mOngoingEarlyHints, linkHeader, aBaseURI, triggeringPrincipal,
cookieJarSettings);
}
}
void EarlyHintsService::FinalResponse(uint32_t aResponseStatus) {
// We will collect telemetry mosly once for a document.
// In case of a reddirect this will be called multiple times.
CollectTelemetry(Some(aResponseStatus));
if (aResponseStatus >= 300) {
mOngoingEarlyHints->CancelAllOngoingPreloads();
mCanceled = true;
}
}
void EarlyHintsService::Cancel() {
if (!mCanceled) {
CollectTelemetry(Nothing());
mOngoingEarlyHints->CancelAllOngoingPreloads();
mCanceled = true;
}
}

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

@ -8,24 +8,17 @@
#ifndef mozilla_net_EarlyHintsService_h
#define mozilla_net_EarlyHintsService_h
#include "nsStringFwd.h"
#include "mozilla/Maybe.h"
#include "mozilla/TimeStamp.h"
#include "nsStringFwd.h"
#include "mozilla/RefPtr.h"
class nsILoadInfo;
class nsIURI;
namespace mozilla::net {
class OngoingEarlyHints;
class EarlyHintsService {
public:
EarlyHintsService();
~EarlyHintsService();
void EarlyHint(const nsACString& aLinkHeader, nsIURI* aBaseURI,
nsILoadInfo* aLoadInfo);
EarlyHintsService() = default;
~EarlyHintsService() = default;
void EarlyHint(const nsACString& linkHeader);
void FinalResponse(uint32_t aResponseStatus);
void Cancel();
@ -35,8 +28,6 @@ class EarlyHintsService {
Maybe<TimeStamp> mFirstEarlyHint;
uint32_t mEarlyHintsCount{0};
bool mCanceled{false};
RefPtr<OngoingEarlyHints> mOngoingEarlyHints;
};
} // namespace mozilla::net

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

@ -50,7 +50,6 @@ EXPORTS.mozilla.net += [
"ClassifierDummyChannelChild.h",
"ClassifierDummyChannelParent.h",
"ClassOfService.h",
"EarlyHintPreloader.h",
"EarlyHintsService.h",
"HttpAuthUtils.h",
"HttpBackgroundChannelChild.h",
@ -102,7 +101,6 @@ UNIFIED_SOURCES += [
"ConnectionEntry.cpp",
"ConnectionHandle.cpp",
"DnsAndConnectSocket.cpp",
"EarlyHintPreloader.cpp",
"EarlyHintsService.cpp",
"Http2Compression.cpp",
"Http2ConnectTransaction.cpp",

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

@ -1976,7 +1976,7 @@ nsresult nsHttpTransaction::ParseLineSegment(char* segment, uint32_t len) {
mResponseHead->Reset();
return NS_OK;
}
if (!mConnection->IsProxyConnectInProgress()) {
{
MutexAutoLock lock(mLock);
mEarlyHintObserver = nullptr;
}

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

@ -1,6 +1,26 @@
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<img src="http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs?138a85be-c7f1-4916-a6ef-c11c95d1cc4e" width="100px">
<script class="testbody" type="text/javascript">
function checkNumberOfLoads(shouldBe) {
var numDownloads = 0;
window.performance.getEntriesByName("http://example.com/browser/netwerk/test/browser/square.png").forEach(entry => {
if (entry.transferSize > 0) {
numDownloads++;
}
});
window.parent.ok(numDownloads == shouldBe, "The number of downloads of square.png is not correct");
};
var img = document.createElement("img");
img.src = "http://example.com/browser/netwerk/test/browser/square.png";
img.addEventListener("load",() => {
checkNumberOfLoads(1);
window.parent.iframeTestCompleted();
});
document.body.appendChild(img);
</script>
</body>
</html>

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

@ -1,2 +1,2 @@
HTTP 103 Too Early
Link: <http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs?138a85be-c7f1-4916-a6ef-c11c95d1cc4e>; rel=preload; as=image
Link: <http://example.com/browser/netwerk/test/browser/square.png>; rel=preload; as=image

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

@ -1,2 +1,2 @@
HTTP 103 Early Hints
Link: <http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs>; rel=preload; as=image
Link: <http://example.com/browser/netwerk/test/browser/square.png>; rel=preload; as=image

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

@ -1,6 +0,0 @@
<!DOCTYPE html>
<html>
<body>
<img src="http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs?1ac2a5e1-90c7-4171-b0f0-676f7d899af3" width="100px">
</body>
</html>

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

@ -1,2 +0,0 @@
Cache-Control: no-cache
Content-Security-Policy: img-src 'none'

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

@ -1,2 +0,0 @@
HTTP 103 Too Early
Link: <http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs?1ac2a5e1-90c7-4171-b0f0-676f7d899af3>; rel=preload; as=image

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

@ -1,6 +0,0 @@
<!DOCTYPE html>
<html>
<body>
<iframe src="/browser/netwerk/test/browser/early_hint_main_html.sjs?early_hint_pixel.sjs=5ecccd01-dd3f-4bbd-bd3e-0491d7dd78a1" width="100px">
</body>
</html>

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

@ -1 +0,0 @@
Cache-Control: no-cache

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

@ -4,11 +4,6 @@ support-files =
ioactivity.html
redirect.sjs
auth_post.sjs
early_hint_main_html.sjs
early_hint_pixel_count.sjs
early_hint_redirect.sjs
early_hint_pixel.sjs
early_hint_error.sjs
post.html
res.css
res.css^headers^
@ -36,19 +31,15 @@ support-files =
res_img_for_unknown_decoder^headers^
res_object.html
res_sub_document.html
square.png
103_preload.html
103_preload.html^headers^
103_preload.html^informationalResponse^
103_preload.html^headers^
no_103_preload.html
no_103_preload.html^headers^
103_preload_and_404.html^informationalResponse^
103_preload_and_404.html^headers^
103_preload_and_404.html
103_preload_iframe.html
103_preload_iframe.html^headers^
103_preload_csp_imgsrc_none.html
103_preload_csp_imgsrc_none.html^headers^
103_preload_csp_imgsrc_none.html^informationalResponse^
[browser_about_cache.js]
[browser_bug1535877.js]
@ -78,6 +69,3 @@ support-files =
[browser_103_telemetry.js]
skip-if =
os == 'linux' && bits == 64 && !debug # Bug 1744028 and Bug 1746324
[browser_103_preload.js]
skip-if =
os == 'linux' && bits == 64 && !debug # Bug 1744028 and Bug 1746324

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

@ -1,480 +0,0 @@
"use strict";
const { TelemetryTestUtils } = ChromeUtils.import(
"resource://testing-common/TelemetryTestUtils.jsm"
);
Services.prefs.setCharPref(
"dom.securecontext.allowlist",
"example.com,example.net"
);
Services.prefs.setBoolPref("network.early-hints.enabled", true);
async function test_hint_preload(
testName,
requestFrom,
imgUrl,
expectedRequestCount,
uuid = undefined
) {
// generate a uuid if none were passed
if (uuid == undefined) {
uuid = Services.uuid.generateUUID();
}
await test_hint_preload_internal(
testName,
requestFrom,
[[imgUrl, uuid.toString()]],
expectedRequestCount
);
}
// - testName is just there to be printed during Asserts when failing
// - the baseUrl can't have query strings, because they are currently used to pass
// the early hint the server responds with
// - urls are in the form [[url1, uuid1], ...]. The uuids are there to make each preload
// unique and not available in the cache from other test cases
// - expectedRequestCount is the sum of all requested objects { normal: count, hinted: count }
async function test_hint_preload_internal(
testName,
requestFrom,
imgUrls,
expectedRequestCount
) {
// reset the count
let headers = new Headers();
headers.append("X-Early-Hint-Count-Start", "");
await fetch(
"http://example.com/browser/netwerk/test/browser/early_hint_pixel_count.sjs",
{ headers }
);
// TODO: consider using http headers instead of query strings to pass the early hints
// to allow the baseUrl
let requestUrl =
requestFrom +
"/browser/netwerk/test/browser/early_hint_main_html.sjs?" +
new URLSearchParams(imgUrls).toString(); // encode the hinted images as query string
await BrowserTestUtils.withNewTab(
{
gBrowser,
url: requestUrl,
waitForLoad: true,
},
async function() {}
);
let gotRequestCount = await fetch(
"http://example.com/browser/netwerk/test/browser/early_hint_pixel_count.sjs"
).then(response => response.json());
await Assert.deepEqual(
gotRequestCount,
expectedRequestCount,
testName + ": Unexpected amount of requests made"
);
}
// TODO testing:
// * Abort main document load while early hint is still loading -> early hint should be aborted
// two early hint responses
add_task(async function test_103_two_preload_header() {
await test_hint_preload_internal(
"103_two_preload_header",
"http://example.com",
[
[
"http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs",
Services.uuid.generateUUID().toString(),
],
["", "new_response"], // empty string to indicate new early hint response
[
"http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs",
Services.uuid.generateUUID().toString(),
],
],
{ hinted: 2, normal: 0 }
);
});
// two link header in one early hint response
add_task(async function test_103_two_preload_header() {
await test_hint_preload_internal(
"103_two_preload_header",
"http://example.com",
[
[
"http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs",
Services.uuid.generateUUID().toString(),
],
["", ""], // empty string to indicate new early hint response
[
"http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs",
Services.uuid.generateUUID().toString(),
],
],
{ hinted: 2, normal: 0 }
);
});
// two links in one early hint link header
add_task(async function test_103_two_preload_header() {
await test_hint_preload_internal(
"103_two_preload_header",
"http://example.com",
[
[
"http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs",
Services.uuid.generateUUID().toString(),
],
[
"http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs",
Services.uuid.generateUUID().toString(),
],
],
{ hinted: 2, normal: 0 }
);
});
// Preload twice same origin in secure context
add_task(async function test_103_preload_twice() {
// pass two times the same uuid so that on the second request, the response is
// already in the cache
let uuid = Services.uuid.generateUUID();
await test_hint_preload(
"test_103_preload",
"http://example.com",
"http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs",
{ hinted: 1, normal: 0 },
uuid
);
await test_hint_preload(
"test_103_preload",
"http://example.com",
"http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs",
{ hinted: 0, normal: 0 },
uuid
);
});
// Test that with config option disabled, no early hint requests are made
add_task(async function test_103_preload() {
Services.prefs.setBoolPref("network.early-hints.enabled", false);
await test_hint_preload(
"test_103_preload",
"http://example.com",
"http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs",
{ hinted: 0, normal: 1 }
);
Services.prefs.setBoolPref("network.early-hints.enabled", true);
});
// Preload with same origin in secure context with mochitest http proxy
add_task(async function test_103_preload_https() {
await test_hint_preload(
"test_103_preload_https",
"https://example.org",
"/browser/netwerk/test/browser/early_hint_pixel.sjs",
{ hinted: 1, normal: 0 }
);
});
// Preload with same origin in secure context
add_task(async function test_103_preload() {
await test_hint_preload(
"test_103_preload",
"http://example.com",
"http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs",
{ hinted: 1, normal: 0 }
);
});
// Cross origin preload in secure context
add_task(async function test_103_preload_cor() {
await test_hint_preload(
"test_103_preload_cor",
"http://example.com",
"http://example.net/browser/netwerk/test/browser/early_hint_pixel.sjs",
{ hinted: 0, normal: 1 }
);
});
// Cross origin preload in insecure context
add_task(async function test_103_preload_insecure_cor() {
await test_hint_preload(
"test_103_preload_insecure_cor",
"http://example.com",
"http://mochi.test:8888/browser/netwerk/test/browser/early_hint_pixel.sjs",
{ hinted: 0, normal: 1 }
);
});
// Same origin request with relative url
add_task(async function test_103_relative_preload() {
await test_hint_preload(
"test_103_relative_preload",
"http://example.com",
"/browser/netwerk/test/browser/early_hint_pixel.sjs",
{ hinted: 1, normal: 0 }
);
});
// Early hint from insecure context
add_task(async function test_103_insecure_preload() {
await test_hint_preload(
"test_103_insecure_preload",
"http://mochi.test:8888",
"/browser/netwerk/test/browser/early_hint_pixel.sjs",
{ hinted: 0, normal: 1 }
);
});
// Early hint to redirect to same origin in secure context
add_task(async function test_103_redirect_same_origin() {
await test_hint_preload(
"test_103_redirect_same_origin",
"http://example.com",
"http://example.com/browser/netwerk/test/browser/early_hint_redirect.sjs?http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs",
{ hinted: 2, normal: 0 } // successful preload of redirect and resulting image
);
});
// Early hint to redirect to cross origin in secure context
add_task(async function test_103_redirect_cross_origin() {
await test_hint_preload(
"test_103_redirect_cross_origin",
"http://example.com",
"http://example.com/browser/netwerk/test/browser/early_hint_redirect.sjs?http://example.net/browser/netwerk/test/browser/early_hint_pixel.sjs",
{ hinted: 1, normal: 1 } // successful load of redirect in preload, but image loaded via normal load
);
});
// Early hint to redirect to cross origin in insecure context
add_task(async function test_103_redirect_insecure_cross_origin() {
await test_hint_preload(
"test_103_redirect_insecure_cross_origin",
"http://example.com",
"http://example.com/browser/netwerk/test/browser/early_hint_redirect.sjs?http://mochi.test:8888/browser/netwerk/test/browser/early_hint_pixel.sjs",
{ hinted: 1, normal: 1 }
);
});
// Cross origin preload from secure context to insecure context on same domain
add_task(async function test_103_preload_mixed_content() {
await test_hint_preload(
"test_103_preload_mixed_content",
"https://example.org",
"http://example.org/browser/netwerk/test/browser/early_hint_pixel.sjs",
{ hinted: 0, normal: 1 }
);
});
// Cross origin preload from secure context to redirected insecure context on same domain
add_task(async function test_103_preload_redirect_mixed_content() {
await test_hint_preload(
"test_103_preload_redirect_mixed_content",
"https://example.org",
"https://example.org/browser/netwerk/test/browser/early_hint_redirect.sjs?http://example.org/browser/netwerk/test/browser/early_hint_pixel.sjs",
{ hinted: 1, normal: 1 }
);
});
// Relative url, correct file for requested uri
add_task(async function test_103_preload_only_file() {
await test_hint_preload(
"test_103_preload_only_file",
"http://example.com",
"early_hint_pixel.sjs",
{ hinted: 1, normal: 0 }
);
});
// csp header with "img-src: 'none'" only on main html response, don't show the image on the page
add_task(async function test_preload_csp_imgsrc_none() {
// reset the count
let headers = new Headers();
headers.append("X-Early-Hint-Count-Start", "");
await fetch(
"http://example.com/browser/netwerk/test/browser/early_hint_pixel_count.sjs",
{ headers }
);
let requestUrl =
"http://example.com/browser/netwerk/test/browser/103_preload_csp_imgsrc_none.html";
await BrowserTestUtils.withNewTab(
{
gBrowser,
url: requestUrl,
waitForLoad: true,
},
async function(browser) {
let noImgLoaded = await SpecialPowers.spawn(browser, [], function() {
let loadInfo = content.performance.getEntriesByName(
"http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs?1ac2a5e1-90c7-4171-b0f0-676f7d899af3"
);
return loadInfo.every(entry => entry.decodedBodySize === 0);
});
await Assert.ok(
noImgLoaded,
"test_preload_csp_imgsrc_none: Image dislpayed unexpectedly"
);
}
);
let gotRequestCount = await fetch(
"http://example.com/browser/netwerk/test/browser/early_hint_pixel_count.sjs"
).then(response => response.json());
await Assert.deepEqual(
gotRequestCount,
{ hinted: 1, normal: 0 },
"test_preload_csp_imgsrc_none: Unexpected amount of requests made"
);
});
// 400 Bad Request
add_task(async function test_103_error_400() {
await test_hint_preload(
"test_103_error_400",
"http://example.com",
"http://example.com/browser/netwerk/test/browser/early_hint_error.sjs?400",
{ hinted: 1, normal: 1 }
);
});
// 401 Unauthorized
add_task(async function test_103_error_401() {
await test_hint_preload(
"test_103_error_401",
"http://example.com",
"http://example.com/browser/netwerk/test/browser/early_hint_error.sjs?401",
{ hinted: 1, normal: 1 }
);
});
// 403 Forbidden
add_task(async function test_103_error_403() {
await test_hint_preload(
"test_103_error_403",
"http://example.com",
"http://example.com/browser/netwerk/test/browser/early_hint_error.sjs?403",
{ hinted: 1, normal: 1 }
);
});
// 404 Not Found
add_task(async function test_103_error_404() {
await test_hint_preload(
"test_103_error_404",
"http://example.com",
"http://example.com/browser/netwerk/test/browser/early_hint_error.sjs?404",
{ hinted: 1, normal: 1 }
);
});
// 408 Request Timeout
add_task(async function test_103_error_408() {
await test_hint_preload(
"test_103_error_408",
"http://example.com",
"http://example.com/browser/netwerk/test/browser/early_hint_error.sjs?408",
{ hinted: 1, normal: 1 }
);
});
// 410 Gone
add_task(async function test_103_error_410() {
await test_hint_preload(
"test_103_error_410",
"http://example.com",
"http://example.com/browser/netwerk/test/browser/early_hint_error.sjs?410",
{ hinted: 1, normal: 0 }
);
});
// 429 Too Many Requests
add_task(async function test_103_error_429() {
await test_hint_preload(
"test_103_error_429",
"http://example.com",
"http://example.com/browser/netwerk/test/browser/early_hint_error.sjs?429",
{ hinted: 1, normal: 1 }
);
});
// 500 Internal Server Error
add_task(async function test_103_error_500() {
await test_hint_preload(
"test_103_error_500",
"http://example.com",
"http://example.com/browser/netwerk/test/browser/early_hint_error.sjs?500",
{ hinted: 1, normal: 1 }
);
});
// 502 Bad Gateway
add_task(async function test_103_error_502() {
await test_hint_preload(
"test_103_error_502",
"http://example.com",
"http://example.com/browser/netwerk/test/browser/early_hint_error.sjs?502",
{ hinted: 1, normal: 1 }
);
});
// 503 Service Unavailable
add_task(async function test_103_error_503() {
await test_hint_preload(
"test_103_error_503",
"http://example.com",
"http://example.com/browser/netwerk/test/browser/early_hint_error.sjs?503",
{ hinted: 1, normal: 1 }
);
});
// 504 Gateway Timeout
add_task(async function test_103_error_504() {
await test_hint_preload(
"test_103_error_504",
"http://example.com",
"http://example.com/browser/netwerk/test/browser/early_hint_error.sjs?504",
{ hinted: 1, normal: 1 }
);
});
// Test that preloads in iframes don't get triggered
add_task(async function test_103_iframe() {
// reset the count
let headers = new Headers();
headers.append("X-Early-Hint-Count-Start", "");
await fetch(
"http://example.com/browser/netwerk/test/browser/early_hint_pixel_count.sjs",
{ headers }
);
let iframeUri =
"http://example.com/browser/netwerk/test/browser/103_preload_iframe.html";
await BrowserTestUtils.withNewTab(
{
gBrowser,
url: iframeUri,
waitForLoad: true,
},
async function() {}
);
let gotRequestCount = await fetch(
"http://example.com/browser/netwerk/test/browser/early_hint_pixel_count.sjs"
).then(response => response.json());
await Assert.deepEqual(
gotRequestCount,
{ hinted: 0, normal: 1 },
"test_103_iframe: Unexpected amount of requests made"
);
});

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

@ -1,37 +0,0 @@
"use strict";
Cu.importGlobalProperties(["URLSearchParams"]);
function handleRequest(request, response) {
response.setStatusLine(
request.httpVersion,
parseInt(request.queryString),
"Dynamic error"
);
response.setHeader("Content-Type", "image/png", false);
response.setHeader("Cache-Control", "max-age=604800", false);
// count requests
let image;
let count = JSON.parse(getSharedState("earlyHintCount"));
if (
request.hasHeader("X-Moz") &&
request.getHeader("X-Moz") === "early hint"
) {
count.hinted += 1;
// set to green/black horizontal stripes (71 bytes)
image = atob(
"iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAADklEQVQIW2OU+i/FAAcADoABNV8X" +
"GBMAAAAASUVORK5CYII="
);
} else {
count.normal += 1;
// set to purple/white checkered pattern (76 bytes)
image = atob(
"iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAAE0lEQVQIW2P4//+/N8MkBiAGsgA1" +
"bAe1SzDY8gAAAABJRU5ErkJggg=="
);
}
setSharedState("earlyHintCount", JSON.stringify(count));
response.write(image);
}

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

@ -1,62 +0,0 @@
"use strict";
function handleRequest(request, response) {
Cu.importGlobalProperties(["URLSearchParams"]);
// write to raw socket
response.seizePower();
let qs = new URLSearchParams(request.queryString);
let imgs = [];
let new_hint = true;
let new_header = true;
for (const [imgUrl, uuid] of qs.entries()) {
if (new_hint) {
// we need to write a new header
new_hint = false;
response.write("HTTP/1.1 103 Early Hint\r\n");
}
if (imgUrl.length == 0) {
// next hint in new early hint response when empty string is passed
new_header = true;
if (uuid === "new_response") {
new_hint = true;
response.write("\r\n");
}
response.write("\r\n");
} else {
// either append link in new header or in same header
if (new_header) {
new_header = false;
response.write("Link: ");
} else {
response.write(", ");
}
// add query string to make request unique this has the drawback that
// the preloaded image can't accept query strings on it's own / or has
// to strip the appended "?uuid" from the query string before parsing
imgs.push(`<img src="${imgUrl}?${uuid}" width="100px">`);
response.write(`<${imgUrl}?${uuid}>; rel=preload; as=image`);
}
}
if (!new_hint) {
// add separator to main document
response.write("\r\n\r\n");
}
let body = `<!DOCTYPE html>
<html>
<body>
${imgs.join("\n")}
</body>
</html>`;
// main document response
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();
}

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

@ -1,30 +0,0 @@
"use strict";
function handleRequest(request, response) {
response.setHeader("Content-Type", "image/png", false);
response.setHeader("Cache-Control", "max-age=604800", false);
let count = JSON.parse(getSharedState("earlyHintCount"));
let image;
// send different sized images depending whether this is an early hint request
if (
request.hasHeader("X-Moz") &&
request.getHeader("X-Moz") === "early hint"
) {
count.hinted += 1;
// set to green/black horizontal stripes (71 bytes)
image = atob(
"iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAADklEQVQIW2OU+i/FAAcADoABNV8X" +
"GBMAAAAASUVORK5CYII="
);
} else {
count.normal += 1;
// set to purple/white checkered pattern (76 bytes)
image = atob(
"iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAAE0lEQVQIW2P4//+/N8MkBiAGsgA1" +
"bAe1SzDY8gAAAABJRU5ErkJggg=="
);
}
setSharedState("earlyHintCount", JSON.stringify(count));
response.write(image);
}

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

@ -1,9 +0,0 @@
"use strict";
function handleRequest(request, response) {
if (request.hasHeader("X-Early-Hint-Count-Start")) {
setSharedState("earlyHintCount", JSON.stringify({ hinted: 0, normal: 0 }));
}
response.setHeader("Content-Type", "application/json", false);
response.write(getSharedState("earlyHintCount"));
}

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

@ -1,21 +0,0 @@
"use strict";
function handleRequest(request, response) {
// increase count
let count = JSON.parse(getSharedState("earlyHintCount"));
if (
request.hasHeader("X-Moz") &&
request.getHeader("X-Moz") === "early hint"
) {
count.hinted += 1;
} else {
count.normal += 1;
}
setSharedState("earlyHintCount", JSON.stringify(count));
// respond with redirect
response.setStatusLine(request.httpVersion, 301, "Moved Permanently");
let location = request.queryString;
response.setHeader("Location", location, false);
response.write("Hello world!");
}

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

@ -1,6 +1,26 @@
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<img src="http://example.com/browser/netwerk/test/browser/early_hint_pixel.sjs" width="100px">
<script class="testbody" type="text/javascript">
function checkNumberOfLoads(shouldBe) {
var numDownloads = 0;
window.performance.getEntriesByName("http://example.com/browser/netwerk/test/browser/square.png").forEach(entry => {
if (entry.transferSize > 0) {
numDownloads++;
}
});
window.parent.ok(numDownloads == shouldBe, "The number of downloads of square.png is not correct");
};
var img = document.createElement("img");
img.src = "http://example.com/browser/netwerk/test/browser/square.png";
img.addEventListener("load",() => {
checkNumberOfLoads(1);
window.parent.iframeTestCompleted();
});
document.body.appendChild(img);
</script>
</body>
</html>