Skip to content

Commit

Permalink
feat: decode percent-encoded path in getPath
Browse files Browse the repository at this point in the history
  • Loading branch information
usualoma committed May 16, 2024
1 parent d87d996 commit f79832d
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 7 deletions.
53 changes: 49 additions & 4 deletions benchmarks/utils/src/get-path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,60 @@ bench('noop', () => {})
const request = new Request('http://localhost/about/me')

group('getPath', () => {
bench('slice + indexOf', () => {
bench('slice + indexOf : w/o decodeURI', () => {
const url = request.url
const queryIndex = url.indexOf('?', 8)
url.slice(url.indexOf('/', 8), queryIndex === -1 ? undefined : queryIndex)
return url.slice(url.indexOf('/', 8), queryIndex === -1 ? undefined : queryIndex)
})

bench('regexp', () => {
bench('regexp : w/o decodeURI', () => {
const match = request.url.match(/^https?:\/\/[^/]+(\/[^?]*)/)
match ? match[1] : ''
return match ? match[1] : ''
})

bench('slice + indexOf', () => {
const url = request.url
const queryIndex = url.indexOf('?', 8)
const path = url.slice(url.indexOf('/', 8), queryIndex === -1 ? undefined : queryIndex)
return path.includes('%') ? decodeURIComponent(path) : path
})

bench('slice + for-loop + flag', () => {
const url = request.url
let start = url.indexOf('/', 8)
let i = start
let hasPercentEncoding = false
for (; i < url.length; i++) {
const charCode = url.charCodeAt(i)
if (charCode === 37) {
// '%'
hasPercentEncoding = true
} else if (charCode === 63) {
// '?'
break
}
}
return hasPercentEncoding ? decodeURIComponent(url.slice(start, i)) : url.slice(start, i)
})

bench('slice + for-loop + immediate return', () => {
const url = request.url
const start = url.indexOf('/', 8)
let i = start
for (; i < url.length; i++) {
const charCode = url.charCodeAt(i)
if (charCode === 37) {
// '%'
// If the path contains percent encoding, use `indexOf()` to find '?' and return the result immediately.
// Although this is a performance disadvantage, it is acceptable since we prefer cases that do not include percent encoding.
const queryIndex = url.indexOf('?', i)
return decodeURIComponent(url.slice(start, queryIndex === -1 ? undefined : queryIndex))
} else if (charCode === 63) {
// '?'
break
}
}
return url.slice(start, i)
})
})

Expand Down
19 changes: 16 additions & 3 deletions src/utils/url.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,23 @@ export const getPattern = (label: string): Pattern | null => {
}

export const getPath = (request: Request): string => {
// Optimized: indexOf() + slice() is faster than RegExp
const url = request.url
const queryIndex = url.indexOf('?', 8)
return url.slice(url.indexOf('/', 8), queryIndex === -1 ? undefined : queryIndex)
const start = url.indexOf('/', 8)
let i = start
for (; i < url.length; i++) {
const charCode = url.charCodeAt(i)
if (charCode === 37) {
// '%'
// If the path contains percent encoding, use `indexOf()` to find '?' and return the result immediately.
// Although this is a performance disadvantage, it is acceptable since we prefer cases that do not include percent encoding.
const queryIndex = url.indexOf('?', i)
return decodeURIComponent(url.slice(start, queryIndex === -1 ? undefined : queryIndex))
} else if (charCode === 63) {
// '?'
break
}
}
return url.slice(start, i)
}

export const getQueryStrings = (url: string): string => {
Expand Down

0 comments on commit f79832d

Please sign in to comment.