Skip to content

Commit 9b914d1

Browse files
authored
Fix getProxyModeBasePath (#2896)
1 parent 3e11678 commit 9b914d1

File tree

5 files changed

+80
-34
lines changed

5 files changed

+80
-34
lines changed

.changeset/funny-clouds-cheat.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'gitbook': patch
3+
---
4+
5+
Fix getProxyModeBasePath that was computing incorrect base path in some scenarios

packages/gitbook/src/lib/paths.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,14 @@ export function removeTrailingSlash(path: string): string {
1818
export function removeLeadingSlash(path: string): string {
1919
return path.replace(/^\/+/, '');
2020
}
21+
22+
/**
23+
* Normalize a pathname to make it start with a slash
24+
*/
25+
export function normalizePathname(pathname: string): string {
26+
if (!pathname.startsWith('/')) {
27+
pathname = `/${pathname}`;
28+
}
29+
30+
return pathname;
31+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { describe, expect, it } from 'bun:test';
2+
import { getProxyModeBasePath } from './proxy';
3+
4+
describe('getProxyModeBasePath', () => {
5+
it('should return the base path for proxy mode (base = /, path = /)', () => {
6+
const input = new URL('https://example.com/docs');
7+
const resolved = { basePath: '/', pathname: '/' };
8+
expect(getProxyModeBasePath(input, resolved)).toEqual('/docs/');
9+
});
10+
11+
it('should return the base path for proxy mode (base = /, path = /hello/world)', () => {
12+
const input = new URL('https://example.com/docs/hello/world');
13+
const resolved = { basePath: '/', pathname: '/hello/world' };
14+
expect(getProxyModeBasePath(input, resolved)).toEqual('/docs/');
15+
});
16+
17+
it('should return the base path for proxy mode (base = /v1, path = /)', () => {
18+
const input = new URL('https://example.com/docs/v1');
19+
const resolved = { basePath: '/v1', pathname: '/' };
20+
expect(getProxyModeBasePath(input, resolved)).toEqual('/docs/v1/');
21+
});
22+
23+
it('should return the base path for proxy mode (base = /v1/, path = /)', () => {
24+
const input = new URL('https://example.com/docs/v1/');
25+
const resolved = { basePath: '/v1/', pathname: '/' };
26+
expect(getProxyModeBasePath(input, resolved)).toEqual('/docs/v1/');
27+
});
28+
29+
it('should return the base path for proxy mode (base = /v1, path = /hello/world)', () => {
30+
const input = new URL('https://example.com/docs/v1/hello/world');
31+
const resolved = { basePath: '/v1', pathname: '/hello/world' };
32+
expect(getProxyModeBasePath(input, resolved)).toEqual('/docs/v1/');
33+
});
34+
35+
it('should return the base path for proxy mode (base = /v1/, path = /hello/world)', () => {
36+
const input = new URL('https://example.com/docs/v1/hello/world');
37+
const resolved = { basePath: '/v1/', pathname: '/hello/world' };
38+
expect(getProxyModeBasePath(input, resolved)).toEqual('/docs/v1/');
39+
});
40+
});

packages/gitbook/src/lib/proxy.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import type { PublishedSiteContent } from '@gitbook/api';
2+
import { joinPath, normalizePathname, removeTrailingSlash } from './paths';
3+
4+
/**
5+
* Compute the final base path for a site served in proxy mode.
6+
* For e.g. if the input URL is `https://example.com/docs/v2/foo/bar` on which
7+
* the site is served at `https://example.com/docs` and the resolved base path is `/v2`
8+
* then the proxy site path would be `/docs/v2/`.
9+
*/
10+
export function getProxyModeBasePath(
11+
input: URL,
12+
resolved: Pick<PublishedSiteContent, 'basePath' | 'pathname'>
13+
): string {
14+
const inputPathname = new URL(input).pathname;
15+
const proxySitePath = inputPathname
16+
.replace(removeTrailingSlash(resolved.pathname), '')
17+
.replace(removeTrailingSlash(resolved.basePath), '');
18+
19+
const result = joinPath(normalizePathname(proxySitePath), resolved.basePath);
20+
return result.endsWith('/') ? result : `${result}/`;
21+
}

packages/gitbook/src/middleware.ts

Lines changed: 3 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
1-
import {
2-
type ContentAPITokenPayload,
3-
CustomizationThemeMode,
4-
GitBookAPI,
5-
type PublishedSiteContent,
6-
} from '@gitbook/api';
1+
import { type ContentAPITokenPayload, CustomizationThemeMode, GitBookAPI } from '@gitbook/api';
72
import { setContext, setTag } from '@sentry/nextjs';
83
import { getURLLookupAlternatives, normalizeURL } from '@v2/lib/data';
94
import assertNever from 'assert-never';
@@ -35,7 +30,8 @@ import {
3530
normalizeVisitorAuthURL,
3631
} from '@/lib/visitor-token';
3732

38-
import { joinPath } from './lib/paths';
33+
import { joinPath, normalizePathname } from '@/lib/paths';
34+
import { getProxyModeBasePath } from '@/lib/proxy';
3935

4036
export const config = {
4137
matcher:
@@ -854,15 +850,6 @@ function stripURLBasePath(url: URL, basePath: string): URL {
854850
return stripped;
855851
}
856852

857-
/** Normalize a pathname to make it start with a slash */
858-
function normalizePathname(pathname: string): string {
859-
if (!pathname.startsWith('/')) {
860-
pathname = `/${pathname}`;
861-
}
862-
863-
return pathname;
864-
}
865-
866853
function stripURLSearch(url: URL): URL {
867854
const stripped = new URL(url.toString());
868855
stripped.search = '';
@@ -918,21 +905,3 @@ function writeCookies<R extends NextResponse>(
918905

919906
return response;
920907
}
921-
922-
/**
923-
* Compute the final base path for a site served in proxy mode.
924-
* For e.g. if the input URL is `https://example.com/docs/v2/foo/bar` on which
925-
* the site is served at `https://example.com/docs` and the resolved base path is `/v2`
926-
* then the proxy site path would be `/docs/v2/`.
927-
*/
928-
function getProxyModeBasePath(
929-
input: URL,
930-
resolved: Pick<PublishedSiteContent, 'basePath' | 'pathname'>
931-
): string {
932-
const inputPathname = stripURLSearch(input).pathname;
933-
const proxySitePath = inputPathname
934-
.replace(resolved.pathname, '')
935-
.replace(resolved.basePath, '');
936-
937-
return joinPath(normalizePathname(proxySitePath), resolved.basePath);
938-
}

0 commit comments

Comments
 (0)