From 197830a8fc03d80bd360d249ed5a430dcdef4175 Mon Sep 17 00:00:00 2001 From: Mario Rogic Date: Mon, 6 Jul 2020 18:54:12 +0100 Subject: [PATCH 1/2] Fix 'TypeError [ERR_UNESCAPED_CHARACTERS]: Request path contains unescaped characters' It appears most browsers (tested in Firefox, Safari and Chromium[Chrome/Brave]) will url-encode paths automatically if they are not already encoded. `xhr2` doesn't match that behavior when run in node: using an unencoded URL will result in `TypeError [ERR_UNESCAPED_CHARACTERS]`. Just adding the encoding line however causes a new issue; already encoded URLs end up being double-encoded, changing the URL incorrectly. Using [`native-url`](https://github.com/GoogleChromeLabs/native-url instead of `url` fixes this, as well as removing the dependency on the deprecated [Legacy URL API](https://nodejs.org/api/url.html#url_legacy_url_api). It would have of course been better to refactor `xhr2` to not use the deprecated API, however this does not appear to be trivial looking at the [`native-url` code](https://github.com/GoogleChromeLabs/native-url/tree/master/src). --- package.json | 4 +++- src/001-xml_http_request.coffee | 4 +++- test/src/helpers/xhr_server.coffee | 4 ++++ test/src/xhr_test.coffee | 22 ++++++++++++++++++++++ 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index b723776..558fad9 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,9 @@ "engines": { "node": ">= 6" }, - "dependencies": {}, + "dependencies": { + "native-url": "^0.3.4" + }, "devDependencies": { "async": ">=3.0.1", "chai": ">=4.2.0", diff --git a/src/001-xml_http_request.coffee b/src/001-xml_http_request.coffee index 3e448b4..82d5a01 100644 --- a/src/001-xml_http_request.coffee +++ b/src/001-xml_http_request.coffee @@ -6,7 +6,7 @@ http = require 'http' https = require 'https' os = require 'os' -url = require 'url' +url = require 'native-url' # The ECMAScript HTTP API. # @@ -105,6 +105,8 @@ class XMLHttpRequest extends XMLHttpRequestEventTarget throw new SecurityError "HTTP method #{method} is not allowed in XHR" xhrUrl = @_parseUrl url + xhrUrl.path = encodeURI xhrUrl.path + async = true if async is undefined switch @readyState diff --git a/test/src/helpers/xhr_server.coffee b/test/src/helpers/xhr_server.coffee index 5dcb0ea..db35810 100644 --- a/test/src/helpers/xhr_server.coffee +++ b/test/src/helpers/xhr_server.coffee @@ -95,6 +95,10 @@ class XhrServer response.write json.body if json.body response.end() + # Returns a given URL parameter. Used for URL encoding testing. + @app.all '/_/url/:arg', (request, response) => + response.json request.params.arg + # Sends data in small chunks. Used for event testing. @app.post '/_/drip', (request, response) -> request.connection.setNoDelay() diff --git a/test/src/xhr_test.coffee b/test/src/xhr_test.coffee index 0f83657..6e76528 100644 --- a/test/src/xhr_test.coffee +++ b/test/src/xhr_test.coffee @@ -70,6 +70,28 @@ describe 'XMLHttpRequest', -> done() @xhr.send() + describe 'on an unencoded URL', -> + beforeEach -> + @xhr.open 'GET', 'http://localhost:8912/_/url/💻' + + it 'encodes correctly', (done) -> + @xhr.onload = (event) => + expect(@xhr.status).to.equal 200 + expect(@xhr.responseText).to.equal '"💻"' + done() + @xhr.send() + + describe 'on an encoded URL', -> + beforeEach -> + @xhr.open 'GET', 'http://localhost:8912/_/url/%F0%9F%92%BB' + + it 'does not double-encode', (done) -> + @xhr.onload = (event) => + expect(@xhr.status).to.equal 200 + expect(@xhr.responseText).to.equal '"💻"' + done() + @xhr.send() + describe 'on a local gopher GET', -> describe '#open + #send', -> it 'throw a NetworkError', -> From a0286b2600fe8b0132e4c99dfd0a14b3bfc7be04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Nicouleaud?= Date: Fri, 10 Jan 2020 23:27:33 +0100 Subject: [PATCH 2/2] Force Mocha to quit after tests complete --- Cakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cakefile b/Cakefile index d23d8ff..f0d15a6 100644 --- a/Cakefile +++ b/Cakefile @@ -20,7 +20,7 @@ task 'test', -> ssl_cert -> test_cases = glob.sync 'test/js/**/*_test.js' test_cases.sort() # Consistent test case order. - run 'node_modules/.bin/mocha --colors --slow 200 --timeout 1000 ' + + run 'node_modules/.bin/mocha --colors --slow 200 --timeout 1000 --exit ' + "--require test/js/helpers/setup.js #{test_cases.join(' ')}" task 'webtest', ->