@@ -139,6 +139,8 @@ module Routing {
139
139
predicate mayResumeDispatch ( ) {
140
140
this .getLastChild ( ) .mayResumeDispatch ( )
141
141
or
142
+ isInMiddlewareSetup ( this )
143
+ or
142
144
exists ( this .( RouteHandler ) .getAContinuationInvocation ( ) )
143
145
or
144
146
// Leaf nodes that aren't functions are assumed to invoke their continuation
@@ -155,6 +157,8 @@ module Routing {
155
157
predicate definitelyResumesDispatch ( ) {
156
158
this .getLastChild ( ) .definitelyResumesDispatch ( )
157
159
or
160
+ isInMiddlewareSetup ( this )
161
+ or
158
162
exists ( this .( RouteHandler ) .getAContinuationInvocation ( ) )
159
163
or
160
164
this instanceof MkRouter
@@ -325,6 +329,19 @@ module Routing {
325
329
DataFlow:: Node getValueImplicitlyStoredInAccessPath ( int n , string path ) { none ( ) }
326
330
}
327
331
332
+ /**
333
+ * Holds if `node` is installed at a route handler that is declared to be a middleware setup,
334
+ * and is therefore assume to resume dispatch.
335
+ */
336
+ private predicate isInMiddlewareSetup ( Node node ) {
337
+ exists ( RouteSetup:: Range range |
338
+ node = getRouteSetupNode ( range ) and
339
+ range .isMiddlewareSetup ( )
340
+ )
341
+ or
342
+ isInMiddlewareSetup ( node .getParent ( ) )
343
+ }
344
+
328
345
/** Holds if `pred` and `succ` are adjacent siblings and `succ` is installed after `pred`. */
329
346
private predicate areSiblings ( Node pred , Node succ ) {
330
347
exists ( ValueNode:: Range base , int n |
@@ -612,6 +629,20 @@ module Routing {
612
629
* Holds if this route setup targets `router` and occurs at the given `cfgNode`.
613
630
*/
614
631
abstract predicate isInstalledAt ( Router:: Range router , ControlFlowNode cfgNode ) ;
632
+
633
+ /**
634
+ * Holds if this is a middleware setup, meaning dispatch will resume after the
635
+ * route handlers in this route setup have completed (usually meaning that they have returned a promise, which has resolved).
636
+ *
637
+ * This should only be overridden when the route setup itself determines whether subsequent
638
+ * route handlers are invoked afterwards.
639
+ * - For Express-like libraries, the route _handler_ determines whether to resume dispatch,
640
+ * based on whether the `next` callback is invoked. For such libraries, do not override `isMiddlewareSetup`.
641
+ * - For Fastify-like libraries, the route _setup_ determines whether to resume dispatch.
642
+ * For example, `.addHook()` will resume dispatch whereas `.get()` will not. `isMiddlewareSetup()` should thus
643
+ * hold for `.addHook()` but not for `.get()` calls.
644
+ */
645
+ predicate isMiddlewareSetup ( ) { none ( ) }
615
646
}
616
647
617
648
/**
@@ -892,10 +923,14 @@ module Routing {
892
923
* based on `Node::Range::getValueAtAccessPath`.
893
924
*/
894
925
private DataFlow:: Node getAnAccessPathRhs ( Node base , int n , string path ) {
895
- // Assigned in the body of a route handler function, whi
926
+ // Assigned in the body of a route handler function, which is a middleware
896
927
exists ( RouteHandler handler | base = handler |
897
928
result = AccessPath:: getAnAssignmentTo ( handler .getParameter ( n ) .ref ( ) , path ) and
898
- exists ( handler .getAContinuationInvocation ( ) )
929
+ (
930
+ exists ( handler .getAContinuationInvocation ( ) )
931
+ or
932
+ isInMiddlewareSetup ( handler )
933
+ )
899
934
)
900
935
or
901
936
// Implicit assignment contributed by framework model
0 commit comments