Skip to content

Commit 84e8cba

Browse files
committed
Redesign 405 handling to not use notFoundHandler.
1 parent b0710e0 commit 84e8cba

File tree

5 files changed

+89
-146
lines changed

5 files changed

+89
-146
lines changed

lib/index.js

Lines changed: 20 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -25,35 +25,25 @@ function captureRouteMethod(caseSensitive, ignoreTrailingSlash, routeMethods, ma
2525
routeMethods.set(url, urlMethods);
2626
matcherMethods.set(urlMatcher, urlMethods);
2727
}
28-
function handleNotFound(matcherMethods, request, reply) {
29-
const { url, method } = request;
30-
const methods = findUrlMethods(matcherMethods, url);
31-
let statusCode, message, error;
32-
if (methods) {
33-
statusCode = 405;
34-
message = `${method} ${url} not allowed`;
35-
error = "Method Not Allowed";
36-
reply.header("allow", methods);
37-
}
38-
else {
39-
statusCode = 404;
40-
message = `Route ${method}:${url} not found`;
41-
error = "Not Found";
42-
}
43-
reply
44-
.code(statusCode)
45-
.send({
46-
message,
47-
error,
48-
statusCode
49-
});
50-
}
51-
function addAllowHeader(routeMethods, request, reply, done) {
52-
// @ts-ignore config does not have url in it's type declaration
53-
const { url } = reply.context.config;
54-
const methods = routeMethods.get(url);
28+
function handleRequest(routeMethods, matcherMethods, send405, request, reply, done) {
29+
const { url, method,
30+
// @ts-ignore request does not have context in it's type declaration
31+
context: { config: { url: path } } } = request;
32+
const methods = path
33+
? routeMethods.get(path)
34+
: findUrlMethods(matcherMethods, url);
5535
if (methods) {
5636
reply.header("allow", methods);
37+
if (send405 && !methods.includes(method)) {
38+
// send 405
39+
reply
40+
.code(405)
41+
.send({
42+
statusCode: 405,
43+
message: `${method} ${url} not allowed`,
44+
error: "Method Not Allowed"
45+
});
46+
}
5747
}
5848
done();
5949
}
@@ -65,15 +55,12 @@ function findUrlMethods(matcherMethods, url) {
6555
}
6656
}
6757
function plugin(fastify, opts, done) {
58+
const { send405 = true } = opts;
59+
const { caseSensitive = true, ignoreTrailingSlash = false } = fastify.initialConfig;
6860
const routeMethods = new Map();
6961
const matcherMethods = new Map();
70-
const { caseSensitive = true, ignoreTrailingSlash = false } = fastify.initialConfig;
7162
fastify.addHook("onRoute", (o) => captureRouteMethod(caseSensitive, ignoreTrailingSlash, routeMethods, matcherMethods, o));
72-
fastify.addHook("onRequest", (q, p, d) => addAllowHeader(routeMethods, q, p, d));
73-
const { send405 = true } = opts;
74-
if (send405) {
75-
fastify.setNotFoundHandler((q, p) => handleNotFound(matcherMethods, q, p));
76-
}
63+
fastify.addHook("onRequest", (q, p, d) => handleRequest(routeMethods, matcherMethods, send405, q, p, d));
7764
done();
7865
}
7966
exports.default = fastify_plugin_1.default(plugin, {

package-lock.json

Lines changed: 34 additions & 36 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "fastify-allow",
3-
"version": "1.1.2",
3+
"version": "1.1.3",
44
"description": "Fastify plugin that adds an Allow header with all registered methods to GET and HEAD responses. See https://datatracker.ietf.org/doc/html/rfc7231#section-7.4.1",
55
"main": "lib/index.js",
66
"types": "lib/index.d.ts",

src/index.ts

Lines changed: 34 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ function captureRouteMethod(caseSensitive: boolean,
1616
routeMethods: RouteMethodsMap,
1717
matcherMethods: MatcherMethodsMap,
1818
routeOptions: FastifyPluginOptions) {
19-
const {method, url} = routeOptions
19+
const { method, url } = routeOptions
2020
const pattern = url.replace(/\/:[^/]+/g, "/[^/]+")
2121
const flags = caseSensitive ? "" : "i"
2222
const trailingSlash = ignoreTrailingSlash ? "/?" : ""
@@ -40,43 +40,40 @@ function captureRouteMethod(caseSensitive: boolean,
4040
}
4141

4242

43-
function handleNotFound(matcherMethods: MatcherMethodsMap,
44-
request: FastifyRequest,
45-
reply: FastifyReply) {
46-
const {url, method} = request
47-
const methods = findUrlMethods(matcherMethods, url)
48-
let statusCode, message, error
49-
50-
if (methods) {
51-
statusCode = 405
52-
message = `${method} ${url} not allowed`
53-
error = "Method Not Allowed"
54-
reply.header("allow", methods)
55-
} else {
56-
statusCode = 404
57-
message = `Route ${method}:${url} not found`
58-
error = "Not Found"
59-
}
60-
61-
reply
62-
.code(statusCode)
63-
.send({
64-
message,
65-
error,
66-
statusCode
67-
})
68-
}
43+
function handleRequest(routeMethods: RouteMethodsMap,
44+
matcherMethods: MatcherMethodsMap,
45+
send405: boolean,
46+
request: FastifyRequest,
47+
reply: FastifyReply,
48+
done: () => void) {
49+
const {
50+
url,
51+
method,
52+
// @ts-ignore request does not have context in it's type declaration
53+
context: {
54+
config: {
55+
url: path
56+
}
57+
}
58+
} = request
6959

60+
const methods = path
61+
? routeMethods.get(path)
62+
: findUrlMethods(matcherMethods, url)
7063

71-
function addAllowHeader(routeMethods: RouteMethodsMap,
72-
request: FastifyRequest,
73-
reply: FastifyReply,
74-
done: () => void) {
75-
// @ts-ignore config does not have url in it's type declaration
76-
const {url} = reply.context.config
77-
const methods = routeMethods.get(url)
7864
if (methods) {
7965
reply.header("allow", methods)
66+
67+
if (send405 && !methods.includes(method)) {
68+
// send 405
69+
reply
70+
.code(405)
71+
.send({
72+
statusCode: 405,
73+
message: `${method} ${url} not allowed`,
74+
error: "Method Not Allowed"
75+
})
76+
}
8077
}
8178
done()
8279
}
@@ -95,15 +92,12 @@ function findUrlMethods(matcherMethods: MatcherMethodsMap,
9592
function plugin(fastify: FastifyInstance,
9693
opts: AllowOptions,
9794
done: () => void) {
95+
const { send405 = true } = opts
96+
const { caseSensitive = true, ignoreTrailingSlash = false } = fastify.initialConfig
9897
const routeMethods = new Map()
9998
const matcherMethods = new Map()
100-
const {caseSensitive = true, ignoreTrailingSlash = false} = fastify.initialConfig
10199
fastify.addHook("onRoute", (o) => captureRouteMethod(caseSensitive, ignoreTrailingSlash, routeMethods, matcherMethods, o))
102-
fastify.addHook("onRequest", (q, p, d) => addAllowHeader(routeMethods, q, p, d))
103-
const { send405 = true } = opts
104-
if (send405) {
105-
fastify.setNotFoundHandler((q, p) => handleNotFound(matcherMethods, q, p))
106-
}
100+
fastify.addHook("onRequest", (q, p, d) => handleRequest(routeMethods, matcherMethods, send405, q, p, d))
107101
done()
108102
}
109103

test/test.ts

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,42 +3,6 @@ import Fastify, {FastifyReply, FastifyRequest, LightMyRequestResponse} from "fas
33
import allowPlugin, {AllowOptions} from "../src"
44

55

6-
test("register without options", (t) => {
7-
t.plan(2)
8-
const app = Fastify()
9-
app.setNotFoundHandler = () => {
10-
t.pass("notFoundHandler set")
11-
return app
12-
}
13-
app.register(allowPlugin)
14-
app.ready(t.error)
15-
})
16-
17-
test("register with send405 options set to true", (t) => {
18-
t.plan(2)
19-
const app = Fastify()
20-
app.setNotFoundHandler = () => {
21-
t.pass("notFoundHandler set")
22-
return app
23-
}
24-
const opts: AllowOptions = {send405: true}
25-
app.register(allowPlugin, opts)
26-
app.ready(t.error)
27-
})
28-
29-
test("register with send405 options set to false", (t) => {
30-
t.plan(1)
31-
const app = Fastify()
32-
app.setNotFoundHandler = () => {
33-
t.fail("notFoundHandler should not be set")
34-
return app
35-
}
36-
const opts: AllowOptions = {send405: false}
37-
app.register(allowPlugin, opts)
38-
app.ready(t.error)
39-
})
40-
41-
426
test("request tests, default fastify options", (testGroup) => {
437
const app = Fastify()
448
const opts: AllowOptions = {send405: true}

0 commit comments

Comments
 (0)