From e45fe88dc484909199e04afcea31d527c22b2c7a Mon Sep 17 00:00:00 2001 From: Luke Edwards Date: Thu, 26 Aug 2021 23:42:36 -0700 Subject: [PATCH] break(url): remove `toDecode` parameter (#175) * break(url): remove `toDecode` param * chore(url): update bench results --- packages/url/bench/index.js | 83 +++-------------------- packages/url/bench/readme.md | 123 ++++++++++++----------------------- packages/url/index.d.ts | 2 +- packages/url/index.js | 17 +---- packages/url/readme.md | 33 +--------- packages/url/test/index.js | 110 ++++++------------------------- 6 files changed, 77 insertions(+), 291 deletions(-) diff --git a/packages/url/bench/index.js b/packages/url/bench/index.js index 61efb99..7f1f6ed 100644 --- a/packages/url/bench/index.js +++ b/packages/url/bench/index.js @@ -17,7 +17,7 @@ const isVerbose = process.argv.includes('--verbose'); /** * @typedef Contender - * @type {(req: Request, toDecode: boolean) => any} + * @type {(req: Request) => any} */ /** @@ -26,22 +26,20 @@ const isVerbose = process.argv.includes('--verbose'); * @type {Record} */ const contenders = { - 'url.parse': (r, d) => { + 'url.parse': r => { let out = native.parse(r.url, true); // query as object - if (d) out.pathname = decodeURIComponent(out.pathname); // returns `null` if no value out.search = out.search || ''; return out; }, - 'new URL()': (r, d) => { + 'new URL()': r => { let url = r.url; let { pathname, search, searchParams } = new URL(url, 'http://x.com'); - if (d) pathname = decodeURIComponent(pathname); return { url, pathname, search, query: searchParams }; }, - 'parseurl': (r, d) => { + 'parseurl': r => { /** @type {Record} */ // @ts-ignore let out = parseurl(r); @@ -51,35 +49,31 @@ const contenders = { // @ts-ignore - always returns `query` as string|null if (out.query) out.query = qs.parse(out.query); - // never decodes, do bare minimum for compat - if (d) out.pathname = decodeURIComponent(out.pathname); - return out; }, - '@polka/url': (r, d) => { + '@polka/url': r => { // @ts-ignore - request - return polka(r, d); + return polka(r); }, }; /** * @param {object} config * @param {string} config.url - * @param {boolean} config.decode * @param {Record} config.expect * @param {boolean} [config.repeat] */ function runner(config) { - let { url, expect, repeat, decode=false } = config; - let title = repeat ? 'repeat' : decode ? 'decode' : 'normal'; + let { url, expect, repeat } = config; + let title = repeat ? 'repeat' : 'normal'; console.log('\nValidation: (%s) "%s"', title, url); Object.keys(contenders).forEach(name => { let key, fn=contenders[name]; try { - let output = fn({ url }, decode); + let output = fn({ url }); for (key in expect) { let tmp = output[key]; @@ -107,7 +101,7 @@ function runner(config) { let req = repeat && { url }; bench.add(name + ' '.repeat(16 - name.length), () => { - fn(req || { url }, decode); + fn(req || { url }); }, { minSamples: 100 }); @@ -120,7 +114,6 @@ function runner(config) { runner({ url: '/foo/bar?user=tj&pet=fluffy', - decode: false, expect: { pathname: '/foo/bar', search: '?user=tj&pet=fluffy', @@ -134,7 +127,6 @@ runner({ runner({ repeat: true, url: '/foo/bar?user=tj&pet=fluffy', - decode: false, expect: { pathname: '/foo/bar', search: '?user=tj&pet=fluffy', @@ -147,7 +139,6 @@ runner({ runner({ url: '/foo/bar', - decode: false, expect: { pathname: '/foo/bar', search: '', @@ -156,62 +147,8 @@ runner({ runner({ url: '/', - decode: false, expect: { pathname: '/', search: '', } }); - -// DECODES - -runner({ - url: '/f%C3%B8%C3%B8%C3%9F%E2%88%82r', - decode: true, - expect: { - pathname: '/føøß∂r', - search: '', - } -}); - -runner({ - url: '/f%C3%B8%C3%B8%C3%9F%E2%88%82r?phone=%2b393383123549', - decode: true, - expect: { - pathname: '/føøß∂r', - search: '?phone=%2b393383123549', - query: { phone: '+393383123549' }, - } -}); - -runner({ - repeat: true, - url: '/f%C3%B8%C3%B8%C3%9F%E2%88%82r?phone=%2b393383123549', - decode: true, - expect: { - pathname: '/føøß∂r', - search: '?phone=%2b393383123549', - query: { phone: '+393383123549' }, - } -}); - -runner({ - url: '/foo/bar?hello=123', - decode: true, - expect: { - pathname: '/foo/bar', - search: '?hello=123', - query: { - hello: '123', - } - } -}); - -runner({ - url: '/foo/bar', - decode: true, - expect: { - pathname: '/foo/bar', - search: '', - } -}); diff --git a/packages/url/bench/readme.md b/packages/url/bench/readme.md index 1106c05..95648e2 100644 --- a/packages/url/bench/readme.md +++ b/packages/url/bench/readme.md @@ -1,79 +1,42 @@ ## Benchmarks -> Running on Node v14.15.3 +> Running on Node v16.8.0 ***Modifications:*** -Each candidate is _slightly_ modified to match the `pathname` and `query` values that `@polka/url` returns. This is done in an honest/best-effort manner to normalize all candidates (and pass the validation steps), especially considering that the typical user _wants_ `pathname`s to be normalized and _wants_ `query` values to be parsed (and decoded) into an object. +Each candidate is _slightly_ modified to match the `search` and `query` values that `@polka/url` returns. This is done in an honest/best-effort manner to normalize all candidates (and pass the validation steps), especially considering that the typical user wants `query` to be parsed (and decoded) into an object. -Please see the [Raw Performance](#raw-performance) benchmarks for results ***without*** any modifications. However, do note that the benchmark is effectively useless since all candidates do different things by default. +Please see the [Raw Performance](#raw-performance) benchmarks for results ***without*** any modifications. However, do note that the raw-benchmark is effectively useless since all candidates do different things by default. -### Without Decoding +## Normalized (minimal) > **Important:** All candidates listed pass validation – sometimes due to normalization. ``` Benchmark: "/foo/bar?user=tj&pet=fluffy" - url.parse x 1,437,988 ops/sec ±0.15% (193 runs sampled) - new URL() x 258,158 ops/sec ±0.17% (193 runs sampled) - parseurl x 2,074,250 ops/sec ±0.22% (193 runs sampled) - @polka/url x 2,584,006 ops/sec ±0.26% (194 runs sampled) + url.parse x 1,766,192 ops/sec ±0.59% (189 runs sampled) + new URL() x 254,742 ops/sec ±0.93% (188 runs sampled) + parseurl x 2,296,634 ops/sec ±0.43% (188 runs sampled) + @polka/url x 3,096,770 ops/sec ±0.56% (189 runs sampled) Benchmark: (REPEAT) "/foo/bar?user=tj&pet=fluffy" - url.parse x 1,457,258 ops/sec ±0.17% (193 runs sampled) - new URL() x 257,459 ops/sec ±0.24% (189 runs sampled) - parseurl x 26,687,772 ops/sec ±0.40% (192 runs sampled) - @polka/url x 117,737,558 ops/sec ±0.23% (193 runs sampled) + url.parse x 1,794,821 ops/sec ±1.01% (188 runs sampled) + new URL() x 258,587 ops/sec ±0.63% (189 runs sampled) + parseurl x 30,616,846 ops/sec ±0.47% (191 runs sampled) + @polka/url x 314,370,079 ops/sec ±0.36% (189 runs sampled) Benchmark: "/foo/bar" - url.parse x 5,928,214 ops/sec ±0.33% (191 runs sampled) - new URL() x 290,799 ops/sec ±0.17% (192 runs sampled) - parseurl x 17,597,099 ops/sec ±0.62% (189 runs sampled) - @polka/url x 34,097,146 ops/sec ±0.55% (192 runs sampled) + url.parse x 7,373,531 ops/sec ±0.63% (188 runs sampled) + new URL() x 291,642 ops/sec ±0.83% (189 runs sampled) + parseurl x 21,946,341 ops/sec ±0.93% (186 runs sampled) + @polka/url x 48,697,030 ops/sec ±0.49% (189 runs sampled) Benchmark: "/" - url.parse x 8,933,877 ops/sec ±0.70% (190 runs sampled) - new URL() x 333,268 ops/sec ±0.19% (193 runs sampled) - parseurl x 27,358,354 ops/sec ±0.76% (188 runs sampled) - @polka/url x 43,529,456 ops/sec ±1.99% (172 runs sampled) -``` - - -### With Decoding - -> **Important:** All candidates listed pass validation – sometimes due to normalization. - -``` -Benchmark: "/f%C3%B8%C3%B8%C3%9F%E2%88%82r" - url.parse x 1,038,724 ops/sec ±0.12% (193 runs sampled) - new URL() x 229,125 ops/sec ±0.17% (192 runs sampled) - parseurl x 1,370,300 ops/sec ±0.20% (192 runs sampled) - @polka/url x 1,540,894 ops/sec ±0.18% (192 runs sampled) - -Benchmark: "/f%C3%B8%C3%B8%C3%9F%E2%88%82r?phone=%2b393383123549" - url.parse x 514,280 ops/sec ±0.40% (193 runs sampled) - new URL() x 187,672 ops/sec ±0.67% (192 runs sampled) - parseurl x 618,801 ops/sec ±0.10% (189 runs sampled) - @polka/url x 696,125 ops/sec ±0.14% (191 runs sampled) - -Benchmark: (REPEAT) "/f%C3%B8%C3%B8%C3%9F%E2%88%82r?phone=%2b393383123549" - url.parse x 425,909 ops/sec ±0.29% (193 runs sampled) - new URL() x 187,735 ops/sec ±0.14% (194 runs sampled) - parseurl x 1,770,147 ops/sec ±0.15% (193 runs sampled) - @polka/url x 197,963,726 ops/sec ±0.18% (194 runs sampled) - -Benchmark: "/foo/bar?hello=123" - url.parse x 1,133,709 ops/sec ±0.28% (190 runs sampled) - new URL() x 236,384 ops/sec ±0.20% (193 runs sampled) - parseurl x 1,431,879 ops/sec ±0.19% (191 runs sampled) - @polka/url x 3,883,489 ops/sec ±0.37% (192 runs sampled) - -Benchmark: "/foo/bar" - url.parse x 1,824,376 ops/sec ±0.54% (192 runs sampled) - new URL() x 252,204 ops/sec ±0.18% (192 runs sampled) - parseurl x 2,329,132 ops/sec ±0.26% (193 runs sampled) - @polka/url x 19,972,200 ops/sec ±0.64% (188 runs sampled) + url.parse x 10,744,706 ops/sec ±0.47% (188 runs sampled) + new URL() x 315,725 ops/sec ±0.86% (184 runs sampled) + parseurl x 46,863,886 ops/sec ±1.06% (189 runs sampled) + @polka/url x 72,862,914 ops/sec ±0.54% (190 runs sampled) ``` @@ -81,44 +44,44 @@ Benchmark: "/foo/bar" These are the results of the _unmodified_ candidates. In other words, there is **zero consistency** in the candidates outputs. For example: -* `url.parse#1` uses [`url.parse`](https://nodejs.org/api/url.html#url_url_parse_urlstring_parsequerystring_slashesdenotehost) with `parseQueryString` enabled
_It decodes the `query` correctly, but all other segments are still encoded segments._ +* `url.parse#1` uses [`url.parse`](https://nodejs.org/api/url.html#url_url_parse_urlstring_parsequerystring_slashesdenotehost) with `parseQueryString` enabled
_It converts the `query` into a decoded object, but everything else remains encoded._ * `url.parse#2` is the same as `url.parse#1`, except `parseQueryString` is disabled.
_It leaves the `query` as a string & does no decoding whatsoever._ -* `new URL()` does what it describes :)
_The `pathname` is never decoded, but `searchParams` is always an decoded `URLSearchParams` instance._ +* `new URL()` does what it describes :)
_Everything remains encoded, except for `searchParams`, which is always an `URLSearchParams` instance with decoded values._ * `parseurl` never decodes any value segments and `query` is always a string. -* `@polka/url` only decodes the `pathname` when asked and `query` is always a decoded object. +* `@polka/url` never decodes any value segments except `query`, which is always a decoded object. ***Results*** ``` Benchmark: (normal) "/foo/bar?user=tj&pet=fluffy" - url.parse#1 x 1,462,942 ops/sec ±0.16% (193 runs sampled) - url.parse#2 x 3,059,883 ops/sec ±0.19% (193 runs sampled) - new URL() x 273,878 ops/sec ±0.11% (194 runs sampled) - parseurl x 7,742,605 ops/sec ±0.25% (192 runs sampled) - @polka/url x 2,611,970 ops/sec ±0.18% (190 runs sampled) + url.parse#1 x 1,757,099 ops/sec ±0.67% (188 runs sampled) + url.parse#2 x 4,487,853 ops/sec ±0.70% (185 runs sampled) + new URL() x 284,153 ops/sec ±0.68% (187 runs sampled) + parseurl x 9,848,571 ops/sec ±0.97% (186 runs sampled) + @polka/url x 3,040,460 ops/sec ±0.79% (188 runs sampled) Benchmark: (repeat) "/foo/bar?user=tj&pet=fluffy" - url.parse#1 x 1,477,740 ops/sec ±0.28% (194 runs sampled) - url.parse#2 x 3,121,952 ops/sec ±0.12% (193 runs sampled) - new URL() x 271,608 ops/sec ±0.24% (192 runs sampled) - parseurl x 112,501,081 ops/sec ±3.88% (177 runs sampled) - @polka/url x 73,331,596 ops/sec ±2.44% (180 runs sampled) + url.parse#1 x 1,827,115 ops/sec ±0.41% (190 runs sampled) + url.parse#2 x 4,442,871 ops/sec ±0.72% (183 runs sampled) + new URL() x 286,803 ops/sec ±0.30% (189 runs sampled) + parseurl x 78,897,892 ops/sec ±1.51% (182 runs sampled) + @polka/url x 291,908,732 ops/sec ±4.97% (179 runs sampled) Benchmark: (normal) "/foo/bar" - url.parse#1 x 6,109,524 ops/sec ±0.39% (190 runs sampled) - url.parse#2 x 6,741,743 ops/sec ±0.38% (190 runs sampled) - new URL() x 304,240 ops/sec ±0.15% (192 runs sampled) - parseurl x 17,809,555 ops/sec ±0.55% (190 runs sampled) - @polka/url x 28,314,612 ops/sec ±1.14% (175 runs sampled) + url.parse#1 x 7,824,747 ops/sec ±0.65% (186 runs sampled) + url.parse#2 x 9,015,704 ops/sec ±0.68% (188 runs sampled) + new URL() x 320,978 ops/sec ±0.41% (188 runs sampled) + parseurl x 25,611,676 ops/sec ±0.45% (189 runs sampled) + @polka/url x 48,554,610 ops/sec ±0.48% (190 runs sampled) Benchmark: (normal) "/" - url.parse#1 x 9,370,629 ops/sec ±0.37% (187 runs sampled) - url.parse#2 x 11,248,825 ops/sec ±0.55% (190 runs sampled) - new URL() x 343,111 ops/sec ±0.18% (193 runs sampled) - parseurl x 28,455,610 ops/sec ±0.92% (187 runs sampled) - @polka/url x 41,677,905 ops/sec ±1.07% (188 runs sampled) + url.parse#1 x 11,682,323 ops/sec ±0.81% (187 runs sampled) + url.parse#2 x 15,679,363 ops/sec ±0.61% (188 runs sampled) + new URL() x 348,880 ops/sec ±0.35% (189 runs sampled) + parseurl x 34,522,603 ops/sec ±0.73% (190 runs sampled) + @polka/url x 71,136,459 ops/sec ±0.58% (189 runs sampled) ``` diff --git a/packages/url/index.d.ts b/packages/url/index.d.ts index 748a3cf..9b27c04 100644 --- a/packages/url/index.d.ts +++ b/packages/url/index.d.ts @@ -7,4 +7,4 @@ export interface ParsedURL { raw: string; } -export function parse(req: IncomingMessage, toDecode?: boolean): ParsedURL; +export function parse(req: IncomingMessage): ParsedURL; diff --git a/packages/url/index.js b/packages/url/index.js index 2d79aa7..9d5e7b9 100644 --- a/packages/url/index.js +++ b/packages/url/index.js @@ -8,21 +8,19 @@ import * as qs from 'querystring'; /** * @typedef Request * @property {string} url - * @property {string} _decoded * @property {ParsedURL} _parsedUrl */ /** * @param {Request} req - * @param {boolean} [toDecode] * @returns {ParsedURL|void} */ -export function parse(req, toDecode) { +export function parse(req) { let raw = req.url; if (raw == null) return; - let prev=req._parsedUrl, encoded=!req._decoded; - if (prev && prev.raw === raw && !toDecode === encoded) return prev; + let prev = req._parsedUrl; + if (prev && prev.raw === raw) return prev; let pathname=raw, search='', query; @@ -36,15 +34,6 @@ export function parse(req, toDecode) { query = qs.parse(search.substring(1)); } } - - if (!!toDecode && encoded) { - if (pathname.indexOf('%') === -1) { - req._decoded = pathname; - } else { - try { pathname = req._decoded = decodeURIComponent(pathname) } - catch (e) { /* URI malformed */ } - } - } } return req._parsedUrl = { pathname, search, query, raw }; diff --git a/packages/url/readme.md b/packages/url/readme.md index a7857ab..69947a7 100644 --- a/packages/url/readme.md +++ b/packages/url/readme.md @@ -34,28 +34,11 @@ let output = parse(req); // Attaches result for future memoization assert.deepEqual(output, req._parsedUrl); //=> true - -// Example with `toDecode` param -req = { - url: '/f%C3%B8%C3%B8%C3%9F%E2%88%82r?phone=%2b8675309' -}; -parse(req, true); -//=> { -//=> pathname: '/føøß∂r', -//=> raw: '/f%C3%B8%C3%B8%C3%9F%E2%88%82r?phone=%2b8675309', -//=> search: '?phone=%2b8675309', -//=> query: { -//=> phone: '+8675309' -//=> } -//=> } - -// Attaches awareness key -assert(req._decoded); //=> '/føøß∂r' ``` ## API -### url(req, toDecode?) +### url(req) Returns: `Object` or `undefined` > **Important:** The `req` must have a `url` key, otherwise `undefined` will be returned.
If no input is provided at all, a `TypeError` will be thrown. @@ -67,20 +50,6 @@ The incoming HTTP request (`req`) or a plain `Object` with a `url` key. > **Note:** In Node.js servers, the [`req.url`](https://nodejs.org/api/http.html#http_message_url) begins with a pathname & does not include a `hash`. -#### toDecode -Type: `Boolean`
-Default: `false` - -If enabled, the `pathname` will be fully decoded, via [`decodeURIComponent`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent). - -> **Important:** Please note the following behaviors: -> * `raw` is _never_ decoded; this key reflects your original value -> * `pathname` is decoded _only_ when `toDecode` is enabled -> * `search` is _never_ decoded; this key reflects your original querystring value -> * `query` is _always_ decoded; even when `toDecode` is disabled - -Additionally, the `req` is mutated with `req._decoded` so as to prevent repetitive decoding. - ## Benchmarks diff --git a/packages/url/test/index.js b/packages/url/test/index.js index 76f3c47..0036b38 100644 --- a/packages/url/test/index.js +++ b/packages/url/test/index.js @@ -4,16 +4,12 @@ import { parse } from '../index'; /** * @param {string} url - * @param {boolean} isDecode * @param {import('..').ParsedURL} expected */ -function run(url, isDecode, expected) { - let title = `url :: "${url}"`; - if (isDecode) title += ' :: decode'; - - test(title, () => { +function run(url, expected) { + test(`url :: "${url}"`, () => { let req = /** @type any */ ({ url }); - let output = parse(req, isDecode); + let output = parse(req); if (output.query) { // convert `null` prototype @@ -21,7 +17,6 @@ function run(url, isDecode, expected) { } assert.type(output, 'object'); - if (isDecode) assert.is(req._decoded, req._parsedUrl.pathname); assert.is(req._parsedUrl, output, 'referential match'); assert.is(output.raw, url); @@ -44,21 +39,21 @@ test('url :: invalid inputs', () => { ); }); -run('/', false, { +run('/', { raw: '/', pathname: '/', search: '', query: undefined, }); -run('/foo/bar', false, { +run('/foo/bar', { raw: '/foo/bar', pathname: '/foo/bar', search: '', query: undefined, }); -run('/foo/bar?fizz=buzz', false, { +run('/foo/bar?fizz=buzz', { raw: '/foo/bar?fizz=buzz', pathname: '/foo/bar', search: '?fizz=buzz', @@ -67,7 +62,7 @@ run('/foo/bar?fizz=buzz', false, { }, }); -run('/foo/bar?fizz=buzz&hello=world', false, { +run('/foo/bar?fizz=buzz&hello=world', { raw: '/foo/bar?fizz=buzz&hello=world', pathname: '/foo/bar', search: '?fizz=buzz&hello=world', @@ -77,14 +72,14 @@ run('/foo/bar?fizz=buzz&hello=world', false, { }, }); -run('/foo.123', false, { +run('/foo.123', { raw: '/foo.123', pathname: '/foo.123', search: '', query: undefined }); -run('/foo?bar', false, { +run('/foo?bar', { raw: '/foo?bar', pathname: '/foo', search: '?bar', @@ -94,7 +89,7 @@ run('/foo?bar', false, { }); // query param w/ "?" value -run('/foo?q=a?b=c', false, { +run('/foo?q=a?b=c', { raw: '/foo?q=a?b=c', pathname: '/foo', search: '?q=a?b=c', @@ -104,7 +99,7 @@ run('/foo?q=a?b=c', false, { }); // repeated query keys -run('/foo?bar=1&bar=2&bar=3&baz=&bat', false, { +run('/foo?bar=1&bar=2&bar=3&baz=&bat', { raw: '/foo?bar=1&bar=2&bar=3&baz=&bat', pathname: '/foo', search: '?bar=1&bar=2&bar=3&baz=&bat', @@ -115,25 +110,16 @@ run('/foo?bar=1&bar=2&bar=3&baz=&bat', false, { } }); -// NOT DECODED -run('/f%C3%B8%C3%B8%C3%9F%E2%88%82r', false, { +run('/f%C3%B8%C3%B8%C3%9F%E2%88%82r', { raw: '/f%C3%B8%C3%B8%C3%9F%E2%88%82r', pathname: '/f%C3%B8%C3%B8%C3%9F%E2%88%82r', search: '', query: undefined }); -// DECODED -run('/f%C3%B8%C3%B8%C3%9F%E2%88%82r', true, { - raw: '/f%C3%B8%C3%B8%C3%9F%E2%88%82r', - pathname: '/føøß∂r', - search: '', - query: undefined -}); - -run('/f%C3%B8%C3%B8%C3%9F%E2%88%82r?phone=%2b8675309', true, { +run('/f%C3%B8%C3%B8%C3%9F%E2%88%82r?phone=%2b8675309', { raw: '/f%C3%B8%C3%B8%C3%9F%E2%88%82r?phone=%2b8675309', - pathname: '/føøß∂r', + pathname: '/f%C3%B8%C3%B8%C3%9F%E2%88%82r', search: '?phone=%2b8675309', query: { phone: '+8675309' @@ -141,7 +127,7 @@ run('/f%C3%B8%C3%B8%C3%9F%E2%88%82r?phone=%2b8675309', true, { }); // query param w/ "+" for space -run('/hello?world=a+b', true, { +run('/hello?world=a+b', { raw: '/hello?world=a+b', pathname: '/hello', search: '?world=a+b', @@ -152,7 +138,7 @@ run('/hello?world=a+b', true, { let plain = 'https://hi.com/w?v=hello&list=world'; let urlencoded = encodeURIComponent(plain); -run(`/foobar/?href=${urlencoded}`, true, { +run(`/foobar/?href=${urlencoded}`, { raw: `/foobar/?href=${urlencoded}`, pathname: '/foobar/', search: `?href=${urlencoded}`, @@ -190,13 +176,11 @@ test('url :: cache :: miss', () => { assert.is.not(out1, out2, 'referential'); }); -test('url :: decode :: URI malformed', () => { +// no effect because no decode +test('url :: malformed uri', () => { /** @type any */ let req = { url: '/%2?foo=bar' }; - let out = parse(req, true); - - // could not be decoded cuz malform - assert.is(req._decoded, undefined); + let out = parse(req); // convert `null` prototype out.query = { ...out.query }; @@ -211,60 +195,4 @@ test('url :: decode :: URI malformed', () => { }); }); -test('url :: decode :: cache :: hit', () => { - /** @type any */ - let req = { url: '/foo/hell%C3%B6' }; - let out1 = parse(req, true); - - // @ts-ignore - out1.foobar = 123; - - let out2 = parse(req, true); - - // @ts-ignore - assert.is(out2.foobar, 123); - assert.is(out1, out2, 'referential'); - assert.is(out1.pathname, '/foo/hellö'); -}); - -test('url :: decode :: cache :: miss #1', () => { - /** @type any */ - let req = { url: '/foo/hell%C3%B6?fizz=buzz' }; - let out1 = parse(req); - - assert.is(req._parsedUrl, out1); - assert.is(out1.pathname, '/foo/hell%C3%B6'); - - // @ts-ignore - out1.foobar = 123; - - let out2 = parse(req, true); - - // @ts-ignore - assert.is(out2.foobar, undefined); - assert.is.not(req._parsedUrl, out1); - assert.is.not(out1, out2, 'referential'); - assert.is(out2.pathname, '/foo/hellö'); -}); - -test('url :: decode :: cache :: miss #2', () => { - /** @type any */ - let req = { url: '/foo/hell%C3%B6?fizz=buzz' }; - let out1 = parse(req, true); - - assert.is(req._parsedUrl, out1); - assert.is(out1.pathname, '/foo/hellö'); - - // @ts-ignore - out1.foobar = 123; - - let out2 = parse(req); - - // @ts-ignore - assert.is(out2.foobar, undefined); - assert.is.not(req._parsedUrl, out1); - assert.is.not(out1, out2, 'referential'); - assert.is(out2.pathname, '/foo/hell%C3%B6'); -}); - test.run();