From 631a4b24371b79833ce19ec8085df34d55fbb9b4 Mon Sep 17 00:00:00 2001 From: Antoni Kepinski Date: Mon, 20 Apr 2020 21:42:51 +0200 Subject: [PATCH] =?UTF-8?q?fix=20question=20mark=20stripped=20from=20url?= =?UTF-8?q?=20when=20no=20params=20are=20given=20(#7=E2=80=A6=20(#782)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix question mark stripped from url when no params are given (#776) * add more tests * whitespace * modify the server to handle the new tests Co-authored-by: dzek69 --- package.json | 2 +- src/request.js | 7 +++++-- src/utils/get-search.js | 9 +++++++++ test/main.js | 33 +++++++++++++++++++++++++++++++++ test/utils/server.js | 6 ++++++ 5 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 src/utils/get-search.js diff --git a/package.json b/package.json index 09ff83d..1691896 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "chai-as-promised": "^7.1.1", "chai-iterator": "^3.0.2", "chai-string": "^1.5.0", - "coveralls": "^3.0.11", + "coveralls": "^3.0.11", "form-data": "^3.0.0", "mocha": "^7.1.1", "nyc": "^15.0.1", diff --git a/src/request.js b/src/request.js index 08d46f7..19b79d3 100644 --- a/src/request.js +++ b/src/request.js @@ -12,6 +12,7 @@ import Stream from 'stream'; import Headers, {exportNodeCompatibleHeaders} from './headers'; import Body, {clone, extractContentType, getTotalBytes} from './body'; import {isAbortSignal} from './utils/is'; +import {getSearch} from './utils/get-search'; const INTERNALS = Symbol('Request internals'); @@ -258,9 +259,11 @@ export function getNodeRequestOptions(request) { // HTTP-network fetch step 4.2 // chunked encoding is handled by Node.js - // manually spread the URL object instead of spread syntax + const search = getSearch(parsedURL); + + // Manually spread the URL object instead of spread syntax const requestOptions = { - path: parsedURL.pathname + parsedURL.search, + path: parsedURL.pathname + search, pathname: parsedURL.pathname, hostname: parsedURL.hostname, protocol: parsedURL.protocol, diff --git a/src/utils/get-search.js b/src/utils/get-search.js new file mode 100644 index 0000000..b3844d8 --- /dev/null +++ b/src/utils/get-search.js @@ -0,0 +1,9 @@ +export function getSearch(parsedURL) { + if (parsedURL.search) { + return parsedURL.search; + } + + const lastOffset = parsedURL.href.length - 1; + const hash = parsedURL.hash || (parsedURL.href[lastOffset] === '#' ? '#' : ''); + return parsedURL.href[lastOffset - hash.length] === '?' ? '?' : ''; +} diff --git a/test/main.js b/test/main.js index 4f6134b..81e1273 100644 --- a/test/main.js +++ b/test/main.js @@ -1909,6 +1909,39 @@ describe('node-fetch', () => { }); }); + it('should keep `?` sign in URL when no params are given', () => { + const url = `${base}question?`; + const urlObject = new URL(url); + const request = new Request(urlObject); + return fetch(request).then(res => { + expect(res.url).to.equal(url); + expect(res.ok).to.be.true; + expect(res.status).to.equal(200); + }); + }); + + it('if params are given, do not modify anything', () => { + const url = `${base}question?a=1`; + const urlObject = new URL(url); + const request = new Request(urlObject); + return fetch(request).then(res => { + expect(res.url).to.equal(url); + expect(res.ok).to.be.true; + expect(res.status).to.equal(200); + }); + }); + + it('should preserve the hash (#) symbol', () => { + const url = `${base}question?#`; + const urlObject = new URL(url); + const request = new Request(urlObject); + return fetch(request).then(res => { + expect(res.url).to.equal(url); + expect(res.ok).to.be.true; + expect(res.status).to.equal(200); + }); + }); + it('should support reading blob as text', () => { return new Response('hello') .blob() diff --git a/test/utils/server.js b/test/utils/server.js index 14f5af4..0616d35 100644 --- a/test/utils/server.js +++ b/test/utils/server.js @@ -49,6 +49,12 @@ export default class TestServer { res.end('world'); } + if (p.includes('question')) { + res.statusCode = 200; + res.setHeader('Content-Type', 'text/plain'); + res.end('ok'); + } + if (p === '/plain') { res.statusCode = 200; res.setHeader('Content-Type', 'text/plain');