diff --git a/src/runtime/bake/DevServer.rs b/src/runtime/bake/DevServer.rs index a765e21ba6cb..6c3156d2eb4b 100644 --- a/src/runtime/bake/DevServer.rs +++ b/src/runtime/bake/DevServer.rs @@ -1737,13 +1737,14 @@ fn on_js_request(dev: &mut DevServer, req: &mut Request, resp: AnyResponse) { return; } - let route_bundle_index = - route_bundle::Index::init(u32::try_from(id & 0xFFFFFFFF).expect("int cast")); - let generation: u32 = u32::try_from(id >> 32).expect("int cast"); + let index = id as u32; + let generation = (id >> 32) as u32; - if route_bundle_index.get() as usize >= dev.route_bundles.len() { + // The URL can hold any u32 and `Index::init` asserts on `u32::MAX`: check the range first. + if index as usize >= dev.route_bundles.len() { return not_found(resp); } + let route_bundle_index = route_bundle::Index::init(index); let route_bundle = &dev.route_bundles[route_bundle_index.get() as usize]; if route_bundle.client_script_generation != generation diff --git a/test/bake/dev/html.test.ts b/test/bake/dev/html.test.ts index 978cfedcc886..f7cf08d3989c 100644 --- a/test/bake/dev/html.test.ts +++ b/test/bake/dev/html.test.ts @@ -373,6 +373,32 @@ devTest("error report endpoint blanks stray non-text bytes in reported frames", await dev.fetch("/").expect.toInclude("

Frame Bytes

"); }, }); + +devTest("client script route answers 404 when the route bundle index is out of range", { + files: { + "index.html": emptyHtmlFile({ + scripts: ["/script.ts"], + body: "

Client Script

", + }), + "script.ts": ` + console.log("client-script-marker"); + `, + }, + async test(dev) { + // `/_bun/client/{name}-{index}{generation}.js`: each hex group holds the four bytes of a u32. + const page = await dev.fetch("/").text(); + const [script, generation] = page.match(/\/_bun\/client\/index-[0-9a-f]{8}([0-9a-f]{8})\.js/) ?? []; + expect(script).toBeString(); + await dev.fetch(script).expect.toInclude("client-script-marker"); + + // `ffffffff` is the value that the index type reserves for "no index". + await dev.fetch(`/_bun/client/index-ffffffff${generation}.js`).expect404(); + await dev.fetch(`/_bun/client/index-feffffff${generation}.js`).expect404(); + + await dev.fetch("/").expect.toInclude("

Client Script

"); + }, +}); + devTest("editing a file imported from outside the project root hot-reloads", { // The Windows watcher does not watch files outside the project directory. skip: ["win32"],