Skip to content

Commit 99a6195

Browse files
committed
Use const instead of let.
Update dependencies. Fix typos in the readme. Code cleanup to clarify different matcher purposes. Fixed wildCardRouteMatcher to match whole URL. Was missing the beginning match token.
1 parent 00cd5dd commit 99a6195

File tree

6 files changed

+562
-276
lines changed

6 files changed

+562
-276
lines changed

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Fastify Allow Plugin
2-
The HTTP 1.1 specification has an [`Allow` header](https://datatracker.ietf.org/doc/html/rfc7231#section-7.4.1) for resources to include in client responses, indicating all the methods the resource supports. All resource requests return the `Allow` header so client develpers can discover all of the allowable methods on the resource. If a resource does not support a method, for instance, `DELETE`, then the response status will be `405 Not Allowed` along with the `Allow` header.
2+
The HTTP 1.1 specification has an [`Allow` header](https://datatracker.ietf.org/doc/html/rfc7231#section-7.4.1) for resources to include in client responses, indicating all the methods the resource supports. All resource requests return the `Allow` header so client developers can discover all the allowable methods on the resource. If a resource does not support a method, for instance, `DELETE`, then the response status will be `405 Not Allowed` along with the `Allow` header.
33

4-
This plugin adds an `Allow` header to all responses with routes that have registered handlers, regardless of the method they handle. It returns a `405 Not Allowed` response when a route has no supported method handler. This behaviour is different from Fastify's default behaviour, which is to return a `404 Not Found` for unhandled methodson a route.
4+
This plugin adds an `Allow` header to all responses with routes that have registered handlers, regardless of the method they handle. It returns a `405 Not Allowed` response when a route has no supported method handler. This behaviour is different from Fastify's default behaviour, which is to return a `404 Not Found` for unhandled methods on a route.
55

66
If a route has no registered method handlers, fastify-allow will send the usual `404 Not Found` response.
77

@@ -57,9 +57,9 @@ fastify.options('*', optionsHandler)
5757

5858
if `send405` is set to false, then `send405ForWildcard` is ignored.
5959

60-
| Option | Description | Default value |
61-
| -------------------- | ------------------------------------------------------------ | ------------- |
62-
| `send405` | Controls whether or not to send `405 Not Allowed` status codes for request that have handlers for other methods, just not the one being sent. | `true` |
60+
| Option | Description | Default value |
61+
|----------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|
62+
| `send405` | Controls whether or not to send `405 Not Allowed` status codes for request that have handlers for other methods, just not the one being sent. | `true` |
6363
| `send405ForWildcard` | Only applies when `send405` is true. Wildcard routes that have no non-wildcard route handlers will still return 405 `Not Allowed` for requests that have a matching wildcard handler. | `false` |
6464

6565

@@ -78,4 +78,4 @@ const allowOpts: AllowOptions = { send405: false, send405ForWildcard: true }
7878
fastify.register(allowPlugin, allowOpts)
7979

8080
// now register handlers
81-
```
81+
```

lib/index.js

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -41,29 +41,28 @@ function comparePaths(p1, p2) {
4141
function captureRouteMethod(caseSensitive, ignoreTrailingSlash, ctx, routeOptions) {
4242
const { send405ForWildcard, routeMethods } = ctx;
4343
const { method, url } = routeOptions;
44-
const wildcardPattern = url.replace(/\*/g, ".+");
45-
const isWildcard = wildcardPattern !== url;
46-
const pattern = wildcardPattern.replace(/\/:[^/]+/g, "/[^/]+");
47-
const flags = caseSensitive ? "" : "i";
48-
const trailingSlash = ignoreTrailingSlash ? "/?" : "";
49-
const urlMatcher = new RegExp(`^${pattern}${trailingSlash}$`, flags);
44+
const urlPattern = url.replace(/\*/g, ".+");
45+
const isWildcard = urlPattern !== url;
46+
const urlMatcher = buildUrlMatcher(urlPattern, caseSensitive, ignoreTrailingSlash);
5047
let urlMethods = routeMethods.get(url) || "";
5148
if (urlMethods) {
5249
urlMethods += ", ";
5350
}
5451
urlMethods += method;
55-
const wildcardMatcher = isWildcard ? new RegExp(wildcardPattern) : false;
56-
for (const [key, value] of routeMethods.entries()) {
57-
// 1. Is this url a wildcard url? Yes, are there urls that this one covers? Add method to their methods
58-
if (wildcardMatcher
59-
&& wildcardMatcher.test(key)
60-
&& !value.includes(method)) {
61-
routeMethods.set(key, `${value}, ${method}`);
52+
const wildcardRouteMatcher = isWildcard
53+
? new RegExp(`^${urlPattern}`)
54+
: false;
55+
for (const [aRoute, aRouteMethods] of routeMethods.entries()) {
56+
// 1. Is this url a wildcard route? Yes, are there urls that this one covers? Add method to their methods
57+
if (wildcardRouteMatcher
58+
&& wildcardRouteMatcher.test(aRoute)
59+
&& !aRouteMethods.includes(method)) {
60+
routeMethods.set(aRoute, `${aRouteMethods}, ${method}`);
6261
}
6362
// 2. Are any existing urls wildcards that cover this url? Add their missing methods to your methods.
64-
if (key.endsWith("*")
65-
&& url.startsWith(key.slice(0, key.length - 1))) {
66-
const otherMethods = value.split(", ");
63+
if (aRoute.endsWith("*")
64+
&& url.startsWith(aRoute.slice(0, aRoute.length - 1))) {
65+
const otherMethods = aRouteMethods.split(", ");
6766
urlMethods = otherMethods.reduce((acc, m) => {
6867
if (!acc.includes(m)) {
6968
acc = `${acc}, ${m}`;
@@ -77,9 +76,15 @@ function captureRouteMethod(caseSensitive, ignoreTrailingSlash, ctx, routeOption
7776
addSortedMatcher(ctx, urlMatcher, url);
7877
}
7978
}
79+
function buildUrlMatcher(wildcardPattern, caseSensitive, ignoreTrailingSlash) {
80+
const pattern = wildcardPattern.replace(/\/:[^/]+/g, "/[^/]+");
81+
const flags = caseSensitive ? "" : "i";
82+
const trailingSlash = ignoreTrailingSlash ? "/?" : "";
83+
return new RegExp(`^${pattern}${trailingSlash}$`, flags);
84+
}
8085
function handleRequest(ctx, request, reply, done) {
8186
const { routeMethods, matcherRoutes, send405 } = ctx;
82-
let { url, method, routerPath = findUrlRoute(matcherRoutes, url) || "" } = request;
87+
const { url, method, routerPath = findUrlRoute(matcherRoutes, url) || "" } = request;
8388
const methods = routeMethods.get(routerPath);
8489
if (methods) {
8590
reply.header("allow", methods);
@@ -116,7 +121,7 @@ function plugin(fastify, opts, done) {
116121
fastify.addHook("onRequest", (q, p, d) => handleRequest(ctx, q, p, d));
117122
done();
118123
}
119-
exports.default = fastify_plugin_1.default(plugin, {
124+
exports.default = (0, fastify_plugin_1.default)(plugin, {
120125
name: "fastify-allow",
121126
fastify: ">=3.x"
122127
});

0 commit comments

Comments
 (0)