Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions patch/patches/devtools.patch
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,55 @@ index 0a5ec620b1..8a34390ac5 100644
let parsedURL;
// This is only to work around invalid URLs we're occasionally getting from some tests.
// TODO(caseq): make sure tests supply valid URLs or we specifically handle invalid ones.
diff --git a/front_end/ui/helpers/OpenInNewTab.ts b/front_end/ui/helpers/OpenInNewTab.ts
index cfa93f3..7f2cda0 100644
--- front_end/ui/helpers/OpenInNewTab.ts
+++ front_end/ui/helpers/OpenInNewTab.ts
@@ -57,8 +57,46 @@ import * as SDK from '../../core/sdk/sdk.js';
* @throws TypeError if `url` is not a valid URL.
* @see https://en.wikipedia.org/wiki/UTM_parameters
*/
+function encodeFilePath(path: string): string {
+ const parts = path.split('/');
+ return parts.map((part, index) => {
+ if (index === 0 && /^[A-Za-z]:$/.test(part)) {
+ return part;
+ }
+ return encodeURIComponent(part);
+ }).join('/');
+}
+
+function fileURLFromAbsolutePath(path: string): URL|null {
+ if (path.startsWith('/')) {
+ return new URL(`file://${encodeFilePath(path)}`);
+ }
+ if (/^[A-Za-z]:[\\/]/.test(path)) {
+ const normalizedPath = path.replace(/\\/g, '/');
+ return new URL(`file:///${encodeFilePath(normalizedPath)}`);
+ }
+ return null;
+}
+
+function normalizeURLToOpen(url: URL|string): URL {
+ if (url instanceof URL) {
+ return url;
+ }
+ try {
+ return new URL(url);
+ } catch (error) {
+ // NW.js can surface Node stack frames as raw absolute paths. Keep stack
+ // filenames unchanged, but open those links as file URLs.
+ const fileURL = fileURLFromAbsolutePath(url);
+ if (fileURL) {
+ return fileURL;
+ }
+ throw error;
+ }
+}
+
export function openInNewTab(url: URL|string): void {
- url = new URL(url);
+ url = normalizeURLToOpen(url);
if (Common.ParsedURL.schemeIs(url, 'javascript:')) {
return;
}
58 changes: 58 additions & 0 deletions src/nwjs_browsertest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1144,6 +1144,64 @@ IN_PROC_BROWSER_TEST_F(NWJSDevToolsTest, Issue4269Crash) {
EXPECT_TRUE(base::EndsWith(url, "inspect.html"));
}

IN_PROC_BROWSER_TEST_F(NWJSDevToolsTest, Issue4269NodeModuleLink) {
LoadAndLaunchApp("issue4269-node-module-link", "Launched");
content::WebContents* wc = GetAppWebContents("index.html");
ASSERT_TRUE(wc);

DevToolsWindowCreationObserver observer;
ASSERT_TRUE(EvalJs(wc, "nw.Window.get().showDevTools()").is_ok());
observer.WaitForLoad();
DevToolsWindow* window = observer.devtools_window();
SwitchToPanel(window, "console");
WebContents* devtools = DevToolsWindowTesting::Get(window)->main_web_contents();

ui_test_utils::BrowserCreatedObserver new_browser_observer;
ASSERT_TRUE(EvalJs(devtools, R"js(
(() => new Promise((resolve, reject) => {
const clickLink = () => {
const links = Array.from(document.querySelectorAll(
'.console-message-text .devtools-link'));
const link =
links.find(link => link.textContent.includes('myModule2.js'));
if (!link) {
return false;
}
link.click();
resolve(true);
return true;
};
if (clickLink()) {
return;
}
const observer = new MutationObserver(() => {
if (clickLink()) {
observer.disconnect();
}
});
observer.observe(document.body, {
childList: true,
subtree: true,
characterData: true
});
setTimeout(() => {
observer.disconnect();
reject(new Error('missing myModule2.js console link'));
}, 5000);
}))()
)js").is_ok());
Browser* active_browser = new_browser_observer.Wait();
ui_test_utils::WaitUntilBrowserBecomeActive(active_browser);
content::WebContents* popup_contents =
active_browser->tab_strip_model()->GetActiveWebContents();
EXPECT_TRUE(content::WaitForLoadStop(popup_contents));

std::string url = popup_contents->GetLastCommittedURL().spec();
LOG(WARNING) << url;
EXPECT_TRUE(url.rfind("file://", 0) == 0);
EXPECT_TRUE(base::EndsWith(url, "myModule2.js"));
}

IN_PROC_BROWSER_TEST_F(NWAppTest, LocalFlash) {
std::string contents;
base::FilePath test_dir = test_data_dir_.Append(FILE_PATH_LITERAL("platform_apps")).Append(FILE_PATH_LITERAL("local_flash"));
Expand Down
15 changes: 15 additions & 0 deletions test/browser/issue4269-node-module-link/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Node module link</title>
</head>
<body>
<script src="myModule.js"></script>
<script>
if (chrome.test) {
chrome.test.sendMessage("Launched");
}
</script>
</body>
</html>
3 changes: 3 additions & 0 deletions test/browser/issue4269-node-module-link/myModule.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
setTimeout(() => {
nw.require('./myModule2');
}, 0);
1 change: 1 addition & 0 deletions test/browser/issue4269-node-module-link/myModule2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
myTestError();
4 changes: 4 additions & 0 deletions test/browser/issue4269-node-module-link/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name": "issue4269-node-module-link",
"main": "index.html"
}