Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions packages/common/http/src/params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export class HttpUrlEncodingCodec implements HttpParameterCodec {
* @returns The encoded key name.
*/
encodeKey(key: string): string {
return standardEncoding(key);
return standardEncoding(key, KEY_ENCODING_REPLACEMENTS);
}

/**
Expand All @@ -53,7 +53,7 @@ export class HttpUrlEncodingCodec implements HttpParameterCodec {
* @returns The encoded value.
*/
encodeValue(value: string): string {
return standardEncoding(value);
return standardEncoding(value, VALUE_ENCODING_REPLACEMENTS);
}

/**
Expand Down Expand Up @@ -100,22 +100,24 @@ function paramParser(rawParams: string, codec: HttpParameterCodec): Map<string,
* Encode input string with standard encodeURIComponent and then un-encode specific characters.
*/
const STANDARD_ENCODING_REGEX = /%(\d[a-f0-9])/gi;
const STANDARD_ENCODING_REPLACEMENTS: {[x: string]: string} = {
const KEY_ENCODING_REPLACEMENTS: {[x: string]: string} = {
'40': '@',
'3A': ':',
'24': '$',
'2C': ',',
'3B': ';',
'3D': '=',
'3F': '?',
'2F': '/',
};
// A pair is split at its first `=`, so that character only carries its literal meaning in a
// value and has to stay percent-encoded in a key.
const VALUE_ENCODING_REPLACEMENTS: {[x: string]: string} = {
...KEY_ENCODING_REPLACEMENTS,
'3D': '=',
};

function standardEncoding(v: string): string {
return encodeURIComponent(v).replace(
STANDARD_ENCODING_REGEX,
(s, t) => STANDARD_ENCODING_REPLACEMENTS[t] ?? s,
);
function standardEncoding(v: string, replacements: {[x: string]: string}): string {
return encodeURIComponent(v).replace(STANDARD_ENCODING_REGEX, (s, t) => replacements[t] ?? s);
}

function valueToString(value: string | number | boolean): string {
Expand Down
9 changes: 9 additions & 0 deletions packages/common/http/test/params_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,15 @@ describe('HttpUrlEncodedParams', () => {
const body2 = new HttpParams({fromString: 'a=1 2 3&b=mail@test&c=3_^[]$&d=eq=1&e=1+1'});
expect(body2.toString()).toEqual('a=1%202%203&b=mail@test&c=3_%5E%5B%5D$&d=eq=1&e=1%2B1');
});

it('should keep `=` encoded in a key so the pair round-trips', () => {
const body = new HttpParams().set('filter=admin', 'true');
expect(body.toString()).toEqual('filter%3Dadmin=true');

const reparsed = new HttpParams({fromString: body.toString()});
expect(reparsed.keys()).toEqual(['filter=admin']);
expect(reparsed.get('filter=admin')).toEqual('true');
});
});

describe('toString', () => {
Expand Down
Loading