mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-10-20 20:30:24 +00:00
Match site redirects whose source has non-ASCII characters (#4689)
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"gitbook": patch
|
||||
---
|
||||
|
||||
Site redirects whose source path has accented or non-Latin characters now redirect visitors instead of returning 404.
|
||||
@@ -97,11 +97,11 @@ describe('fetchPageData', () => {
|
||||
|
||||
describe('resolveMissingPagePath', () => {
|
||||
function createRedirectContext(options: {
|
||||
siteRedirect?: { target: string; permanent?: boolean };
|
||||
siteRedirect?: { source?: string; target: string; permanent?: boolean };
|
||||
spaceRedirectPageId?: string;
|
||||
}) {
|
||||
const getSiteRedirectBySource = mock(async ({ source }: { source: string }) =>
|
||||
options.siteRedirect && source === '/old'
|
||||
options.siteRedirect && source === (options.siteRedirect.source ?? '/old')
|
||||
? {
|
||||
data: {
|
||||
target: options.siteRedirect.target,
|
||||
@@ -143,6 +143,24 @@ describe('resolveMissingPagePath', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('resolves a site redirect whose source has non-ASCII characters', async () => {
|
||||
const context = createRedirectContext({
|
||||
siteRedirect: {
|
||||
source: '/de/kategorien-hinzuf%C3%BCgen',
|
||||
target: 'https://docs.example.com/new',
|
||||
},
|
||||
});
|
||||
const pathname = normalizeURL(
|
||||
new URL('https://docs.example.com/de/kategorien-hinzufügen')
|
||||
).pathname.slice(1);
|
||||
|
||||
expect(await resolveMissingPagePath(context, pathname)).toEqual({
|
||||
type: 'redirect',
|
||||
destination: '/new',
|
||||
permanent: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('resolves a space redirect to a page', async () => {
|
||||
const context = createRedirectContext({ spaceRedirectPageId: page.id });
|
||||
|
||||
|
||||
@@ -186,7 +186,8 @@ export async function resolveMissingPagePath(
|
||||
|
||||
/**
|
||||
* Transform a pathname into a candidate source for site redirect matching.
|
||||
* We also encode each segment to handle special characters in redirects.
|
||||
* The pathname is already percent-encoded, so each segment is decoded before being encoded
|
||||
* again: redirect sources store special characters percent-encoded exactly once.
|
||||
*/
|
||||
function toSiteRedirectSourceCandidate(pathname: string): string {
|
||||
const normalized = withLeadingSlash(pathname);
|
||||
@@ -194,11 +195,19 @@ function toSiteRedirectSourceCandidate(pathname: string): string {
|
||||
normalized
|
||||
.slice(1)
|
||||
.split('/')
|
||||
.map((segment) => encodeURIComponent(segment))
|
||||
.map((segment) => encodeURIComponent(safeDecodeURIComponent(segment)))
|
||||
.join('/')
|
||||
);
|
||||
}
|
||||
|
||||
function safeDecodeURIComponent(segment: string): string {
|
||||
try {
|
||||
return decodeURIComponent(segment);
|
||||
} catch {
|
||||
return segment;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the page path from the params.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user