diff --git a/browser/base/content/test/static/browser_all_files_referenced.js b/browser/base/content/test/static/browser_all_files_referenced.js index f51ac3637388..52f696eda551 100644 --- a/browser/base/content/test/static/browser_all_files_referenced.js +++ b/browser/base/content/test/static/browser_all_files_referenced.js @@ -430,7 +430,6 @@ var gChromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].getService( ); var gChromeMap = new Map(); var gOverrideMap = new Map(); -var gComponentsSet = new Set(); // In this map when the value is a Set of URLs, the file is referenced if any // of the files in the Set is referenced. @@ -505,8 +504,6 @@ function parseManifest(manifestUri) { } } else if (type == "resource") { trackResourcePrefix(argv[0]); - } else if (type == "component") { - gComponentsSet.add(argv[1]); } } }); @@ -647,6 +644,10 @@ function parseCodeFile(fileUri) { /["'`]chrome:\/\/[a-zA-Z0-9-]+\/(content|skin|locale)\/[^"'` ]*["'`]/g ); + if (!urls) { + urls = line.match(/["']moz-src:\/\/\/[^"']+["']/g); + } + if (!urls) { urls = line.match(/["']resource:\/\/[^"']+["']/g); if ( @@ -734,7 +735,10 @@ function parseCodeFile(fileUri) { if (!/\.(properties|js|jsm|mjs|json|css)$/.test(url)) { url += ".js"; } - if (url.startsWith("resource://")) { + if ( + url.startsWith("resource://") || + url.startsWith("moz-src:///") + ) { addCodeReference(url, fileUri); } else { // if we end up with a chrome:// url here, it's likely because @@ -784,13 +788,22 @@ function parseCodeFile(fileUri) { function convertToCodeURI(fileUri) { let baseUri = fileUri; let path = ""; - while (true) { + while (baseUri) { let slashPos = baseUri.lastIndexOf("/", baseUri.length - 2); if (slashPos <= 0) { // File not accessible from chrome protocol, try resource:// for (let res of gResourceMap) { if (fileUri.startsWith(res[1])) { - return fileUri.replace(res[1], "resource://" + res[0] + "/"); + let resourceUriString = fileUri.replace( + res[1], + `resource://${res[0]}/` + ); + // If inside moz-src, treat as moz-src url. + resourceUriString = resourceUriString.replace( + /^resource:\/\/gre\/moz-src\//, + "moz-src:///" + ); + return resourceUriString; } } // Give up and return the original URL. @@ -802,6 +815,7 @@ function convertToCodeURI(fileUri) { return gChromeMap.get(baseUri) + path; } } + throw new Error(`Unparsable URI: ${fileUri}`); } async function chromeFileExists(aURI) { @@ -849,6 +863,7 @@ function findChromeUrlsFromArray(array, prefix) { // Only keep strings that look like real chrome or resource urls. if ( /chrome:\/\/[a-zA-Z09-]+\/(content|skin|locale)\//.test(string) || + /moz-src:\/\/\/\w+/.test(string) || /resource:\/\/[a-zA-Z09-]*\/.*\.[a-z]+/.test(string) ) { gReferencesFromCode.set(string, null); @@ -862,10 +877,12 @@ add_task(async function checkAllTheFiles() { const libxul = await IOUtils.read(PathUtils.xulLibraryPath); findChromeUrlsFromArray(libxul, "chrome://"); findChromeUrlsFromArray(libxul, "resource://"); + findChromeUrlsFromArray(libxul, "moz-src:///"); // Handle NS_LITERAL_STRING. let uint16 = new Uint16Array(libxul.buffer); findChromeUrlsFromArray(uint16, "chrome://"); findChromeUrlsFromArray(uint16, "resource://"); + findChromeUrlsFromArray(uint16, "moz-src:///"); const kCodeExtensions = [ ".xml", @@ -954,6 +971,7 @@ add_task(async function checkAllTheFiles() { // the non-devtools paths: let devtoolsPrefixes = [ "chrome://devtools", + "moz-src:///devtools/", "resource://devtools/", "resource://devtools-shared-images/", "resource://devtools-highlighter-styles/", @@ -968,7 +986,9 @@ add_task(async function checkAllTheFiles() { for (let uri of uris) { uri = convertToCodeURI(uri.spec); if ( - (uri.startsWith("chrome://") || uri.startsWith("resource://")) && + (uri.startsWith("chrome://") || + uri.startsWith("resource://") || + uri.startsWith("moz-src:///")) && isDevtools == hasDevtoolsPrefix(uri) ) { chromeFiles.push(uri); @@ -1025,9 +1045,6 @@ add_task(async function checkAllTheFiles() { if (rv && f.startsWith("resource://app/")) { rv = isUnreferenced(f.replace("resource://app/", "resource:///")); } - if (rv && /^resource:\/\/(?:app|gre)\/components\/[^/]+\.js$/.test(f)) { - rv = !gComponentsSet.has(f.replace(/.*\//, "")); - } if (!rv) { foundReference = true; if (useAllowlist) { @@ -1108,7 +1125,9 @@ add_task(async function checkAllTheFiles() { } if ( - (file.startsWith("chrome://") || file.startsWith("resource://")) && + (file.startsWith("chrome://") || + file.startsWith("resource://") || + file.startsWith("moz-src:///")) && !(await chromeFileExists(file)) ) { // Ignore chrome prefixes that have been automatically expanded. diff --git a/docshell/base/BaseHistory.cpp b/docshell/base/BaseHistory.cpp index f6666292539f..b7a7fa557779 100644 --- a/docshell/base/BaseHistory.cpp +++ b/docshell/base/BaseHistory.cpp @@ -27,7 +27,8 @@ static constexpr nsLiteralCString kDisallowedSchemes[] = { "chrome"_ns, "data"_ns, "imap"_ns, "javascript"_ns, "mailbox"_ns, "news"_ns, "page-icon"_ns, "resource"_ns, "view-source"_ns, - "moz-extension"_ns, "moz-page-thumb"_ns, "x-moz-ews"_ns, + "moz-extension"_ns, "moz-page-thumb"_ns, "moz-src"_ns, + "x-moz-ews"_ns, }; bool BaseHistory::CanStore(nsIURI* aURI) { diff --git a/dom/security/nsCSPService.cpp b/dom/security/nsCSPService.cpp index 75e8ec19332e..7a1e6002a235 100644 --- a/dom/security/nsCSPService.cpp +++ b/dom/security/nsCSPService.cpp @@ -89,7 +89,7 @@ bool subjectToCSP(nsIURI* aURI, nsContentPolicyType aContentType) { if (aURI->SchemeIs("chrome") && !isImgOrStyleOrDTD) { return true; } - if (aURI->SchemeIs("moz-icon")) { + if (aURI->SchemeIs("moz-icon") || aURI->SchemeIs("moz-src")) { return true; } bool match; diff --git a/dom/security/nsContentSecurityUtils.cpp b/dom/security/nsContentSecurityUtils.cpp index b77e27d799ba..e09c50a8b9e8 100644 --- a/dom/security/nsContentSecurityUtils.cpp +++ b/dom/security/nsContentSecurityUtils.cpp @@ -1903,6 +1903,10 @@ bool nsContentSecurityUtils::ValidateScriptFilename(JSContext* cx, // If it's a resource:// url, allow it return true; } + if (StringBeginsWith(filename, "moz-src://"_ns)) { + // If it's a moz-src:// url, allow it + return true; + } if (StringBeginsWith(filename, "file://"_ns)) { // We will temporarily allow all file:// URIs through for now return true; diff --git a/js/loader/ScriptLoadRequest.cpp b/js/loader/ScriptLoadRequest.cpp index b2e2777730e0..eba7e9a2a4fd 100644 --- a/js/loader/ScriptLoadRequest.cpp +++ b/js/loader/ScriptLoadRequest.cpp @@ -226,7 +226,7 @@ void ScriptLoadRequest::MarkScriptForBytecodeEncoding(JSScript* aScript) { static bool IsInternalURIScheme(nsIURI* uri) { return uri->SchemeIs("moz-extension") || uri->SchemeIs("resource") || - uri->SchemeIs("chrome"); + uri->SchemeIs("moz-src") || uri->SchemeIs("chrome"); } void ScriptLoadRequest::SetBaseURLFromChannelAndOriginalURI( diff --git a/js/xpconnect/loader/mozJSModuleLoader.cpp b/js/xpconnect/loader/mozJSModuleLoader.cpp index 13f3b353ac1e..473554eebbf1 100644 --- a/js/xpconnect/loader/mozJSModuleLoader.cpp +++ b/js/xpconnect/loader/mozJSModuleLoader.cpp @@ -1039,7 +1039,8 @@ nsresult mozJSModuleLoader::GetModuleImportStack(const nsACString& aLocation, /* static */ bool mozJSModuleLoader::IsTrustedScheme(nsIURI* aURI) { - return aURI->SchemeIs("resource") || aURI->SchemeIs("chrome"); + return aURI->SchemeIs("resource") || aURI->SchemeIs("chrome") || + aURI->SchemeIs("moz-src"); } nsresult mozJSModuleLoader::ImportESModule( diff --git a/netwerk/base/nsIOService.cpp b/netwerk/base/nsIOService.cpp index 81d646f38f16..e5dc788b0a07 100644 --- a/netwerk/base/nsIOService.cpp +++ b/netwerk/base/nsIOService.cpp @@ -903,7 +903,7 @@ nsresult nsIOService::AsyncOnChannelRedirect( bool nsIOService::UsesExternalProtocolHandler(const nsACString& aScheme) { if (aScheme == "file"_ns || aScheme == "chrome"_ns || - aScheme == "resource"_ns) { + aScheme == "resource"_ns || aScheme == "moz-src"_ns) { // Don't allow file:, chrome: or resource: URIs to be handled with // nsExternalProtocolHandler, since internally we rely on being able to // use and read from these URIs. diff --git a/netwerk/base/nsNetUtil.cpp b/netwerk/base/nsNetUtil.cpp index 6c602cd5228b..4d0767a8eab0 100644 --- a/netwerk/base/nsNetUtil.cpp +++ b/netwerk/base/nsNetUtil.cpp @@ -102,6 +102,7 @@ #endif #include "nsAboutProtocolHandler.h" #include "nsResProtocolHandler.h" +#include "mozilla/net/MozSrcProtocolHandler.h" #include "mozilla/net/ExtensionProtocolHandler.h" #include "mozilla/net/PageThumbProtocolHandler.h" #include "mozilla/net/SFVService.h" @@ -1912,6 +1913,15 @@ nsresult NS_NewURI(nsIURI** aURI, const nsACString& aSpec, return handler->NewURI(aSpec, aCharset, aBaseURI, aURI); } + if (scheme.EqualsLiteral("moz-src")) { + RefPtr handler = + MozSrcProtocolHandler::GetSingleton(); + if (!handler) { + return NS_ERROR_NOT_AVAILABLE; + } + return handler->NewURI(aSpec, aCharset, aBaseURI, aURI); + } + if (scheme.EqualsLiteral("indexeddb") || scheme.EqualsLiteral("uuid")) { return NS_MutateURI(new nsStandardURL::Mutator()) .Apply(&nsIStandardURLMutator::Init, nsIStandardURL::URLTYPE_AUTHORITY, diff --git a/netwerk/base/nsStandardURL.cpp b/netwerk/base/nsStandardURL.cpp index ff9323639d34..b2778adf3610 100644 --- a/netwerk/base/nsStandardURL.cpp +++ b/netwerk/base/nsStandardURL.cpp @@ -579,6 +579,7 @@ nsresult nsStandardURL::BuildNormalizedSpec(const char* spec, nsDependentCSubstring tempHost(spec + mHost.mPos, mHost.mLen); nsresult rv; bool allowIp = !SegmentIs(spec, mScheme, "resource") && + !SegmentIs(spec, mScheme, "moz-src") && !SegmentIs(spec, mScheme, "chrome"); if (tempHost.First() == '[' && allowIp) { mCheckedIfHostA = true; diff --git a/netwerk/build/components.conf b/netwerk/build/components.conf index 4f5448176629..c2fdcc763eb5 100644 --- a/netwerk/build/components.conf +++ b/netwerk/build/components.conf @@ -466,6 +466,23 @@ Classes = [ ], }, }, + { + 'cid': '{4abd60aa-6b7d-4f3b-bf52-d7ce8ae6dd36}', + 'contract_ids': ['@mozilla.org/network/protocol;1?name=moz-src'], + 'singleton': True, + 'type': 'mozilla::net::MozSrcProtocolHandler', + 'headers': ['/netwerk/protocol/res/MozSrcProtocolHandler.h'], + 'constructor': 'mozilla::net::MozSrcProtocolHandler::GetSingleton', + 'protocol_config': { + 'scheme': 'moz-src', + 'flags': [ + 'URI_STD', + 'URI_IS_UI_RESOURCE', + 'URI_IS_LOCAL_RESOURCE', + 'URI_IS_POTENTIALLY_TRUSTWORTHY', + ], + }, + }, { 'cid': '{9c7ec5d1-23f9-11d5-aea8-8fcc0793e97f}', 'contract_ids': ['@mozilla.org/network/protocol;1?name=view-source'], diff --git a/netwerk/protocol/res/MozSrcProtocolHandler.cpp b/netwerk/protocol/res/MozSrcProtocolHandler.cpp new file mode 100644 index 000000000000..2ace95741cd0 --- /dev/null +++ b/netwerk/protocol/res/MozSrcProtocolHandler.cpp @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 "mozilla/ModuleUtils.h" +#include "mozilla/ClearOnShutdown.h" +#include "mozilla/Omnijar.h" + +#include "MozSrcProtocolHandler.h" + +#define MOZSRC_SCHEME "moz-src" + +namespace mozilla { +namespace net { + +NS_IMPL_QUERY_INTERFACE(MozSrcProtocolHandler, nsISubstitutingProtocolHandler, + nsIProtocolHandler, nsISupportsWeakReference) +NS_IMPL_ADDREF_INHERITED(MozSrcProtocolHandler, SubstitutingProtocolHandler) +NS_IMPL_RELEASE_INHERITED(MozSrcProtocolHandler, SubstitutingProtocolHandler) + +mozilla::StaticRefPtr MozSrcProtocolHandler::sSingleton; + +already_AddRefed MozSrcProtocolHandler::GetSingleton() { + if (!sSingleton) { + RefPtr handler = new MozSrcProtocolHandler(); + if (NS_WARN_IF(NS_FAILED(handler->Init()))) { + return nullptr; + } + sSingleton = handler; + ClearOnShutdown(&sSingleton); + } + return do_AddRef(sSingleton); +} + +MozSrcProtocolHandler::MozSrcProtocolHandler() + : SubstitutingProtocolHandler(MOZSRC_SCHEME) {} + +nsresult MozSrcProtocolHandler::Init() { + nsresult rv = mozilla::Omnijar::GetURIString(mozilla::Omnijar::GRE, mGREURI); + NS_ENSURE_SUCCESS(rv, rv); + + mGREURI.AppendLiteral(MOZSRC_SCHEME); + + return NS_OK; +} + +bool MozSrcProtocolHandler::ResolveSpecialCases(const nsACString& aHost, + const nsACString& aPath, + const nsACString& aPathname, + nsACString& aResult) { + aResult = mGREURI; + aResult.Append(aPathname); + return true; +} + +nsresult MozSrcProtocolHandler::GetSubstitutionInternal(const nsACString& aRoot, + nsIURI** aResult) { + nsAutoCString uri; + + if (!ResolveSpecialCases(aRoot, "/"_ns, "/"_ns, uri)) { + return NS_ERROR_NOT_AVAILABLE; + } + + return NS_NewURI(aResult, uri); +} + +} // namespace net +} // namespace mozilla diff --git a/netwerk/protocol/res/MozSrcProtocolHandler.h b/netwerk/protocol/res/MozSrcProtocolHandler.h new file mode 100644 index 000000000000..14845c7ef3aa --- /dev/null +++ b/netwerk/protocol/res/MozSrcProtocolHandler.h @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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 MozSrcProtocolHandler_h___ +#define MozSrcProtocolHandler_h___ + +#include "nsIProtocolHandler.h" +#include "nsISubstitutingProtocolHandler.h" +#include "SubstitutingProtocolHandler.h" + +namespace mozilla { +namespace net { + +class MozSrcProtocolHandler final : public nsISubstitutingProtocolHandler, + public SubstitutingProtocolHandler, + public nsSupportsWeakReference { + public: + NS_DECL_ISUPPORTS_INHERITED + NS_FORWARD_NSIPROTOCOLHANDLER(SubstitutingProtocolHandler::) + NS_FORWARD_NSISUBSTITUTINGPROTOCOLHANDLER(SubstitutingProtocolHandler::) + + static already_AddRefed GetSingleton(); + + MozSrcProtocolHandler(); + + protected: + ~MozSrcProtocolHandler() = default; + + [[nodiscard]] virtual bool ResolveSpecialCases(const nsACString& aHost, + const nsACString& aPath, + const nsACString& aPathname, + nsACString& aResult) override; + + [[nodiscard]] nsresult GetSubstitutionInternal(const nsACString& aRoot, + nsIURI** aResult) override; + + private: + static mozilla::StaticRefPtr sSingleton; + nsresult Init(); + + nsCString mGREURI; +}; + +} // namespace net +} // namespace mozilla + +#endif /* MozSrcProtocolHandler_h___ */ diff --git a/netwerk/protocol/res/moz.build b/netwerk/protocol/res/moz.build index 63407eebd8b3..e8d20f19a1b4 100644 --- a/netwerk/protocol/res/moz.build +++ b/netwerk/protocol/res/moz.build @@ -13,6 +13,7 @@ XPIDL_MODULE = "necko_res" EXPORTS.mozilla.net += [ "ExtensionProtocolHandler.h", + "MozSrcProtocolHandler.h", "PageThumbProtocolHandler.h", "RemoteStreamGetter.h", "SubstitutingJARURI.h", @@ -26,6 +27,7 @@ EXPORTS += [ UNIFIED_SOURCES += [ "ExtensionProtocolHandler.cpp", + "MozSrcProtocolHandler.cpp", "nsResProtocolHandler.cpp", "PageThumbProtocolHandler.cpp", "RemoteStreamGetter.cpp", diff --git a/python/mozbuild/mozpack/packager/formats.py b/python/mozbuild/mozpack/packager/formats.py index 49aa9eff8884..2926f98ce09c 100644 --- a/python/mozbuild/mozpack/packager/formats.py +++ b/python/mozbuild/mozpack/packager/formats.py @@ -345,6 +345,7 @@ class OmniJarSubFormatter(PiecemealFormatter): return True return path[0] in [ "modules", + "moz-src", "actors", "dictionaries", "hyphenation", diff --git a/startupcache/StartupCacheUtils.cpp b/startupcache/StartupCacheUtils.cpp index c8dcdd7f1173..84c919aa4ba1 100644 --- a/startupcache/StartupCacheUtils.cpp +++ b/startupcache/StartupCacheUtils.cpp @@ -7,7 +7,7 @@ #include "nsNetUtil.h" #include "nsIFileURL.h" #include "nsIJARURI.h" -#include "nsIResProtocolHandler.h" +#include "nsISubstitutingProtocolHandler.h" #include "nsIChromeRegistry.h" #include "nsStringStream.h" #include "StartupCacheUtils.h" @@ -136,17 +136,20 @@ static inline bool canonicalizeBase(nsAutoCString& spec, nsACString& out) { nsresult ResolveURI(nsIURI* in, nsIURI** out) { nsresult rv; + nsAutoCString scheme; + in->GetScheme(scheme); + // Resolve resource:// URIs. At the end of this if/else block, we // have both spec and uri variables identifying the same URI. - if (in->SchemeIs("resource")) { + if (scheme.EqualsLiteral("resource") || scheme.EqualsLiteral("moz-src")) { nsCOMPtr ioService = do_GetIOService(&rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr ph; - rv = ioService->GetProtocolHandler("resource", getter_AddRefs(ph)); + rv = ioService->GetProtocolHandler(scheme.get(), getter_AddRefs(ph)); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr irph(do_QueryInterface(ph, &rv)); + nsCOMPtr irph(do_QueryInterface(ph, &rv)); NS_ENSURE_SUCCESS(rv, rv); nsAutoCString spec; @@ -155,7 +158,7 @@ nsresult ResolveURI(nsIURI* in, nsIURI** out) { return ioService->NewURI(spec, nullptr, nullptr, out); } - if (in->SchemeIs("chrome")) { + if (scheme.EqualsLiteral("chrome")) { nsCOMPtr chromeReg = mozilla::services::GetChromeRegistry(); if (!chromeReg) return NS_ERROR_UNEXPECTED; diff --git a/toolkit/components/extensions/webrequest/WebNavigationContent.cpp b/toolkit/components/extensions/webrequest/WebNavigationContent.cpp index 9b7a53a3bca8..dab7067ae347 100644 --- a/toolkit/components/extensions/webrequest/WebNavigationContent.cpp +++ b/toolkit/components/extensions/webrequest/WebNavigationContent.cpp @@ -197,14 +197,14 @@ WebNavigationContent::OnStateChange(nsIWebProgress* aWebProgress, nsCOMPtr uri; MOZ_TRY(channel->GetURI(getter_AddRefs(uri))); - // Prevents "about", "chrome", "resource" and "moz-extension" URI schemes to - // be reported with the resolved "file" or "jar" URIs (see bug 1246125) + // Prevent "about", "chrome", "resource", "moz-src", and "moz-extension" URIs + // being reported with the resolved "file" or "jar" URIs (see bug 1246125). if (uri->SchemeIs("file") || uri->SchemeIs("jar")) { nsCOMPtr originalURI; MOZ_TRY(channel->GetOriginalURI(getter_AddRefs(originalURI))); // FIXME: We probably actually want NS_GetFinalChannelURI here. if (originalURI->SchemeIs("about") || originalURI->SchemeIs("chrome") || - originalURI->SchemeIs("resource") || + originalURI->SchemeIs("resource") || originalURI->SchemeIs("moz-src") || originalURI->SchemeIs("moz-extension")) { uri = originalURI.forget(); }