@@ -36,18 +36,11 @@ module Koa {
36
36
/**
37
37
* A Koa route handler.
38
38
*/
39
- class RouteHandler extends HTTP:: Servers:: StandardRouteHandler , DataFlow:: ValueNode {
40
- Function function ;
41
-
42
- RouteHandler ( ) {
43
- function = astNode and
44
- any ( RouteSetup setup ) .getARouteHandler ( ) = this
45
- }
46
-
39
+ abstract class RouteHandler extends HTTP:: Servers:: StandardRouteHandler , DataFlow:: SourceNode {
47
40
/**
48
41
* Gets the parameter of the route handler that contains the context object.
49
42
*/
50
- Parameter getContextParameter ( ) { result = function .getParameter ( 0 ) }
43
+ Parameter getContextParameter ( ) { result = getAFunctionValue ( ) . getFunction ( ) .getParameter ( 0 ) }
51
44
52
45
/**
53
46
* Gets an expression that contains the "context" object of
@@ -70,6 +63,35 @@ module Koa {
70
63
* object of a route handler invocation.
71
64
*/
72
65
Expr getARequestOrContextExpr ( ) { result = getARequestExpr ( ) or result = getAContextExpr ( ) }
66
+
67
+ /**
68
+ * Gets a reference to a request parameter defined by this route handler.
69
+ */
70
+ DataFlow:: Node getARequestParameterAccess ( ) {
71
+ none ( ) // overriden in subclasses.
72
+ }
73
+
74
+ /**
75
+ * Gets the dataflow node that is given to a `RouteSetup` to register the handler.
76
+ */
77
+ abstract DataFlow:: SourceNode getRouteHandlerRegistration ( ) ;
78
+ }
79
+
80
+ /**
81
+ * A koa route handler registered directly with a route-setup.
82
+ * Like:
83
+ * ```JavaScript
84
+ * var route = require('koa-route');
85
+ * var app = new Koa();
86
+ * app.use((context, next) => {
87
+ * ...
88
+ * });
89
+ * ```
90
+ */
91
+ private class StandardRouteHandler extends RouteHandler {
92
+ StandardRouteHandler ( ) { any ( RouteSetup setup ) .getARouteHandler ( ) = this }
93
+
94
+ override DataFlow:: SourceNode getRouteHandlerRegistration ( ) { result = this }
73
95
}
74
96
75
97
/**
@@ -100,6 +122,77 @@ module Koa {
100
122
}
101
123
}
102
124
125
+ /**
126
+ * A Koa route handler registered using a routing library.
127
+ *
128
+ * Example of what that could look like:
129
+ * ```JavaScript
130
+ * const router = require('koa-router')();
131
+ * const Koa = require('koa');
132
+ * const app = new Koa();
133
+ * router.get('/', async (ctx, next) => {
134
+ * // route handler stuff
135
+ * });
136
+ * app.use(router.routes());
137
+ * ```
138
+ */
139
+ private class RoutedRouteHandler extends RouteHandler , DataFlow:: SourceNode {
140
+ DataFlow:: InvokeNode router ;
141
+ DataFlow:: MethodCallNode call ;
142
+
143
+ RoutedRouteHandler ( ) {
144
+ router = DataFlow:: moduleImport ( [ "@koa/router" , "koa-router" ] ) .getAnInvocation ( ) and
145
+ call = router .getAMethodCall * ( ) and
146
+ call .getMethodName ( ) =
147
+ [
148
+ "use" , "get" , "post" , "put" , "link" , "unlink" , "delete" , "del" , "head" , "options" ,
149
+ "patch" , "all"
150
+ ] and
151
+ this .flowsTo ( call .getArgument ( any ( int i | i >= 1 ) ) )
152
+ }
153
+
154
+ override DataFlow:: SourceNode getRouteHandlerRegistration ( ) {
155
+ result = call
156
+ or
157
+ result = router .getAMethodCall ( "routes" )
158
+ }
159
+ }
160
+
161
+ /**
162
+ * A route handler registered using the `koa-route` library.
163
+ *
164
+ * Example of how `koa-route` can be used:
165
+ * ```JavaScript
166
+ * var route = require('koa-route');
167
+ * var Koa = require('koa');
168
+ * var app = new Koa();
169
+ *
170
+ * app.use(route.get('/pets', (context, param1, param2, param3, ...params) => {
171
+ * // route handler stuff
172
+ * }));
173
+ */
174
+ class KoaRouteHandler extends RouteHandler , DataFlow:: SourceNode {
175
+ DataFlow:: CallNode call ;
176
+
177
+ KoaRouteHandler ( ) {
178
+ call =
179
+ DataFlow:: moduleMember ( "koa-route" ,
180
+ [
181
+ "all" , "acl" , "bind" , "checkout" , "connect" , "copy" , "delete" , "del" , "get" , "head" ,
182
+ "link" , "lock" , "msearch" , "merge" , "mkactivity" , "mkcalendar" , "mkcol" , "move" ,
183
+ "notify" , "options" , "patch" , "post" , "propfind" , "proppatch" , "purge" , "put" , "rebind" ,
184
+ "report" , "search" , "subscribe" , "trace" , "unbind" , "unlink" , "unlock" , "unsubscribe"
185
+ ] ) .getACall ( ) and
186
+ this .flowsTo ( call .getArgument ( 1 ) )
187
+ }
188
+
189
+ override DataFlow:: Node getARequestParameterAccess ( ) {
190
+ result = call .getABoundCallbackParameter ( 1 , any ( int i | i >= 1 ) )
191
+ }
192
+
193
+ override DataFlow:: SourceNode getRouteHandlerRegistration ( ) { result = call }
194
+ }
195
+
103
196
/**
104
197
* A Koa request source, that is, an access to the `request` property
105
198
* of a context object.
@@ -189,6 +282,9 @@ module Koa {
189
282
kind = "parameter" and
190
283
this = getAQueryParameterAccess ( rh )
191
284
or
285
+ kind = "parameter" and
286
+ this = rh .getARequestParameterAccess ( )
287
+ or
192
288
exists ( Expr e | rh .getARequestOrContextExpr ( ) = e |
193
289
// `ctx.request.url`, `ctx.request.originalUrl`, or `ctx.request.href`
194
290
exists ( string propName |
@@ -202,6 +298,10 @@ module Koa {
202
298
propName = "href"
203
299
)
204
300
or
301
+ // params, when handler is registered by `koa-router` or similar.
302
+ kind = "parameter" and
303
+ this .asExpr ( ) .( PropAccess ) .accesses ( e , "params" )
304
+ or
205
305
// `ctx.request.body`
206
306
e instanceof RequestExpr and
207
307
kind = "body" and
@@ -285,7 +385,13 @@ module Koa {
285
385
getMethodName ( ) = "use"
286
386
}
287
387
288
- override DataFlow:: SourceNode getARouteHandler ( ) { result .flowsToExpr ( getArgument ( 0 ) ) }
388
+ override DataFlow:: SourceNode getARouteHandler ( ) {
389
+ // `StandardRouteHandler` uses this predicate in it's charpred, so making this predicate return a `RouteHandler` would give an empty recursion.
390
+ result .flowsToExpr ( getArgument ( 0 ) )
391
+ or
392
+ // For the route-handlers that does not depend on this predicate in their charpred.
393
+ result .( RouteHandler ) .getRouteHandlerRegistration ( ) .flowsToExpr ( getArgument ( 0 ) )
394
+ }
289
395
290
396
override Expr getServer ( ) { result = server }
291
397
}
0 commit comments