Bug 1742438 - Prep Part 9: Encode URIs on worker script loader creation; r=asuth

This step is not strictly necessary, and if this is too ugly we can think of something else. The
reason for this change is that ScriptLoadRequests are initialized by a URI, and the owner of these
objects will be the worker thread. However, the current strategy requires that we create the URI
only on the main thread. We always have this information however, when we create the loader, so
there isn't any reason to defer this step until we bounce back into the main thread.

This is another spot where we can reduce reliance on the main thread, which is an eventual goal, so
it seems like this change is an improvement even outside of the goal of moving to ScriptLoadRequests
as a representation.

An alternative approach here would be to initialized the nsIURI ahead of time, and pass it with the
script url to the initialization of the WorkerScriptLoader. However, this isn't ideal as _ideally_
we would remove the text url all together, but this is necessary for errors. We can do this if we
handle workers and main thread differently (and maybe it is worthwhile) as only the main thread
needs encoding information.

Differential Revision: https://phabricator.services.mozilla.com/D146170
This commit is contained in:
Yulia Startsev
2022-07-14 17:07:23 +00:00
parent 8c005ccfc7
commit 80d116b0fd
5 changed files with 80 additions and 40 deletions

View File

@@ -51,6 +51,7 @@
#include "mozilla/AntiTrackingUtils.h"
#include "mozilla/ArrayAlgorithm.h"
#include "mozilla/Assertions.h"
#include "mozilla/Encoding.h"
#include "mozilla/LoadContext.h"
#include "mozilla/Maybe.h"
#include "mozilla/ipc/BackgroundUtils.h"
@@ -82,14 +83,17 @@ namespace mozilla::dom::workerinternals {
namespace {
nsresult ConstructURI(const nsAString& aScriptURL, nsIURI* baseURI,
Document* parentDoc, bool aDefaultURIEncoding,
const mozilla::Encoding* aDocumentEncoding,
nsIURI** aResult) {
nsresult rv;
if (aDefaultURIEncoding) {
rv = NS_NewURI(aResult, aScriptURL, nullptr, baseURI);
// Only top level workers' main script use the document charset for the
// script uri encoding. Otherwise, default encoding (UTF-8) is applied.
if (aDocumentEncoding) {
nsAutoCString charset;
aDocumentEncoding->Name(charset);
rv = NS_NewURI(aResult, aScriptURL, charset.get(), baseURI);
} else {
rv = nsContentUtils::NewURIWithDocumentCharset(aResult, aScriptURL,
parentDoc, baseURI);
rv = NS_NewURI(aResult, aScriptURL, nullptr, baseURI);
}
if (NS_FAILED(rv)) {
@@ -232,7 +236,8 @@ nsresult ChannelFromScriptURL(
void LoadAllScripts(WorkerPrivate* aWorkerPrivate,
UniquePtr<SerializedStackHolder> aOriginStack,
const nsTArray<nsString>& aScriptURLs, bool aIsMainScript,
WorkerScriptType aWorkerScriptType, ErrorResult& aRv) {
WorkerScriptType aWorkerScriptType, ErrorResult& aRv,
const mozilla::Encoding* aDocumentEncoding = nullptr) {
aWorkerPrivate->AssertIsOnWorkerThread();
NS_ASSERTION(!aScriptURLs.IsEmpty(), "Bad arguments!");
@@ -262,8 +267,8 @@ void LoadAllScripts(WorkerPrivate* aWorkerPrivate,
RefPtr<loader::WorkerScriptLoader> loader = new loader::WorkerScriptLoader(
aWorkerPrivate, std::move(aOriginStack), syncLoopTarget,
std::move(aLoadInfos), clientInfo, controller, aIsMainScript,
aWorkerScriptType, aRv);
std::move(aLoadInfos), aDocumentEncoding, clientInfo, controller,
aIsMainScript, aWorkerScriptType, aRv);
NS_ASSERTION(aLoadInfos.IsEmpty(), "Should have swapped!");
@@ -330,8 +335,7 @@ class ChannelGetterRunnable final : public WorkerMainThreadRunnable {
// Nested workers use default uri encoding.
nsCOMPtr<nsIURI> url;
mResult =
ConstructURI(mScriptURL, baseURI, parentDoc, true, getter_AddRefs(url));
mResult = ConstructURI(mScriptURL, baseURI, nullptr, getter_AddRefs(url));
NS_ENSURE_SUCCESS(mResult, true);
Maybe<ClientInfo> clientInfo;
@@ -456,6 +460,7 @@ WorkerScriptLoader::WorkerScriptLoader(
WorkerPrivate* aWorkerPrivate,
UniquePtr<SerializedStackHolder> aOriginStack,
nsIEventTarget* aSyncLoopTarget, nsTArray<ScriptLoadInfo> aLoadInfos,
const mozilla::Encoding* aDocumentEncoding,
const Maybe<ClientInfo>& aClientInfo,
const Maybe<ServiceWorkerDescriptor>& aController, bool aIsMainScript,
WorkerScriptType aWorkerScriptType, ErrorResult& aRv)
@@ -474,6 +479,16 @@ WorkerScriptLoader::WorkerScriptLoader(
MOZ_ASSERT_IF(aIsMainScript, mLoadInfos.Length() == 1);
for (ScriptLoadInfo& loadInfo : mLoadInfos) {
// Only top level workers' main script use the document charset for the
// script uri encoding. Otherwise, default encoding (UTF-8) is applied.
MOZ_ASSERT_IF(bool(aDocumentEncoding),
aIsMainScript && !aWorkerPrivate->GetParent());
nsresult rv = ConstructURI(loadInfo.mURL, GetBaseURI(), aDocumentEncoding,
getter_AddRefs(loadInfo.mURI));
if (NS_WARN_IF(NS_FAILED(rv))) {
loadInfo.mLoadResult = rv;
}
// Build up our list of references here. This will be removed once
// we move to ScriptLoadRequestList.
mLoadingRequests.AppendElement(&loadInfo);
@@ -481,6 +496,7 @@ WorkerScriptLoader::WorkerScriptLoader(
}
bool WorkerScriptLoader::DispatchLoadScripts() {
mWorkerPrivate->AssertIsOnWorkerThread();
RefPtr<ScriptLoaderRunnable> runnable = new ScriptLoaderRunnable(this);
if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
@@ -686,6 +702,11 @@ nsresult WorkerScriptLoader::LoadScript(ScriptLoadInfo* aLoadInfo) {
AssertIsOnMainThread();
MOZ_ASSERT_IF(IsMainWorkerScript(), !IsDebuggerScript());
// The URL passed to us for loading was invalid, stop loading at this point.
if (aLoadInfo->mLoadResult != NS_ERROR_NOT_INITIALIZED) {
return aLoadInfo->mLoadResult;
}
WorkerPrivate* parentWorker = mWorkerPrivate->GetParent();
// For JavaScript debugging, the devtools server must run on the same
@@ -703,9 +724,6 @@ nsresult WorkerScriptLoader::LoadScript(ScriptLoadInfo* aLoadInfo) {
NS_ENSURE_TRUE(NS_LoadGroupMatchesPrincipal(loadGroup, principal),
NS_ERROR_FAILURE);
// Figure out our base URI.
nsCOMPtr<nsIURI> baseURI = GetBaseURI();
// May be null.
nsCOMPtr<Document> parentDoc = mWorkerPrivate->GetDocument();
@@ -747,16 +765,6 @@ nsresult WorkerScriptLoader::LoadScript(ScriptLoadInfo* aLoadInfo) {
}
if (!channel) {
// Only top level workers' main script use the document charset for the
// script uri encoding. Otherwise, default encoding (UTF-8) is applied.
bool useDefaultEncoding = !(!parentWorker && IsMainWorkerScript());
nsCOMPtr<nsIURI> url;
rv = ConstructURI(aLoadInfo->mURL, baseURI, parentDoc, useDefaultEncoding,
getter_AddRefs(url));
if (NS_FAILED(rv)) {
return rv;
}
nsCOMPtr<nsIReferrerInfo> referrerInfo =
ReferrerInfo::CreateForFetch(principal, nullptr);
if (parentWorker && !IsMainWorkerScript()) {
@@ -765,12 +773,12 @@ nsresult WorkerScriptLoader::LoadScript(ScriptLoadInfo* aLoadInfo) {
->CloneWithNewPolicy(parentWorker->GetReferrerPolicy());
}
rv = ChannelFromScriptURL(principal, parentDoc, mWorkerPrivate, loadGroup,
ios, secMan, url, mClientInfo, mController,
IsMainWorkerScript(), mWorkerScriptType,
mWorkerPrivate->ContentPolicyType(), loadFlags,
mWorkerPrivate->CookieJarSettings(), referrerInfo,
getter_AddRefs(channel));
rv = ChannelFromScriptURL(
principal, parentDoc, mWorkerPrivate, loadGroup, ios, secMan,
aLoadInfo->mURI, mClientInfo, mController, IsMainWorkerScript(),
mWorkerScriptType, mWorkerPrivate->ContentPolicyType(), loadFlags,
mWorkerPrivate->CookieJarSettings(), referrerInfo,
getter_AddRefs(channel));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@@ -1183,13 +1191,14 @@ void ReportLoadError(ErrorResult& aRv, nsresult aLoadResult,
void LoadMainScript(WorkerPrivate* aWorkerPrivate,
UniquePtr<SerializedStackHolder> aOriginStack,
const nsAString& aScriptURL,
WorkerScriptType aWorkerScriptType, ErrorResult& aRv) {
WorkerScriptType aWorkerScriptType, ErrorResult& aRv,
const mozilla::Encoding* aDocumentEncoding) {
nsTArray<nsString> scriptURLs;
scriptURLs.AppendElement(aScriptURL);
LoadAllScripts(aWorkerPrivate, std::move(aOriginStack), scriptURLs, true,
aWorkerScriptType, aRv);
aWorkerScriptType, aRv, aDocumentEncoding);
}
void Load(WorkerPrivate* aWorkerPrivate,