Browse Source

url: trim leading slashes of file URL paths

It should trim the slashes after the colon into three for file URL.

PR-URL: https://github.com/nodejs/node/pull/12203
Refs: https://github.com/w3c/web-platform-tests/pull/5195
Fixes: https://github.com/nodejs/node/issues/11188
Reviewed-By: Timothy Gu <timothygu99@gmail.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
v6
Daijiro Wachi 8 years ago
parent
commit
b470a85f07
  1. 22
      src/node_url.cc
  2. 29
      test/fixtures/url-setter-tests.js
  3. 352
      test/fixtures/url-tests.js

22
src/node_url.cc

@ -1108,12 +1108,14 @@ namespace url {
state = kFileHost; state = kFileHost;
} else { } else {
if (has_base && if (has_base &&
base->scheme == "file:" && base->scheme == "file:") {
base->flags & URL_FLAGS_HAS_PATH && if (NORMALIZED_WINDOWS_DRIVE_LETTER(base->path[0])) {
base->path.size() > 0 && url->flags |= URL_FLAGS_HAS_PATH;
NORMALIZED_WINDOWS_DRIVE_LETTER(base->path[0])) { url->path.push_back(base->path[0]);
url->flags |= URL_FLAGS_HAS_PATH; } else {
url->path.push_back(base->path[0]); url->flags |= URL_FLAGS_HAS_HOST;
url->host = base->host;
}
} }
state = kPath; state = kPath;
continue; continue;
@ -1196,6 +1198,14 @@ namespace url {
url->path.push_back(segment); url->path.push_back(segment);
} }
buffer.clear(); buffer.clear();
if (url->scheme == "file:" &&
(ch == kEOL ||
ch == '?' ||
ch == '#')) {
while (url->path.size() > 1 && url->path[0].length() == 0) {
url->path.erase(url->path.begin());
}
}
if (ch == '?') { if (ch == '?') {
url->flags |= URL_FLAGS_HAS_QUERY; url->flags |= URL_FLAGS_HAS_QUERY;
state = kQuery; state = kQuery;

29
test/fixtures/url-setter-tests.js

@ -1,7 +1,7 @@
'use strict'; 'use strict';
/* WPT Refs: /* WPT Refs:
https://github.com/w3c/web-platform-tests/blob/e48dd15/url/setters_tests.json https://github.com/w3c/web-platform-tests/blob/3eff1bd/url/setters_tests.json
License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html
*/ */
module.exports = module.exports =
@ -1620,6 +1620,33 @@ module.exports =
"href": "sc://example.net/%23", "href": "sc://example.net/%23",
"pathname": "/%23" "pathname": "/%23"
} }
},
{
"comment": "File URLs and (back)slashes",
"href": "file://monkey/",
"new_value": "\\\\",
"expected": {
"href": "file://monkey/",
"pathname": "/"
}
},
{
"comment": "File URLs and (back)slashes",
"href": "file:///unicorn",
"new_value": "//\\/",
"expected": {
"href": "file:///",
"pathname": "/"
}
},
{
"comment": "File URLs and (back)slashes",
"href": "file:///unicorn",
"new_value": "//monkey/..//",
"expected": {
"href": "file:///",
"pathname": "/"
}
} }
], ],
"search": [ "search": [

352
test/fixtures/url-tests.js

@ -1,7 +1,7 @@
'use strict'; 'use strict';
/* WPT Refs: /* WPT Refs:
https://github.com/w3c/web-platform-tests/blob/b207902/url/urltestdata.json https://github.com/w3c/web-platform-tests/blob/3eff1bd/url/urltestdata.json
License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html License: http://www.w3.org/Consortium/Legal/2008/04-testsuite-copyright.html
*/ */
module.exports = module.exports =
@ -281,6 +281,11 @@ module.exports =
"base": "http://example.org/foo/bar", "base": "http://example.org/foo/bar",
"failure": true "failure": true
}, },
{
"input": "non-special://f:999999/c",
"base": "http://example.org/foo/bar",
"failure": true
},
{ {
"input": "http://f: 21 / b ? d # e ", "input": "http://f: 21 / b ? d # e ",
"base": "http://example.org/foo/bar", "base": "http://example.org/foo/bar",
@ -3669,6 +3674,35 @@ module.exports =
"search": "", "search": "",
"hash": "" "hash": ""
}, },
// {
// "input": "https://faß.ExAmPlE/",
// "base": "about:blank",
// "href": "https://xn--fa-hia.example/",
// "origin": "https://faß.example",
// "protocol": "https:",
// "username": "",
// "password": "",
// "host": "xn--fa-hia.example",
// "hostname": "xn--fa-hia.example",
// "port": "",
// "pathname": "/",
// "search": "",
// "hash": ""
// },
// {
// "input": "sc://faß.ExAmPlE/",
// "base": "about:blank",
// "href": "sc://fa%C3%9F.ExAmPlE/",
// "protocol": "sc:",
// "username": "",
// "password": "",
// "host": "fa%C3%9F.ExAmPlE",
// "hostname": "fa%C3%9F.ExAmPlE",
// "port": "",
// "pathname": "/",
// "search": "",
// "hash": ""
// },
"Invalid escaped characters should fail and the percents should be escaped. https://www.w3.org/Bugs/Public/show_bug.cgi?id=24191", "Invalid escaped characters should fail and the percents should be escaped. https://www.w3.org/Bugs/Public/show_bug.cgi?id=24191",
{ {
"input": "http://%zz%66%a.com", "input": "http://%zz%66%a.com",
@ -5110,6 +5144,318 @@ module.exports =
"search": "?test", "search": "?test",
"hash": "#x" "hash": "#x"
}, },
"# File URLs and many (back)slashes",
{
"input": "file:\\\\//",
"base": "about:blank",
"href": "file:///",
"protocol": "file:",
"username": "",
"password": "",
"host": "",
"hostname": "",
"port": "",
"pathname": "/",
"search": "",
"hash": ""
},
{
"input": "file:\\\\\\\\",
"base": "about:blank",
"href": "file:///",
"protocol": "file:",
"username": "",
"password": "",
"host": "",
"hostname": "",
"port": "",
"pathname": "/",
"search": "",
"hash": ""
},
{
"input": "file:\\\\\\\\?fox",
"base": "about:blank",
"href": "file:///?fox",
"protocol": "file:",
"username": "",
"password": "",
"host": "",
"hostname": "",
"port": "",
"pathname": "/",
"search": "?fox",
"hash": ""
},
{
"input": "file:\\\\\\\\#guppy",
"base": "about:blank",
"href": "file:///#guppy",
"protocol": "file:",
"username": "",
"password": "",
"host": "",
"hostname": "",
"port": "",
"pathname": "/",
"search": "",
"hash": "#guppy"
},
{
"input": "file://spider///",
"base": "about:blank",
"href": "file://spider/",
"protocol": "file:",
"username": "",
"password": "",
"host": "spider",
"hostname": "spider",
"port": "",
"pathname": "/",
"search": "",
"hash": ""
},
{
"input": "file:\\\\localhost//",
"base": "about:blank",
"href": "file:///",
"protocol": "file:",
"username": "",
"password": "",
"host": "",
"hostname": "",
"port": "",
"pathname": "/",
"search": "",
"hash": ""
},
{
"input": "file:///localhost//cat",
"base": "about:blank",
"href": "file:///localhost//cat",
"protocol": "file:",
"username": "",
"password": "",
"host": "",
"hostname": "",
"port": "",
"pathname": "/localhost//cat",
"search": "",
"hash": ""
},
{
"input": "file://\\/localhost//cat",
"base": "about:blank",
"href": "file:///localhost//cat",
"protocol": "file:",
"username": "",
"password": "",
"host": "",
"hostname": "",
"port": "",
"pathname": "/localhost//cat",
"search": "",
"hash": ""
},
{
"input": "file://localhost//a//../..//",
"base": "about:blank",
"href": "file:///",
"protocol": "file:",
"username": "",
"password": "",
"host": "",
"hostname": "",
"port": "",
"pathname": "/",
"search": "",
"hash": ""
},
{
"input": "/////mouse",
"base": "file:///elephant",
"href": "file:///mouse",
"protocol": "file:",
"username": "",
"password": "",
"host": "",
"hostname": "",
"port": "",
"pathname": "/mouse",
"search": "",
"hash": ""
},
{
"input": "\\//pig",
"base": "file://lion/",
"href": "file:///pig",
"protocol": "file:",
"username": "",
"password": "",
"host": "",
"hostname": "",
"port": "",
"pathname": "/pig",
"search": "",
"hash": ""
},
{
"input": "\\/localhost//pig",
"base": "file://lion/",
"href": "file:///pig",
"protocol": "file:",
"username": "",
"password": "",
"host": "",
"hostname": "",
"port": "",
"pathname": "/pig",
"search": "",
"hash": ""
},
{
"input": "//localhost//pig",
"base": "file://lion/",
"href": "file:///pig",
"protocol": "file:",
"username": "",
"password": "",
"host": "",
"hostname": "",
"port": "",
"pathname": "/pig",
"search": "",
"hash": ""
},
// {
// "input": "/..//localhost//pig",
// "base": "file://lion/",
// "href": "file://lion/localhost//pig",
// "protocol": "file:",
// "username": "",
// "password": "",
// "host": "lion",
// "hostname": "lion",
// "port": "",
// "pathname": "/localhost//pig",
// "search": "",
// "hash": ""
// },
{
"input": "file://",
"base": "file://ape/",
"href": "file:///",
"protocol": "file:",
"username": "",
"password": "",
"host": "",
"hostname": "",
"port": "",
"pathname": "/",
"search": "",
"hash": ""
},
"# File URLs with non-empty hosts",
// {
// "input": "/rooibos",
// "base": "file://tea/",
// "href": "file://tea/rooibos",
// "protocol": "file:",
// "username": "",
// "password": "",
// "host": "tea",
// "hostname": "tea",
// "port": "",
// "pathname": "/rooibos",
// "search": "",
// "hash": ""
// },
// {
// "input": "/?chai",
// "base": "file://tea/",
// "href": "file://tea/?chai",
// "protocol": "file:",
// "username": "",
// "password": "",
// "host": "tea",
// "hostname": "tea",
// "port": "",
// "pathname": "/",
// "search": "?chai",
// "hash": ""
// },
"# Windows drive letter quirk with not empty host",
{
"input": "file://example.net/C:/",
"base": "about:blank",
"href": "file:///C:/",
"protocol": "file:",
"username": "",
"password": "",
"host": "",
"hostname": "",
"port": "",
"pathname": "/C:/",
"search": "",
"hash": ""
},
{
"input": "file://1.2.3.4/C:/",
"base": "about:blank",
"href": "file:///C:/",
"protocol": "file:",
"username": "",
"password": "",
"host": "",
"hostname": "",
"port": "",
"pathname": "/C:/",
"search": "",
"hash": ""
},
{
"input": "file://[1::8]/C:/",
"base": "about:blank",
"href": "file:///C:/",
"protocol": "file:",
"username": "",
"password": "",
"host": "",
"hostname": "",
"port": "",
"pathname": "/C:/",
"search": "",
"hash": ""
},
"# Windows drive letter quirk (no host)",
{
"input": "file:/C|/",
"base": "about:blank",
"href": "file:///C:/",
"protocol": "file:",
"username": "",
"password": "",
"host": "",
"hostname": "",
"port": "",
"pathname": "/C:/",
"search": "",
"hash": ""
},
{
"input": "file://C|/",
"base": "about:blank",
"href": "file:///C:/",
"protocol": "file:",
"username": "",
"password": "",
"host": "",
"hostname": "",
"port": "",
"pathname": "/C:/",
"search": "",
"hash": ""
},
"# file URLs without base URL by Rimas Misevičius", "# file URLs without base URL by Rimas Misevičius",
{ {
"input": "file:", "input": "file:",
@ -5213,12 +5559,12 @@ module.exports =
{ {
"input": "http://?", "input": "http://?",
"base": "about:blank", "base": "about:blank",
"failure": "true" "failure": true
}, },
{ {
"input": "http://#", "input": "http://#",
"base": "about:blank", "base": "about:blank",
"failure": "true" "failure": true
}, },
"# Non-special-URL path tests", "# Non-special-URL path tests",
// { // {

Loading…
Cancel
Save