|
1 |
| -import { type ContentAPITokenPayload, CustomizationThemeMode, GitBookAPI } from '@gitbook/api'; |
| 1 | +import { |
| 2 | + type ContentAPITokenPayload, |
| 3 | + CustomizationThemeMode, |
| 4 | + GitBookAPI, |
| 5 | + type PublishedSiteContent, |
| 6 | +} from '@gitbook/api'; |
2 | 7 | import { setContext, setTag } from '@sentry/nextjs';
|
3 | 8 | import { getURLLookupAlternatives, normalizeURL } from '@v2/lib/data';
|
4 | 9 | import assertNever from 'assert-never';
|
@@ -181,7 +186,9 @@ export async function middleware(request: NextRequest) {
|
181 | 186 | headers.set('x-gitbook-origin-basepath', originBasePath);
|
182 | 187 | headers.set(
|
183 | 188 | 'x-gitbook-basepath',
|
184 |
| - mode === 'proxy' ? originBasePath : joinPath(originBasePath, resolved.basePath) |
| 189 | + mode === 'proxy' |
| 190 | + ? getProxyModeBasePath(inputURL, resolved) |
| 191 | + : joinPath(originBasePath, resolved.basePath) |
185 | 192 | );
|
186 | 193 | headers.set('x-gitbook-content-space', resolved.space);
|
187 | 194 | if ('site' in resolved) {
|
@@ -335,7 +342,10 @@ function getInputURL(request: NextRequest): {
|
335 | 342 | // to determine the site to serve.
|
336 | 343 | const xGitbookSite = request.headers.get('x-gitbook-site-url');
|
337 | 344 | if (xGitbookSite) {
|
338 |
| - mode = 'proxy'; |
| 345 | + return { |
| 346 | + mode: 'proxy', |
| 347 | + url: new URL(xGitbookSite), |
| 348 | + }; |
339 | 349 | }
|
340 | 350 |
|
341 | 351 | return { url, mode };
|
@@ -400,16 +410,8 @@ async function lookupSiteInSingleMode(url: URL): Promise<LookupResult> {
|
400 | 410 | * GITBOOK_MODE=proxy
|
401 | 411 | * When proxying a site on a different base URL.
|
402 | 412 | */
|
403 |
| -async function lookupSiteInProxy(request: NextRequest, _url: URL): Promise<LookupResult> { |
404 |
| - const rawSiteUrl = request.headers.get('x-gitbook-site-url'); |
405 |
| - if (!rawSiteUrl) { |
406 |
| - throw new Error( |
407 |
| - 'Missing x-gitbook-site-url header. It should be passed when using GITBOOK_MODE=proxy.' |
408 |
| - ); |
409 |
| - } |
410 |
| - |
411 |
| - const siteUrl = new URL(rawSiteUrl); |
412 |
| - return await lookupSiteInMultiMode(request, siteUrl); |
| 413 | +async function lookupSiteInProxy(request: NextRequest, url: URL): Promise<LookupResult> { |
| 414 | + return await lookupSiteInMultiMode(request, url); |
413 | 415 | }
|
414 | 416 |
|
415 | 417 | /**
|
@@ -916,3 +918,21 @@ function writeCookies<R extends NextResponse>(
|
916 | 918 |
|
917 | 919 | return response;
|
918 | 920 | }
|
| 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