diff --git a/src/middleware/methodNotAllowedMiddleware.ts b/src/middleware/methodNotAllowedMiddleware.ts new file mode 100644 index 0000000..ea0459c --- /dev/null +++ b/src/middleware/methodNotAllowedMiddleware.ts @@ -0,0 +1,7 @@ +import type { Middleware } from './middleware'; + +export class MethodNotAllowedMiddleware implements Middleware { + handle(): Promise { + return Promise.resolve(new Response(undefined, { status: 405 })); + } +} diff --git a/src/routes/index.ts b/src/routes/index.ts index 5cdeda3..157adfa 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -1,5 +1,6 @@ import latestVersions from '../constants/latestVersions.json' assert { type: 'json' }; import { cached } from '../middleware/cacheMiddleware'; +import { MethodNotAllowedMiddleware } from '../middleware/methodNotAllowedMiddleware'; import { NotFoundMiddleware } from '../middleware/notFoundMiddleware'; import { OptionsMiddleware } from '../middleware/optionsMiddleware'; import { OriginMiddleware } from '../middleware/originMiddleware'; @@ -52,6 +53,8 @@ export function registerRoutes(router: Router): void { ]); router.get('*', [new NotFoundMiddleware()]); + + router.all('*', [new MethodNotAllowedMiddleware()]); } export * from './router'; diff --git a/src/routes/router.ts b/src/routes/router.ts index 2f8359a..c9cf507 100644 --- a/src/routes/router.ts +++ b/src/routes/router.ts @@ -17,6 +17,14 @@ export class Router { return this.itty.fetch(request, ctx); } + all(endpoint: string, middlewares: Middleware[]): void { + const middlewareChain = buildMiddlewareChain(middlewares); + + this.itty.all(endpoint, (req, ctx) => { + return callMiddlewareChain(middlewareChain, req, ctx); + }); + } + options(endpoint: string, middlewares: Middleware[]): void { const middlewareChain = buildMiddlewareChain(middlewares); diff --git a/tests/e2e/file.test.ts b/tests/e2e/file.test.ts index 2dea723..64ea892 100644 --- a/tests/e2e/file.test.ts +++ b/tests/e2e/file.test.ts @@ -172,6 +172,16 @@ describe('File Tests', () => { assert.strictEqual(body, '{ hello:'); }); + it('sends a 405 for anything other than GET or HEAD', async () => { + // Doesn't need to be all-inclusive + for (const method of ['POST', 'PATCH', 'DELETE', 'PROPFIND']) { + const res = await mf.dispatchFetch(`${url}`, { + method: method, + }); + assert.strictEqual(res.status, 405, method); + } + }); + // Cleanup Miniflare after(async () => mf.dispose()); });