From 2882247ad3bae6904066afc458ad7ae948b8e42a Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 29 Jul 2026 08:50:02 +0700 Subject: [PATCH] fix: add catch-all S3 route for path-style requests (/{bucket}/{key}) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bun's '/' route only matches root path '/'. S3 SDK clients using forcePathStyle:true send ALL requests to /{bucket}/{key} which never matched any route → 404. Added '/*' catch-all that checks for S3 auth headers before dispatching. Co-Authored-By: Claude Opus 5 (1M context) --- src/interfaces/http/routes/index.ts | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/interfaces/http/routes/index.ts b/src/interfaces/http/routes/index.ts index cc1ab80..f70751e 100644 --- a/src/interfaces/http/routes/index.ts +++ b/src/interfaces/http/routes/index.ts @@ -127,6 +127,35 @@ export const routes = { POST: handleS3Direct, OPTIONS: handleS3Direct, }, + // Catch-all for S3 path-style requests (/{bucket}/{key} ...) + // Only intercepts requests with S3 auth headers; others get 404. + '/*': { + GET: (req: Request): Promise => { + if (shouldHandleS3(req, Object.fromEntries(req.headers))) return handleS3Direct(req); + return Promise.resolve(new Response('Not Found', { status: 404 })); + }, + PUT: (req: Request): Promise => { + if (shouldHandleS3(req, Object.fromEntries(req.headers))) return handleS3Direct(req); + return Promise.resolve(new Response('Not Found', { status: 404 })); + }, + HEAD: (req: Request): Promise => { + if (shouldHandleS3(req, Object.fromEntries(req.headers))) return handleS3Direct(req); + return Promise.resolve(new Response('Not Found', { status: 404 })); + }, + DELETE: (req: Request): Promise => { + if (shouldHandleS3(req, Object.fromEntries(req.headers))) return handleS3Direct(req); + return Promise.resolve(new Response('Not Found', { status: 404 })); + }, + POST: (req: Request): Promise => { + if (shouldHandleS3(req, Object.fromEntries(req.headers))) return handleS3Direct(req); + return Promise.resolve(new Response('Not Found', { status: 404 })); + }, + PATCH: (req: Request): Promise => { + if (shouldHandleS3(req, Object.fromEntries(req.headers))) return handleS3Direct(req); + return Promise.resolve(new Response('Not Found', { status: 404 })); + }, + OPTIONS: handleS3Direct, + }, '/api/v1/auth/login': { POST: withRateLimit(handleLogin), },