diff --git a/front_end/core/common/ParsedURL.ts b/front_end/core/common/ParsedURL.ts index 72c57172acc241981a356895de8db1a155116972..c07e08d92d9d797a06af30b088b4f7a110e8f0b2 100644 --- a/front_end/core/common/ParsedURL.ts +++ b/front_end/core/common/ParsedURL.ts @@ -64,6 +64,14 @@ export function normalizePath(path: string): string { return normalizedPath; } +export function schemeIs(url: Platform.DevToolsPath.UrlString, scheme: string): boolean { + try { + return (new URL(url)).protocol === scheme; + } catch (e) { + return false; + } +} + export class ParsedURL { isValid: boolean; url: string; diff --git a/front_end/core/sdk/DebuggerModel.ts b/front_end/core/sdk/DebuggerModel.ts index 7bdc0387bff5e574bdfd09249c10b96066584ec1..6721d33efb59cb7185a97a3e612a6f9250453266 100644 --- a/front_end/core/sdk/DebuggerModel.ts +++ b/front_end/core/sdk/DebuggerModel.ts @@ -422,7 +422,7 @@ export class DebuggerModel extends SDKModel { Promise { // Convert file url to node-js path. let urlRegex; - if (this.target().type() === Type.Node && url.startsWith('file://')) { + if (this.target().type() === Type.Node && Common.ParsedURL.schemeIs(url as Platform.DevToolsPath.UrlString, 'file:')) { // TODO(crbug.com/1253323): Cast to UrlString will be removed when migration to branded types is complete. const platformPath = Common.ParsedURL.ParsedURL.capFilePrefix(url as Platform.DevToolsPath.UrlString, Host.Platform.isWin()); diff --git a/front_end/core/sdk/NetworkRequest.ts b/front_end/core/sdk/NetworkRequest.ts index 5afb3f02802974bdd92659f4de60567de0798190..de663b33dd4b54985bbeb83b3a83d06672bc0e1c 100644 --- a/front_end/core/sdk/NetworkRequest.ts +++ b/front_end/core/sdk/NetworkRequest.ts @@ -408,7 +408,7 @@ export class NetworkRequest extends Common.ObjectWrapper.ObjectWrapper i // If a page resulted in an error, the browser will navigate to an internal error page // hosted at 'chrome-error://...'. In this case, skip the frame navigated event to preserve // the network log. - if (mainFrame.url !== mainFrame.unreachableUrl() && mainFrame.url.startsWith('chrome-error://')) { + if (mainFrame.url !== mainFrame.unreachableUrl() && Common.ParsedURL.schemeIs(mainFrame.url as Platform.DevToolsPath.UrlString, 'chrome-error:')) { return; } diff --git a/front_end/models/persistence/Automapping.ts b/front_end/models/persistence/Automapping.ts index cc30a0196b89f97c08d9b7b97d1e6d5fef6979d8..2c6d63cdc4f34ec3a7fe7de7bfd01bc6e3b14a5f 100644 --- a/front_end/models/persistence/Automapping.ts +++ b/front_end/models/persistence/Automapping.ts @@ -192,7 +192,7 @@ export class Automapping { if (this.interceptors.some(interceptor => interceptor(networkSourceCode))) { return; } - if (networkSourceCode.url().startsWith('wasm://')) { + if (Common.ParsedURL.schemeIs(networkSourceCode.url() as Platform.DevToolsPath.UrlString, 'wasm:')) { return; } const createBindingPromise = @@ -322,7 +322,7 @@ export class Automapping { private createBinding(networkSourceCode: Workspace.UISourceCode.UISourceCode): Promise { const url = networkSourceCode.url(); - if (url.startsWith('file://') || url.startsWith('snippet://')) { + if (Common.ParsedURL.schemeIs(url as Platform.DevToolsPath.UrlString, 'file:') || Common.ParsedURL.schemeIs(url as Platform.DevToolsPath.UrlString, 'snippet:')) { const decodedUrl = sanitizeSourceUrl(url); if (!decodedUrl) { return Promise.resolve(null as AutomappingStatus | null); diff --git a/front_end/models/persistence/NetworkPersistenceManager.ts b/front_end/models/persistence/NetworkPersistenceManager.ts index 4745df8fe1b62f0b1dfb38eeba0f672852e605e0..a086dd5fe3d78aee4b71d10e23f0bf1ee0200ae9 100644 --- a/front_end/models/persistence/NetworkPersistenceManager.ts +++ b/front_end/models/persistence/NetworkPersistenceManager.ts @@ -331,7 +331,7 @@ export class NetworkPersistenceManager extends Common.ObjectWrapper.ObjectWrappe } private canHandleNetworkUISourceCode(uiSourceCode: Workspace.UISourceCode.UISourceCode): boolean { - return this.activeInternal && !uiSourceCode.url().startsWith('snippet://'); + return this.activeInternal && !Common.ParsedURL.schemeIs(uiSourceCode.url() as Platform.DevToolsPath.UrlString, 'snippet:'); } private async networkUISourceCodeAdded(uiSourceCode: Workspace.UISourceCode.UISourceCode): Promise { diff --git a/front_end/models/persistence/PersistenceActions.ts b/front_end/models/persistence/PersistenceActions.ts index 23f9b7adbb6a761908509e5bbc932aa8cfda13fa..8cac6bccfd7beae35ce1f108f3d3475fb5c9d682 100644 --- a/front_end/models/persistence/PersistenceActions.ts +++ b/front_end/models/persistence/PersistenceActions.ts @@ -92,7 +92,7 @@ export class ContextMenuProvider implements UI.ContextMenu.Provider { const binding = uiSourceCode && PersistenceImpl.instance().binding(uiSourceCode); const fileURL = binding ? binding.fileSystem.contentURL() : contentProvider.contentURL(); - if (fileURL.startsWith('file://')) { + if (Common.ParsedURL.schemeIs(fileURL as Platform.DevToolsPath.UrlString, 'file:')) { // TODO(crbug.com/1253323): Cast to UrlString will be removed when migration to branded types is complete. const path = Common.ParsedURL.ParsedURL.capFilePrefix(fileURL as Platform.DevToolsPath.UrlString, Host.Platform.isWin()); diff --git a/front_end/models/persistence/PersistenceUtils.ts b/front_end/models/persistence/PersistenceUtils.ts index 0caad032d4a32e221b762420713b82913ceb040d..ce90fabf051944476713f35a323b1c328c5146e0 100644 --- a/front_end/models/persistence/PersistenceUtils.ts +++ b/front_end/models/persistence/PersistenceUtils.ts @@ -48,7 +48,7 @@ export class PersistenceUtils { static iconForUISourceCode(uiSourceCode: Workspace.UISourceCode.UISourceCode): UI.Icon.Icon|null { const binding = PersistenceImpl.instance().binding(uiSourceCode); if (binding) { - if (!binding.fileSystem.url().startsWith('file://')) { + if (!Common.ParsedURL.schemeIs(binding.fileSystem.url() as Platform.DevToolsPath.UrlString, 'file:')) { return null; } const icon = UI.Icon.Icon.create('mediumicon-file-sync'); @@ -60,7 +60,7 @@ export class PersistenceUtils { return icon; } if (uiSourceCode.project().type() !== Workspace.Workspace.projectTypes.FileSystem || - !uiSourceCode.url().startsWith('file://')) { + !Common.ParsedURL.schemeIs(uiSourceCode.url() as Platform.DevToolsPath.UrlString, 'file:')) { return null; } diff --git a/front_end/panels/console/ConsoleContextSelector.ts b/front_end/panels/console/ConsoleContextSelector.ts index df37f9e4245be9ba92814a210deb119d06a46188..feb902658c0aed1880bd156a5a3648cd9e86aec1 100644 --- a/front_end/panels/console/ConsoleContextSelector.ts +++ b/front_end/panels/console/ConsoleContextSelector.ts @@ -226,7 +226,7 @@ export class ConsoleContextSelector implements SDK.TargetManager.SDKModelObserve const resourceTreeModel = target.model(SDK.ResourceTreeModel.ResourceTreeModel); frame = resourceTreeModel && resourceTreeModel.frameForId(executionContext.frameId); } - if (executionContext.origin.startsWith('chrome-extension://')) { + if (Common.ParsedURL.schemeIs(executionContext.origin as Platform.DevToolsPath.UrlString, 'chrome-extension:')) { return i18nString(UIStrings.extension); } const sameTargetParentFrame = frame && frame.sameTargetParentFrame(); diff --git a/front_end/panels/console/ConsoleFormat.ts b/front_end/panels/console/ConsoleFormat.ts index 6fd5e8fa48b83a3ac57a098414867f53f164d91d..20e60ffa2601f80faa924f1e3023933390522735 100644 --- a/front_end/panels/console/ConsoleFormat.ts +++ b/front_end/panels/console/ConsoleFormat.ts @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import * as Common from '../../core/common/common.js'; +import type * as Platform from '../../core/platform/platform.js'; import type * as SDK from '../../core/sdk/sdk.js'; // VGA color palette @@ -216,7 +218,8 @@ export const updateStyle = (currentStyle: Map match[1]); - if (potentialUrls.some(potentialUrl => !potentialUrl.startsWith('data:'))) { + if (potentialUrls.some( + potentialUrl => !Common.ParsedURL.schemeIs(potentialUrl as Platform.DevToolsPath.UrlString, 'data:'))) { continue; } currentStyle.set(property, { diff --git a/front_end/panels/coverage/CoverageModel.ts b/front_end/panels/coverage/CoverageModel.ts index 58e166c544a2deb976823011b7712439baa625f0..f0fb375eab36464009e70d141a14349dc8017632 100644 --- a/front_end/panels/coverage/CoverageModel.ts +++ b/front_end/panels/coverage/CoverageModel.ts @@ -469,7 +469,7 @@ export class CoverageModel extends SDK.SDKModel.SDKModel { continue; } const url = urlInfo.url(); - if (url.startsWith('extensions::') || url.startsWith('chrome-extension://')) { + if (url.startsWith('extensions::') || Common.ParsedURL.schemeIs(url as Platform.DevToolsPath.UrlString, 'chrome-extension:')) { continue; } result.push(...await urlInfo.entriesForExport()); diff --git a/front_end/panels/snippets/ScriptSnippetFileSystem.ts b/front_end/panels/snippets/ScriptSnippetFileSystem.ts index 12e28a01786a0aa596bca1923a0edb9697000761..dba702d01ef3b12bc715d8b2324cd2f89559498d 100644 --- a/front_end/panels/snippets/ScriptSnippetFileSystem.ts +++ b/front_end/panels/snippets/ScriptSnippetFileSystem.ts @@ -136,7 +136,7 @@ export class SnippetFileSystem extends Persistence.PlatformFileSystem.PlatformFi } export async function evaluateScriptSnippet(uiSourceCode: Workspace.UISourceCode.UISourceCode): Promise { - if (!uiSourceCode.url().startsWith('snippet://')) { + if (!Common.ParsedURL.schemeIs(uiSourceCode.url() as Platform.DevToolsPath.UrlString, 'snippet:')) { return; } @@ -191,7 +191,7 @@ export async function evaluateScriptSnippet(uiSourceCode: Workspace.UISourceCode } export function isSnippetsUISourceCode(uiSourceCode: Workspace.UISourceCode.UISourceCode): boolean { - return uiSourceCode.url().startsWith('snippet://'); + return Common.ParsedURL.schemeIs(uiSourceCode.url() as Platform.DevToolsPath.UrlString, 'snippet:'); } export function isSnippetsProject(project: Workspace.Workspace.Project): boolean { diff --git a/front_end/panels/timeline/TimelineUIUtils.ts b/front_end/panels/timeline/TimelineUIUtils.ts index d94ead6987096a3d0dcae571774ca9d55d952c30..01b2c986ea2484717d12d7bba4af788c06087069 100644 --- a/front_end/panels/timeline/TimelineUIUtils.ts +++ b/front_end/panels/timeline/TimelineUIUtils.ts @@ -3392,8 +3392,8 @@ export class TimelineUIUtils { if (!trimAt) { trimAt = 30; } - return url.startsWith('about:') ? `"${Platform.StringUtilities.trimMiddle(frame.name, trimAt)}"` : - frame.url.trimEnd(trimAt); + return Common.ParsedURL.schemeIs(url as Platform.DevToolsPath.UrlString, 'about:') ? `"${Platform.StringUtilities.trimMiddle(frame.name, trimAt)}"` : + frame.url.trimEnd(trimAt); } } diff --git a/front_end/ui/legacy/components/utils/Linkifier.ts b/front_end/ui/legacy/components/utils/Linkifier.ts index b0efe3c7ed407de4a0b2d8fa1f6488d17c61e295..797043bce87d822646af6d490032cbfcf8fc12a5 100644 --- a/front_end/ui/legacy/components/utils/Linkifier.ts +++ b/front_end/ui/legacy/components/utils/Linkifier.ts @@ -27,7 +27,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - +import * as Platform from '../../../../core/platform/platform.js'; import * as Common from '../../../../core/common/common.js'; import * as Host from '../../../../core/host/host.js'; import * as i18n from '../../../../core/i18n/i18n.js'; @@ -516,7 +516,7 @@ export class Linkifier implements SDK.TargetManager.Observer { const preventClick = options.preventClick; const maxLength = options.maxLength || UI.UIUtils.MaxLengthForDisplayedURLs; const bypassURLTrimming = options.bypassURLTrimming; - if (!url || url.trim().toLowerCase().startsWith('javascript:')) { + if (!url || Common.ParsedURL.schemeIs(url as Platform.DevToolsPath.UrlString, 'javascript:')) { const element = document.createElement('span'); if (className) { element.className = className;