Skip to content
3 changes: 2 additions & 1 deletion packages/url/src/get-query-args.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/**
* Internal dependencies
*/
import { safeDecodeURIComponent } from './safe-decode-uri-component';
import { getQueryString } from './get-query-string';

/** @typedef {import('./get-query-arg').QueryArgParsed} QueryArgParsed */
Expand Down Expand Up @@ -85,7 +86,7 @@ export function getQueryArgs( url ) {
// Filtering avoids decoding as `undefined` for value, where
// default is restored in destructuring assignment.
.filter( Boolean )
.map( decodeURIComponent );
.map( safeDecodeURIComponent );

if ( key ) {
const segments = key.replace( /\]/g, '' ).split( '[' );
Expand Down
10 changes: 10 additions & 0 deletions packages/url/src/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,16 @@ describe( 'getQueryArgs', () => {
)
).toEqual( data );
} );

it( 'should not blow up on malformed params', () => {
const url = 'https://andalouses.example/beach?foo=bar&baz=%E0%A4%A';

expect( () => getQueryArgs( url ) ).not.toThrow();
expect( getQueryArgs( url ) ).toEqual( {
baz: '%E0%A4%A',
foo: 'bar',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PHP's parse_str() returns the malformed query var:

wp shell
wp> parse_str( 'foo=bar&baz=%E0%A4%A', $args );
=> NULL
$ wp> $args
=> array(2) {
  ["foo"]=>
  string(3) "bar"
  ["baz"]=>
  string(4) "�%A"
}

getQueryArgs() was originally designed to emulate parse_str() (#20693). Would it be possible to return the malformed value instead, for consistent behavior?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, @danielbachhuber for pointing this out. I wasn't familiar with that.
I did the changes as requested.

Please note, that although this is a step to the right direction, will minimally affect the issue we have in calypso.

Calypso uses two ways to parse URLs:

  1. qs library
  2. Using the following import:
import { getQueryArgs } from 'calypso/lib/query-args';

This internally uses the get-query-args I'm about to fix here, but to fix the issue related to this pr, we need to stop using qs and start using our function as stated above.

I proposed to add that inside the calypso README file for other developers to be aware.

We can create a ticket to remove qs library of course, but this is a huge take and I think it's better if we do it incrementally.

Maybe we should communicate that also to the calypso channel as well?

Any thoughts?

Thank you!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This internally uses the get-query-args I'm about to fix here, but to fix the issue related to this pr, we need to stop using qs and start using our function as stated above.

I proposed to add that inside the calypso README file for other developers to be aware.

We can create a ticket to remove qs library of course, but this is a huge take and I think it's better if we do it incrementally.

@kozer I'm not sure README is quite the right approach. Can you create a new issue in https://github.com/Automattic/wp-calypso and we can discuss with the Calypso team?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getQueryArgs() was originally designed to emulate parse_str() (#20693). Would it be possible to return the malformed value instead, for consistent behavior?

I kind of agree with this. Is there is a reason not to return the value? You could just replace decodeURIComponent with safeDecodeURIComponent then.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Raising another hand of agreement. I think using safeDecodeURIComponent was the intention here since it does exactly what we're aiming for.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ntsekouras , @tyxla I did the changes you proposed. Thanks so much!
I already have created an issue here. Do you think it make sense to open a new one?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I already have created an issue here. Do you think it make sense to open a new one?

@kozer No, that's sufficient.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for taking care of that, @kozer, looks great 🙌

} );
} );
} );
} );

Expand Down