File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -7,6 +7,14 @@ const MAX_VARIABLE_LENGTH = 1_000_000; // 1MB
77const MAX_TEMPLATE_EXPRESSIONS = 10_000 ;
88const MAX_REGEX_LENGTH = 1_000_000 ; // 1MB
99
10+ function safeDecode ( s : string ) : string {
11+ try {
12+ return decodeURIComponent ( s ) ;
13+ } catch {
14+ return s ;
15+ }
16+ }
17+
1018export class UriTemplate {
1119 /**
1220 * Returns true if the given string contains any URI template expressions.
@@ -302,8 +310,8 @@ export class UriTemplate {
302310 for ( const pair of queryPart . split ( '&' ) ) {
303311 const equalIndex = pair . indexOf ( '=' ) ;
304312 if ( equalIndex !== - 1 ) {
305- const key = decodeURIComponent ( pair . slice ( 0 , equalIndex ) ) ;
306- const value = decodeURIComponent ( pair . slice ( equalIndex + 1 ) ) ;
313+ const key = safeDecode ( pair . slice ( 0 , equalIndex ) ) ;
314+ const value = safeDecode ( pair . slice ( equalIndex + 1 ) ) ;
307315 queryParams . set ( key , value ) ;
308316 }
309317 }
Original file line number Diff line number Diff line change @@ -249,6 +249,12 @@ describe('UriTemplate', () => {
249249 expect ( match ) . toEqual ( { q : 'hello world' } ) ;
250250 expect ( template . variableNames ) . toEqual ( [ 'q' ] ) ;
251251 } ) ;
252+
253+ it ( 'should not throw on malformed percent-encoding in query parameters' , ( ) => {
254+ const template = new UriTemplate ( '/search{?q}' ) ;
255+ expect ( template . match ( '/search?q=100%' ) ) . toEqual ( { q : '100%' } ) ;
256+ expect ( template . match ( '/search?q=%ZZ' ) ) . toEqual ( { q : '%ZZ' } ) ;
257+ } ) ;
252258 } ) ;
253259
254260 describe ( 'security and edge cases' , ( ) => {
You can’t perform that action at this time.
0 commit comments