From 68cf850bc43901ba4cfa82cb1fff87cd1e4c34bf Mon Sep 17 00:00:00 2001 From: Daijiro Wachi Date: Mon, 10 Apr 2017 18:09:06 +0200 Subject: [PATCH] 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/12507 Refs: https://github.com/w3c/web-platform-tests/pull/5195 Fixes: https://github.com/nodejs/node/issues/11188 Reviewed-By: James M Snell --- src/node_url.cc | 22 +- test/fixtures/url-setter-tests.js | 29 ++- test/fixtures/url-tests.js | 352 +++++++++++++++++++++++++++++- 3 files changed, 393 insertions(+), 10 deletions(-) diff --git a/src/node_url.cc b/src/node_url.cc index f9965d537b9abf..16a4cdd45b54b4 100644 --- a/src/node_url.cc +++ b/src/node_url.cc @@ -1108,12 +1108,14 @@ namespace url { state = kFileHost; } else { if (has_base && - base->scheme == "file:" && - base->flags & URL_FLAGS_HAS_PATH && - base->path.size() > 0 && - NORMALIZED_WINDOWS_DRIVE_LETTER(base->path[0])) { - url->flags |= URL_FLAGS_HAS_PATH; - url->path.push_back(base->path[0]); + base->scheme == "file:") { + if (NORMALIZED_WINDOWS_DRIVE_LETTER(base->path[0])) { + url->flags |= URL_FLAGS_HAS_PATH; + url->path.push_back(base->path[0]); + } else { + url->flags |= URL_FLAGS_HAS_HOST; + url->host = base->host; + } } state = kPath; continue; @@ -1196,6 +1198,14 @@ namespace url { url->path.push_back(segment); } 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 == '?') { url->flags |= URL_FLAGS_HAS_QUERY; state = kQuery; diff --git a/test/fixtures/url-setter-tests.js b/test/fixtures/url-setter-tests.js index 8c15a3cc5ac885..d0688611a01c0f 100644 --- a/test/fixtures/url-setter-tests.js +++ b/test/fixtures/url-setter-tests.js @@ -1,7 +1,7 @@ 'use strict'; /* 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 */ module.exports = @@ -1620,6 +1620,33 @@ module.exports = "href": "sc://example.net/%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": [ diff --git a/test/fixtures/url-tests.js b/test/fixtures/url-tests.js index c7e63f50331c3b..3858f12db55e0d 100644 --- a/test/fixtures/url-tests.js +++ b/test/fixtures/url-tests.js @@ -1,7 +1,7 @@ 'use strict'; /* 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 */ module.exports = @@ -281,6 +281,11 @@ module.exports = "base": "http://example.org/foo/bar", "failure": true }, + { + "input": "non-special://f:999999/c", + "base": "http://example.org/foo/bar", + "failure": true + }, { "input": "http://f: 21 / b ? d # e ", "base": "http://example.org/foo/bar", @@ -3669,6 +3674,35 @@ module.exports = "search": "", "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", { "input": "http://%zz%66%a.com", @@ -5110,6 +5144,318 @@ module.exports = "search": "?test", "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", { "input": "file:", @@ -5213,12 +5559,12 @@ module.exports = { "input": "http://?", "base": "about:blank", - "failure": "true" + "failure": true }, { "input": "http://#", "base": "about:blank", - "failure": "true" + "failure": true }, "# Non-special-URL path tests", // {