Skip to content

Commit

Permalink
Prevent append of trailing slash in cases where path ends with a file…
Browse files Browse the repository at this point in the history
… extension (#66636)

### What

Skip adding trailing slash for file pattern like same origin urls

### Why

Fixes #66635

Next.js will not append trailing slash for file like pattern urls when
`trailingSlash` is enabled. This PR aligns the behavior of the metadata
trailing slash appending with next-server route handling.

---------

Co-authored-by: Jiachi Liu <inbox@huozhi.im>
  • Loading branch information
kshehadeh and huozhi committed Jun 11, 2024
1 parent 44661c2 commit 9728a35
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 2 deletions.
11 changes: 11 additions & 0 deletions packages/next/src/lib/metadata/resolvers/resolve-url.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,17 @@ describe('resolveAbsoluteUrlWithPathname', () => {
'https://example.com/foo?bar'
)
})

it('should not add trailing slash to relative url that matches file pattern', () => {
expect(resolver('/foo.html')).toBe('https://example.com/foo.html')
expect(resolver('/foo.html?q=v')).toBe('https://example.com/foo.html?q=v')
expect(resolver(new URL('/.well-known/bar.jpg', metadataBase))).toBe(
'https://example.com/.well-known/bar.jpg/'
)
expect(resolver(new URL('/foo.html', metadataBase))).toBe(
'https://example.com/foo.html'
)
})
})
})

Expand Down
20 changes: 18 additions & 2 deletions packages/next/src/lib/metadata/resolvers/resolve-url.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,13 @@ function resolveRelativeUrl(url: string | URL, pathname: string): string | URL {
return url
}

// The regex is matching logic from packages/next/src/lib/load-custom-routes.ts
const FILE_REGEX =
/^(?:\/((?!\.well-known(?:\/.*)?)(?:[^/]+\/)*[^/]+\.\w+))(\/?|$)/i
function isFilePattern(pathname: string): boolean {
return FILE_REGEX.test(pathname)
}

// Resolve `pathname` if `url` is a relative path the compose with `metadataBase`.
function resolveAbsoluteUrlWithPathname(
url: string | URL,
Expand All @@ -110,18 +117,27 @@ function resolveAbsoluteUrlWithPathname(
// - Doesn't have query
if (trailingSlash && !resolvedUrl.endsWith('/')) {
let isRelative = resolvedUrl.startsWith('/')
let isExternal = false
let hasQuery = resolvedUrl.includes('?')
let isExternal = false
let isFileUrl = false

if (!isRelative) {
try {
const parsedUrl = new URL(resolvedUrl)
isExternal =
metadataBase != null && parsedUrl.origin !== metadataBase.origin
isFileUrl = isFilePattern(parsedUrl.pathname)
} catch {
// If it's not a valid URL, treat it as external
isExternal = true
}
if (!isExternal && !hasQuery) return `${resolvedUrl}/`
if (
// Do not apply trailing slash for file like urls, aligning with the behavior with `trailingSlash`
!isFileUrl &&
!isExternal &&
!hasQuery
)
return `${resolvedUrl}/`
}
}

Expand Down

0 comments on commit 9728a35

Please sign in to comment.