1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-22 07:14:47 -05:00

fix(cli/rt): Fix file URL to path conversion on Windows (#6920)

This commit is contained in:
Nayeem Rahman 2020-07-30 23:37:26 +01:00 committed by GitHub
parent 0da4779b17
commit 6e7208bec2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 62 additions and 40 deletions

View file

@ -64,23 +64,18 @@
}
function pathFromURLWin32(url) {
const hostname = url.hostname;
const pathname = decodeURIComponent(url.pathname.replace(/\//g, "\\"));
if (hostname !== "") {
//TODO(actual-size) Node adds a punycode decoding step, we should consider adding this
return `\\\\${hostname}${pathname}`;
let path = decodeURIComponent(
url.pathname
.replace(/^\/*([A-Za-z]:)(\/|$)/, "$1/")
.replace(/\//g, "\\"),
);
if (url.hostname != "") {
// Note: The `URL` implementation guarantees that the drive letter and
// hostname are mutually exclusive. Otherwise it would not have been valid
// to append the hostname and path like this.
path = `\\\\${url.hostname}${path}`;
}
const validPath = /^\\(?<driveLetter>[A-Za-z]):\\/;
const matches = validPath.exec(pathname);
if (!matches?.groups?.driveLetter) {
throw new TypeError("A URL with the file schema must be absolute.");
}
// we don't want a leading slash on an absolute path in Windows
return pathname.slice(1);
return path;
}
function pathFromURLPosix(url) {

View file

@ -1,31 +1,49 @@
// Copyright 2018-2020 the Deno authors. All rights reserved. MIT license.
import { posix, win32 } from "./mod.ts";
import { assertEquals } from "../testing/asserts.ts";
import { assertEquals, assertThrows } from "../testing/asserts.ts";
Deno.test("[path] fromFileUrl", function () {
assertEquals(posix.fromFileUrl(new URL("file:///home/foo")), "/home/foo");
assertEquals(posix.fromFileUrl("file:///"), "/");
assertEquals(posix.fromFileUrl("file:///home/foo"), "/home/foo");
assertEquals(posix.fromFileUrl("file:///home/foo%20bar"), "/home/foo bar");
assertEquals(posix.fromFileUrl("https://example.com/foo"), "/foo");
assertEquals(posix.fromFileUrl("file:///"), "/");
// Drive letters are supported platform-independently to align with the WHATWG
// URL specification.
assertEquals(posix.fromFileUrl("file:///c:"), "c:/");
assertEquals(posix.fromFileUrl("file:///c:/"), "c:/");
assertEquals(posix.fromFileUrl("file:///C:/"), "C:/");
assertEquals(posix.fromFileUrl("file:///C:/Users/"), "C:/Users/");
assertEquals(posix.fromFileUrl("file://localhost/foo"), "/foo");
assertEquals(posix.fromFileUrl("file:///C:"), "/C:");
assertEquals(posix.fromFileUrl("file:///C:/"), "/C:/");
assertEquals(posix.fromFileUrl("file:///C:/Users/"), "/C:/Users/");
assertEquals(posix.fromFileUrl("file:///C:foo/bar"), "/C:foo/bar");
assertThrows(
() => posix.fromFileUrl("http://localhost/foo"),
TypeError,
"Must be a file URL.",
);
assertThrows(
() => posix.fromFileUrl("abcd://localhost/foo"),
TypeError,
"Must be a file URL.",
);
});
Deno.test("[path] fromFileUrl (win32)", function () {
assertEquals(win32.fromFileUrl(new URL("file:///home/foo")), "\\home\\foo");
assertEquals(win32.fromFileUrl("file:///"), "\\");
assertEquals(win32.fromFileUrl("file:///home/foo"), "\\home\\foo");
assertEquals(win32.fromFileUrl("file:///home/foo%20bar"), "\\home\\foo bar");
assertEquals(win32.fromFileUrl("https://example.com/foo"), "\\foo");
assertEquals(win32.fromFileUrl("file:///"), "\\");
assertEquals(win32.fromFileUrl("file:///c:"), "c:\\");
assertEquals(win32.fromFileUrl("file:///c:/"), "c:\\");
assertEquals(win32.fromFileUrl("file://localhost/foo"), "\\\\localhost\\foo");
assertEquals(win32.fromFileUrl("file:///C:"), "C:\\");
assertEquals(win32.fromFileUrl("file:///C:/"), "C:\\");
// Drop the hostname if a drive letter is parsed.
assertEquals(win32.fromFileUrl("file://localhost/C:/"), "C:\\");
assertEquals(win32.fromFileUrl("file:///C:/Users/"), "C:\\Users\\");
assertEquals(win32.fromFileUrl("file:///C:foo/bar"), "\\C:foo\\bar");
assertThrows(
() => win32.fromFileUrl("http://localhost/foo"),
TypeError,
"Must be a file URL.",
);
assertThrows(
() => win32.fromFileUrl("abcd://localhost/foo"),
TypeError,
"Must be a file URL.",
);
});

View file

@ -430,11 +430,11 @@ export function parse(path: string): ParsedPath {
/** Converts a file URL to a path string.
*
* fromFileUrl("file:///home/foo"); // "/home/foo"
*
* Note that non-file URLs are treated as file URLs and irrelevant components
* are ignored.
*/
export function fromFileUrl(url: string | URL): string {
return decodeURIComponent((url instanceof URL ? url : new URL(url)).pathname
.replace(/^\/*([A-Za-z]:)(\/|$)/, "$1/"));
url = url instanceof URL ? url : new URL(url);
if (url.protocol != "file:") {
throw new TypeError("Must be a file URL.");
}
return decodeURIComponent(url.pathname);
}

View file

@ -907,16 +907,25 @@ export function parse(path: string): ParsedPath {
/** Converts a file URL to a path string.
*
* fromFileUrl("file:///C:/Users/foo"); // "C:\\Users\\foo"
* fromFileUrl("file:///home/foo"); // "\\home\\foo"
*
* Note that non-file URLs are treated as file URLs and irrelevant components
* are ignored.
* fromFileUrl("file:///C:/Users/foo"); // "C:\\Users\\foo"
* fromFileUrl("file://localhost/home/foo"); // "\\\\localhost\\home\\foo"
*/
export function fromFileUrl(url: string | URL): string {
return decodeURIComponent(
(url instanceof URL ? url : new URL(url)).pathname
url = url instanceof URL ? url : new URL(url);
if (url.protocol != "file:") {
throw new TypeError("Must be a file URL.");
}
let path = decodeURIComponent(
url.pathname
.replace(/^\/*([A-Za-z]:)(\/|$)/, "$1/")
.replace(/\//g, "\\"),
);
if (url.hostname != "") {
// Note: The `URL` implementation guarantees that the drive letter and
// hostname are mutually exclusive. Otherwise it would not have been valid
// to append the hostname and path like this.
path = `\\\\${url.hostname}${path}`;
}
return path;
}