From: Eduardo San Martin Morote Date: Fri, 13 Nov 2020 10:40:33 +0000 (+0100) Subject: fix(query): encode space as + X-Git-Tag: v4.0.0-rc.3~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4d3dd5fd523cefc675aa7e61ed9b06b66e42b80c;p=thirdparty%2Fvuejs%2Frouter.git fix(query): encode space as + Close #561 --- diff --git a/__tests__/encoding.spec.ts b/__tests__/encoding.spec.ts index 8fd7ab99..d299ac3a 100644 --- a/__tests__/encoding.spec.ts +++ b/__tests__/encoding.spec.ts @@ -58,9 +58,9 @@ describe('Encoding', () => { }) describe('query params', () => { - const safePerSpec = "!$'*+,:;@[]_|?/{}^()`" - const toEncodeForKey = ' "<>#&=' - const toEncodeForValue = ' "<>#&' + const safePerSpec = "!$'*,:;@[]_|?/{}^()`" + const toEncodeForKey = '"<>#&=' + const toEncodeForValue = '"<>#&' const encodedToEncodeForKey = toEncodeForKey .split('') .map(c => { @@ -100,6 +100,16 @@ describe('Encoding', () => { expect(encodeQueryKey(toEncodeForKey)).toBe(encodedToEncodeForKey) expect(encodeQueryValue(toEncodeForValue)).toBe(encodedToEncodeForValue) }) + + it('encodes space as +', () => { + expect(encodeQueryKey(' ')).toBe('+') + expect(encodeQueryValue(' ')).toBe('+') + }) + + it('encodes +', () => { + expect(encodeQueryKey('+')).toBe('%2B') + expect(encodeQueryValue('+')).toBe('%2B') + }) }) describe('hash', () => { diff --git a/__tests__/parseQuery.spec.ts b/__tests__/parseQuery.spec.ts index 11542cb9..b16c8624 100644 --- a/__tests__/parseQuery.spec.ts +++ b/__tests__/parseQuery.spec.ts @@ -65,6 +65,18 @@ describe('parseQuery', () => { }) }) + it('decodes the + as space', () => { + expect(parseQuery('a+b=c+d')).toEqual({ + 'a b': 'c d', + }) + }) + + it('decodes the encoded + as +', () => { + expect(parseQuery('a%2Bb=c%2Bd')).toEqual({ + 'a+b': 'c+d', + }) + }) + // this is for browsers like IE that allow invalid characters it('keep invalid values as is', () => { expect(parseQuery('e=%&e=%25')).toEqual({ diff --git a/src/encoding.ts b/src/encoding.ts index 8d1a6602..47964c47 100644 --- a/src/encoding.ts +++ b/src/encoding.ts @@ -23,6 +23,7 @@ const AMPERSAND_RE = /&/g // %26 const SLASH_RE = /\//g // %2F const EQUAL_RE = /=/g // %3D const IM_RE = /\?/g // %3F +const PLUS_RE = /\+/g // %2B /** * NOTE: It's not clear to me if we should encode the + symbol in queries, it * seems to be less flexible than not doing so and I can't find out the legacy @@ -37,7 +38,6 @@ const IM_RE = /\?/g // %3F * - https://url.spec.whatwg.org/#urlencoded-parsing * - https://stackoverflow.com/questions/1634271/url-encoding-the-space-character-or-20 */ -// const PLUS_RE = /\+/g // %3F const ENC_BRACKET_OPEN_RE = /%5B/g // [ const ENC_BRACKET_CLOSE_RE = /%5D/g // ] @@ -46,6 +46,7 @@ const ENC_BACKTICK_RE = /%60/g // ` const ENC_CURLY_OPEN_RE = /%7B/g // { const ENC_PIPE_RE = /%7C/g // | const ENC_CURLY_CLOSE_RE = /%7D/g // } +const ENC_SPACE_RE = /%20/g // } /** * Encode characters that need to be encoded on the path, search and hash @@ -83,13 +84,18 @@ export function encodeHash(text: string): string { * @returns encoded string */ export function encodeQueryValue(text: string | number): string { - return commonEncode(text) - .replace(HASH_RE, '%23') - .replace(AMPERSAND_RE, '%26') - .replace(ENC_BACKTICK_RE, '`') - .replace(ENC_CURLY_OPEN_RE, '{') - .replace(ENC_CURLY_CLOSE_RE, '}') - .replace(ENC_CARET_RE, '^') + return ( + commonEncode(text) + // Encode the space as +, encode the + to differentiate it from the space + .replace(PLUS_RE, '%2B') + .replace(ENC_SPACE_RE, '+') + .replace(HASH_RE, '%23') + .replace(AMPERSAND_RE, '%26') + .replace(ENC_BACKTICK_RE, '`') + .replace(ENC_CURLY_OPEN_RE, '{') + .replace(ENC_CURLY_CLOSE_RE, '}') + .replace(ENC_CARET_RE, '^') + ) } /** diff --git a/src/query.ts b/src/query.ts index b8a1c02d..e7903c4b 100644 --- a/src/query.ts +++ b/src/query.ts @@ -50,7 +50,9 @@ export function parseQuery(search: string): LocationQuery { const hasLeadingIM = search[0] === '?' const searchParams = (hasLeadingIM ? search.slice(1) : search).split('&') for (let i = 0; i < searchParams.length; ++i) { - const searchParam = searchParams[i] + // pre decode the + into space + // FIXME: can't import PLUS_RE because it becomes a different regex ??? + const searchParam = searchParams[i].replace(/\+/g, ' ') // allow the = character let eqPos = searchParam.indexOf('=') let key = decode(eqPos < 0 ? searchParam : searchParam.slice(0, eqPos))