fulmine.js 5.19.6 → 5.19.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/declarative.js +9 -1
- package/src/node-shim.js +4 -1
- package/src/route.js +12 -13
- package/src/utils.js +20 -5
package/package.json
CHANGED
package/src/declarative.js
CHANGED
|
@@ -18,7 +18,7 @@ limitations under the License.
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
const acorn = require("acorn");
|
|
21
|
-
const { stringify, contentTypeSet, withUtf8Charset, contentTypeFor } = require("./utils.js");
|
|
21
|
+
const { stringify, contentTypeSet, withUtf8Charset, contentTypeFor, headerIsWritable } = require("./utils.js");
|
|
22
22
|
// H3App, DeclarativeResponse and _cfg exist at runtime but are missing from the .d.ts the
|
|
23
23
|
// package ships, so the module is read through a loose alias
|
|
24
24
|
const uWS = require("uWebSockets.js");
|
|
@@ -261,6 +261,11 @@ function readStatusAndHeaders(callExprs, headers) {
|
|
|
261
261
|
}
|
|
262
262
|
value = resolved;
|
|
263
263
|
}
|
|
264
|
+
// a name or a value setHeader refuses is an error page in express, not a header:
|
|
265
|
+
// left to the ordinary path, which throws it
|
|
266
|
+
if (!headerIsWritable(String(header), value)) {
|
|
267
|
+
return null;
|
|
268
|
+
}
|
|
264
269
|
const index = headers.findIndex((entry) => String(entry[0]).toLowerCase() === name);
|
|
265
270
|
if (index === -1) {
|
|
266
271
|
headers.push([header, value]);
|
|
@@ -280,6 +285,9 @@ function readStatusAndHeaders(callExprs, headers) {
|
|
|
280
285
|
if (call.arguments[0].type !== "Literal" || call.arguments[1].type !== "Literal") {
|
|
281
286
|
return null;
|
|
282
287
|
}
|
|
288
|
+
if (!headerIsWritable(String(call.arguments[0].value), String(call.arguments[1].value))) {
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
283
291
|
headers.push([call.arguments[0].value, String(call.arguments[1].value)]);
|
|
284
292
|
} else if (call.obj.propertyName === "sendStatus") {
|
|
285
293
|
if (call.arguments[0].type !== "Literal") {
|
package/src/node-shim.js
CHANGED
|
@@ -417,7 +417,10 @@ function serveNodeRequest(router, nodeReq, nodeRes, next) {
|
|
|
417
417
|
router._armAbort(shimRes, response);
|
|
418
418
|
|
|
419
419
|
return router._routeRequest(request, response).then((matched) => {
|
|
420
|
-
|
|
420
|
+
// a 404 after the head is out is left as it is, an error after it is not: it goes on to
|
|
421
|
+
// the final handler, which closes the connection as express's does. Same rule as the
|
|
422
|
+
// native path, see nativeDone in router-utils.js
|
|
423
|
+
if (matched || response.aborted || (response.headersSent && !request._error)) {
|
|
421
424
|
return;
|
|
422
425
|
}
|
|
423
426
|
if (next) {
|
package/src/route.js
CHANGED
|
@@ -120,20 +120,19 @@ class Route {
|
|
|
120
120
|
if (handle.length !== 4) {
|
|
121
121
|
return next(err);
|
|
122
122
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
handle(req, res, next);
|
|
134
|
-
} catch (thrown) {
|
|
135
|
-
next(thrown);
|
|
123
|
+
} else if (handle.length === 4) {
|
|
124
|
+
return next();
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
const out = err ? handle(err, req, res, next) : handle(req, res, next);
|
|
128
|
+
// a rejected promise goes to next() as the error it carries, as express's Layer
|
|
129
|
+
// does it. A bare rejection carries none and gets the one express invents. Thenable
|
|
130
|
+
// too, which express deprecates but still waits for
|
|
131
|
+
if (out && typeof out.then === "function") {
|
|
132
|
+
out.then(null, (thrown) => next(thrown || new Error("Rejected promise")));
|
|
136
133
|
}
|
|
134
|
+
} catch (thrown) {
|
|
135
|
+
next(thrown);
|
|
137
136
|
}
|
|
138
137
|
sync = 0;
|
|
139
138
|
};
|
package/src/utils.js
CHANGED
|
@@ -416,6 +416,10 @@ function patternToRegex(pattern, isPrefix = false, caseSensitive = true, strict
|
|
|
416
416
|
}
|
|
417
417
|
groupContent += pattern[i++];
|
|
418
418
|
}
|
|
419
|
+
// a group nobody closed, which express refuses rather than reading to the end
|
|
420
|
+
if (braceDepth > 0) {
|
|
421
|
+
throw new Error(`Unexpected end at index ${len}, expected }: ${pattern}`);
|
|
422
|
+
}
|
|
419
423
|
i++;
|
|
420
424
|
|
|
421
425
|
// When a :parameter precedes this group, that parameter is the one that gives ground
|
|
@@ -512,12 +516,12 @@ function patternToRegex(pattern, isPrefix = false, caseSensitive = true, strict
|
|
|
512
516
|
|
|
513
517
|
// these have no meaning in a path, and the route is refused rather than matching them
|
|
514
518
|
// literally: a path that quietly stops matching is worse than one that fails at startup.
|
|
515
|
-
// Escape them to use them as literals.
|
|
516
|
-
if ("?+()[]!".includes(ch)) {
|
|
519
|
+
// Escape them to use them as literals. A } here closes a group nobody opened.
|
|
520
|
+
if ("?+()[]!}".includes(ch)) {
|
|
517
521
|
throw new Error(`Unexpected ${ch} at index ${i}: ${pattern}`);
|
|
518
522
|
}
|
|
519
523
|
|
|
520
|
-
if (".^$|
|
|
524
|
+
if (".^$|".includes(ch)) {
|
|
521
525
|
regexPattern += "\\" + ch;
|
|
522
526
|
} else {
|
|
523
527
|
regexPattern += ch;
|
|
@@ -556,9 +560,20 @@ function escapePathLiteral(literal) {
|
|
|
556
560
|
return literal.replace(/[:*{}?+()[\]!.^$|\\]/g, "\\$&");
|
|
557
561
|
}
|
|
558
562
|
|
|
563
|
+
// Everything path-to-regexp gives a meaning to: a parameter, a wildcard, a group, a character it
|
|
564
|
+
// reserves, and the backslash that makes one of them literal. A dot or a dash is not in here, so
|
|
565
|
+
// the ordinary path stays a string compare.
|
|
566
|
+
const PATH_SYNTAX = /[:*{}?+()[\]!\\]/;
|
|
567
|
+
|
|
559
568
|
/**
|
|
560
569
|
* Whether a path has anything in it that a string comparison cannot answer, which is a parameter,
|
|
561
|
-
* a wildcard
|
|
570
|
+
* a wildcard, an optional group, or a reserved character. A regular expression is already
|
|
571
|
+
* compiled, so it needs nothing.
|
|
572
|
+
*
|
|
573
|
+
* The escapes are what the short list of three used to miss: "/\\(a\\)" is the way to ask for a
|
|
574
|
+
* literal parenthesis, and comparing it as text looked for the backslashes on the wire and
|
|
575
|
+
* answered 404. A reserved character written bare, "/(a)", has to reach the compiler too, which
|
|
576
|
+
* is what refuses it the way express does.
|
|
562
577
|
*
|
|
563
578
|
* @param {string|RegExp} pattern
|
|
564
579
|
* @returns {boolean}
|
|
@@ -568,7 +583,7 @@ function needsConversionToRegex(pattern) {
|
|
|
568
583
|
return false;
|
|
569
584
|
}
|
|
570
585
|
|
|
571
|
-
return
|
|
586
|
+
return PATH_SYNTAX.test(pattern);
|
|
572
587
|
}
|
|
573
588
|
|
|
574
589
|
/**
|