diff options
| author | Yuriy Andamasov <yuriy@vyos.io> | 2026-07-22 16:11:16 +0300 |
|---|---|---|
| committer | Yuriy Andamasov <yuriy@vyos.io> | 2026-07-22 16:11:16 +0300 |
| commit | f1fc5d8d45242c3b259ce216c0705e828a51fb2a (patch) | |
| tree | b801641bf8d502254f3d4e8b9005e9c84dcedf96 /workers | |
| parent | cce3f36602e285a13efe02bf8906f871f04c5ada (diff) | |
| download | vyos-documentation-claude/html-handling-parity.tar.gz vyos-documentation-claude/html-handling-parity.zip | |
workers: html_handling none + worker index-mapping — RTD .html URL parity (smoke 307 fix)claude/html-handling-parity
Diffstat (limited to 'workers')
| -rw-r--r-- | workers/branch/src/index.ts | 11 | ||||
| -rw-r--r-- | workers/branch/test/content.test.ts | 95 | ||||
| -rw-r--r-- | workers/branch/wrangler.legacy.jsonc | 2 | ||||
| -rw-r--r-- | workers/branch/wrangler.rolling.jsonc | 2 | ||||
| -rw-r--r-- | workers/branch/wrangler.v14.jsonc | 2 | ||||
| -rw-r--r-- | workers/branch/wrangler.v15.jsonc | 2 |
6 files changed, 109 insertions, 5 deletions
diff --git a/workers/branch/src/index.ts b/workers/branch/src/index.ts index d955d166..e9342c26 100644 --- a/workers/branch/src/index.ts +++ b/workers/branch/src/index.ts @@ -38,7 +38,16 @@ export function withDocsHeaders( export default { async fetch(request: Request, env: Env): Promise<Response> { const url = new URL(request.url); - const resp = await env.ASSETS.fetch(request); + // With assets html_handling "none", the runtime serves explicit .html URLs directly + // but does NOT map a directory URL ("/foo/") to its index.html — the worker must map + // trailing-slash URLs to index.html itself to preserve ReadTheDocs URL parity. + let assetRequest = request; + if (url.pathname.endsWith("/")) { + const mapped = new URL(url); + mapped.pathname = url.pathname + "index.html"; + assetRequest = new Request(mapped, request); + } + const resp = await env.ASSETS.fetch(assetRequest); return withDocsHeaders(resp, url.pathname, env); }, } satisfies ExportedHandler<Env>; diff --git a/workers/branch/test/content.test.ts b/workers/branch/test/content.test.ts index fcf068da..807b1dd1 100644 --- a/workers/branch/test/content.test.ts +++ b/workers/branch/test/content.test.ts @@ -78,3 +78,98 @@ describe("default fetch entrypoint", () => { expect(resp.headers.get("Cache-Control")).toBe("no-store"); }); }); + +describe("directory-index mapping (html_handling \"none\", §3.2.3 amended 2026-07-22)", () => { + // Assets binding stub emulating html_handling:"none": exact-path lookups only — + // no extension inference and no directory auto-index. A bare "/foo/" therefore only + // resolves because the worker rewrites it to "/foo/index.html" before this runs, which + // is exactly the RTD-parity behavior under test. + const ASSET_MAP: Record<string, string> = { + "/en/rolling/index.html": "<html>root index</html>", + "/en/rolling/cli.html": "<html>cli page</html>", + "/en/rolling/guide/index.html": "<html>guide index</html>", + }; + + const makeAssetsEnv = (docsEnv: Env["DOCS_ENV"], seen: string[]): Env => ({ + ASSETS: { + fetch: async (req: Request) => { + seen.push(req.url); + const body = ASSET_MAP[new URL(req.url).pathname]; + return body === undefined + ? new Response("not found", { status: 404, headers: { "content-type": "text/html" } }) + : new Response(body, { headers: { "content-type": "text/html" } }); + }, + } as unknown as Fetcher, + DOCS_BUILD_SHA: "testsha", + DOCS_ENV: docsEnv, + }); + + it("trailing-slash directory URL is mapped to index.html → 200 + index content", async () => { + const seen: string[] = []; + const resp = await worker.fetch( + new Request("https://docs.vyos.io/en/rolling/"), + makeAssetsEnv("production", seen), + ); + expect(resp.status).toBe(200); + expect(await resp.text()).toBe("<html>root index</html>"); + // worker rewrote "/en/rolling/" → "/en/rolling/index.html" before hitting ASSETS + expect(seen).toEqual(["https://docs.vyos.io/en/rolling/index.html"]); + // 200 still carries the build stamp + the page cache class + expect(resp.headers.get("X-Docs-Build")).toBe("testsha"); + expect(resp.headers.get("Cache-Control")) + .toBe("public, max-age=0, s-maxage=300, must-revalidate"); + }); + + it("explicit .html URL is served directly — 200, never a 3xx redirect", async () => { + const seen: string[] = []; + const resp = await worker.fetch( + new Request("https://docs.vyos.io/en/rolling/cli.html"), + makeAssetsEnv("production", seen), + ); + expect(resp.status).toBe(200); + expect(resp.status).toBeLessThan(300); // no 307/308 for explicit .html paths + expect(await resp.text()).toBe("<html>cli page</html>"); + // passed through unmodified — the worker never rewrites explicit-file paths + expect(seen).toEqual(["https://docs.vyos.io/en/rolling/cli.html"]); + expect(resp.headers.get("X-Docs-Build")).toBe("testsha"); + expect(resp.headers.get("Cache-Control")) + .toBe("public, max-age=0, s-maxage=300, must-revalidate"); + }); + + it("explicit nested /folder/index.html is served directly → 200", async () => { + const seen: string[] = []; + const resp = await worker.fetch( + new Request("https://docs.vyos.io/en/rolling/guide/index.html"), + makeAssetsEnv("production", seen), + ); + expect(resp.status).toBe(200); + expect(await resp.text()).toBe("<html>guide index</html>"); + expect(seen).toEqual(["https://docs.vyos.io/en/rolling/guide/index.html"]); + expect(resp.headers.get("X-Docs-Build")).toBe("testsha"); + expect(resp.headers.get("Cache-Control")) + .toBe("public, max-age=0, s-maxage=300, must-revalidate"); + }); + + it("extensionless page path (no trailing slash) is not mapped → 404", async () => { + const seen: string[] = []; + const resp = await worker.fetch( + new Request("https://docs.vyos.io/en/rolling/cli"), + makeAssetsEnv("production", seen), + ); + expect(resp.status).toBe(404); + // passed through unmodified; html_handling:"none" does not infer ".html" + expect(seen).toEqual(["https://docs.vyos.io/en/rolling/cli"]); + // a 404 must never carry a cacheable page/asset class + expect(resp.headers.get("Cache-Control")).toBe("no-store"); + }); + + it("directory mapping preserves the original query string", async () => { + const seen: string[] = []; + const resp = await worker.fetch( + new Request("https://docs.vyos.io/en/rolling/?q=foo"), + makeAssetsEnv("production", seen), + ); + expect(resp.status).toBe(200); + expect(seen).toEqual(["https://docs.vyos.io/en/rolling/index.html?q=foo"]); + }); +}); diff --git a/workers/branch/wrangler.legacy.jsonc b/workers/branch/wrangler.legacy.jsonc index fd036ec5..aef5144e 100644 --- a/workers/branch/wrangler.legacy.jsonc +++ b/workers/branch/wrangler.legacy.jsonc @@ -8,7 +8,7 @@ "assets": { "directory": "../../dist/assets", // populated by CI (Task 3.2); html_handling per §3.2.3 "binding": "ASSETS", - "html_handling": "auto-trailing-slash", + "html_handling": "none", // "none" + worker index-mapping: RTD parity — explicit .html URLs must serve 200, never 307 (§3.2.3 amended 2026-07-22) "not_found_handling": "404-page", "run_worker_first": true }, diff --git a/workers/branch/wrangler.rolling.jsonc b/workers/branch/wrangler.rolling.jsonc index 4595a06a..7a6f646c 100644 --- a/workers/branch/wrangler.rolling.jsonc +++ b/workers/branch/wrangler.rolling.jsonc @@ -8,7 +8,7 @@ "assets": { "directory": "../../dist/assets", // populated by CI (Task 3.2); html_handling per §3.2.3 "binding": "ASSETS", - "html_handling": "auto-trailing-slash", + "html_handling": "none", // "none" + worker index-mapping: RTD parity — explicit .html URLs must serve 200, never 307 (§3.2.3 amended 2026-07-22) "not_found_handling": "404-page", "run_worker_first": true }, diff --git a/workers/branch/wrangler.v14.jsonc b/workers/branch/wrangler.v14.jsonc index 2c7310aa..fe758dd9 100644 --- a/workers/branch/wrangler.v14.jsonc +++ b/workers/branch/wrangler.v14.jsonc @@ -8,7 +8,7 @@ "assets": { "directory": "../../dist/assets", // populated by CI (Task 3.2); html_handling per §3.2.3 "binding": "ASSETS", - "html_handling": "auto-trailing-slash", + "html_handling": "none", // "none" + worker index-mapping: RTD parity — explicit .html URLs must serve 200, never 307 (§3.2.3 amended 2026-07-22) "not_found_handling": "404-page", "run_worker_first": true }, diff --git a/workers/branch/wrangler.v15.jsonc b/workers/branch/wrangler.v15.jsonc index 45098aee..f2a0d7a4 100644 --- a/workers/branch/wrangler.v15.jsonc +++ b/workers/branch/wrangler.v15.jsonc @@ -8,7 +8,7 @@ "assets": { "directory": "../../dist/assets", // populated by CI (Task 3.2); html_handling per §3.2.3 "binding": "ASSETS", - "html_handling": "auto-trailing-slash", + "html_handling": "none", // "none" + worker index-mapping: RTD parity — explicit .html URLs must serve 200, never 307 (§3.2.3 amended 2026-07-22) "not_found_handling": "404-page", "run_worker_first": true }, |
