Construct all public site redirects from PUBLIC_BASE and cover internal HTTP requests for bare, index, and directory canonicalization.
- commit
- 76f1c02f8db5532398510674cdaa46abbfe98b3d
- parent
- 930bc04a0db9b6e1cfc986bb0509da1d55a654f5
- author
- Dami <dami.etoile@gmail.com>
| M | worker/ | 23 | ++++++++++++++------ |
| M | worker/ | 34 | ++++++++++++++++++++++++++++++ |
@@ -45,10 +45,19 @@ function publicSiteHeaders(address: string): HeadersInit {
4545 };4646 }4747 48-function publicSiteRedirect(url: string, address: string): Response {48+function publicSiteRedirect(49+ env: Env,50+ pathname: string,51+ search: string,52+ address: string,53+): Response {54+ const url = new URL(env.PUBLIC_BASE);55+ url.pathname = pathname;56+ url.search = search;57+ url.hash = "";4958 return new Response(null, {5059 status: 302,51- headers: { location: url, ...publicSiteHeaders(address) },60+ headers: { location: url.toString(), ...publicSiteHeaders(address) },5261 });5362 }5463 @@ -244,7 +253,9 @@ export async function serve(
244253 if (m[2] === undefined) {245254 if (filePaths.length !== 1) {246255 return publicSiteRedirect(247- new URL(`/${addressStr}/`, url).toString(),256+ env,257+ `/${addressStr}/`,258+ url.search,248259 addressStr,249260 );250261 }@@ -263,15 +274,13 @@ export async function serve(
263274 const canonicalPath = isRootIndex && filePaths.length === 1264275 ? `/${addressStr}`265276 : path.slice(0, -"index.html".length);266- const canonicalUrl = new URL(canonicalPath, url);267- canonicalUrl.search = url.search;268- return publicSiteRedirect(canonicalUrl.toString(), addressStr);277+ return publicSiteRedirect(env, canonicalPath, url.search, addressStr);269278 }270279 271280 const entry = manifest.files[assetPath];272281 if (!entry && manifest.files[`${assetPath}/index.html`]) {273282 // Directory hit without trailing slash: redirect so relative URLs resolve.274- return publicSiteRedirect(new URL(`${path}/`, url).toString(), addressStr);283+ return publicSiteRedirect(env, `${path}/`, url.search, addressStr);275284 }276285 if (!entry) return htmlResponse(NOT_FOUND_PAGE, 404);277286 @@ -22,6 +22,7 @@ function envFor(files, siteOverrides = {}) {
2222 };2323 2424 return {25+ PUBLIC_BASE: "https://n.zip",2526 DB: {2627 prepare() {2728 return {@@ -86,6 +87,39 @@ test("nested index redirects to its directory", async () => {
8687 assert.equal(response.headers.get("location"), "https://n.zip/2f9b/docs/");8788 });8889 90+test("canonical redirects use the HTTPS public base instead of the request origin", async (t) => {91+ const cases = [92+ {93+ name: "bare multi-file address",94+ requestUrl: "http://internal/2f9b?mode=pwa",95+ files: { "index.html": html, "style.css": css },96+ location: "https://n.zip/2f9b/?mode=pwa",97+ },98+ {99+ name: "explicit index",100+ requestUrl: "http://internal/2f9b/index.html?mode=pwa",101+ files: { "index.html": html, "style.css": css },102+ location: "https://n.zip/2f9b/?mode=pwa",103+ },104+ {105+ name: "directory without trailing slash",106+ requestUrl: "http://internal/2f9b/docs?mode=pwa",107+ files: { "index.html": html, "docs/index.html": html },108+ location: "https://n.zip/2f9b/docs/?mode=pwa",109+ },110+ ];111+112+ for (const { name, requestUrl, files, location } of cases) {113+ await t.test(name, async () => {114+ const url = new URL(requestUrl);115+ const response = await serve(new Request(url), envFor(files), url);116+117+ assert.equal(response.status, 302);118+ assert.equal(response.headers.get("location"), location);119+ });120+ }121+});122+89123 test("canonical directory URL serves its index without redirecting", async () => {90124 const url = new URL("https://n.zip/2f9b/");91125 const response = await serve(