Skip to content
Merged
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
1 change: 1 addition & 0 deletions packages/url/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

- `filterURLForDisplay`: Clamp the truncated file name's head slice at zero, so a small `maxLength` no longer returns a string longer than the untruncated one ([#81529](https://github.com/WordPress/gutenberg/pull/81529)).
- `getQueryArgs`: Split each query argument on its first `=` only, so values containing `=` — base64 padding, JWTs, nested URLs — are no longer truncated, and ignore malformed pairs with no key instead of promoting the value to one ([#81066](https://github.com/WordPress/gutenberg/pull/81066)).
- `normalizePath` no longer throws a `URIError` when a query parameter contains a malformed percent sequence, such as `/wp/v2/posts?search=50%off`. It now uses `safeDecodeURIComponent`, matching the fix already applied to `getQueryArgs` in [#45561](https://github.com/WordPress/gutenberg/pull/45561) ([#81086](https://github.com/WordPress/gutenberg/pull/81086)).

## 4.53.0 (2026-08-12)

Expand Down
4 changes: 3 additions & 1 deletion packages/url/src/normalize-path.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { safeDecodeURIComponent } from './safe-decode-uri-component';

/**
* Given a path, returns a normalized path where equal query parameter values
* will be treated as identical, regardless of order they appear in the original
Expand Down Expand Up @@ -25,7 +27,7 @@ export function normalizePath( path: string ): string {
// [ [ 'b, '1%2C2' ], [ 'c', '2' ], [ 'a', '5' ] ]
.map( ( entry ) => entry.split( '=' ) )
// [ [ 'b', '1,2' ], [ 'c', '2' ], [ 'a', '5' ] ]
.map( ( pair ) => pair.map( decodeURIComponent ) )
.map( ( pair ) => pair.map( safeDecodeURIComponent ) )
// [ [ 'a', '5' ], [ 'b, '1,2' ], [ 'c', '2' ] ]
.sort( ( a, b ) => a[ 0 ].localeCompare( b[ 0 ] ) )
// [ [ 'a', '5' ], [ 'b, '1%2C2' ], [ 'c', '2' ] ]
Expand Down
14 changes: 14 additions & 0 deletions packages/url/src/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1305,4 +1305,18 @@ describe( 'normalizePath', () => {
const ab = normalizePath( '/foo/bar?a%2Ca=5,5&a,b=1,1' );
expect( ab ).toBe( '/foo/bar?a%2Ca=5%2C5&a%2Cb=1%2C1' );
} );

it( 'should not blow up on malformed params', () => {
const path = '/foo/bar?baz=%E0%A4%A';

expect( () => normalizePath( path ) ).not.toThrow();
expect( normalizePath( path ) ).toBe( '/foo/bar?baz=%25E0%25A4%25A' );
} );

it( 'returns a stable path when a param is malformed', () => {
const ab = normalizePath( '/foo/bar?a=5&b=50%off' );
const ba = normalizePath( '/foo/bar?b=50%off&a=5' );

expect( ab ).toBe( ba );
} );
} );
Loading