Skip to content

Commit 02c1d68

Browse files
committed
support indirect route-handlers for NodeJS
1 parent dafcd59 commit 02c1d68

File tree

3 files changed

+48
-4
lines changed

3 files changed

+48
-4
lines changed

javascript/ql/src/semmle/javascript/frameworks/NodeJSLib.qll

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,12 @@ module NodeJSLib {
228228
t.start() and
229229
result = handler.flow().getALocalSource()
230230
or
231-
exists(DataFlow::TypeBackTracker t2 | result = getARouteHandler(t2).backtrack(t2, t))
231+
exists(DataFlow::TypeBackTracker t2, DataFlow::SourceNode succ | succ = getARouteHandler(t2) |
232+
result = succ.backtrack(t2, t)
233+
or
234+
t = t2 and
235+
Express::routeHandlerStep(result, succ)
236+
)
232237
}
233238

234239
override Expr getServer() { result = server }
@@ -727,9 +732,6 @@ module NodeJSLib {
727732
or
728733
// heuristic: does not return anything (Node.js will not use the return value)
729734
exists(astNode.getAReturnStmt().getExpr())
730-
or
731-
// heuristic: is not invoked (Node.js invokes this at a call site we cannot reason precisely about)
732-
exists(DataFlow::InvokeNode cs | cs.getACallee() = astNode)
733735
)
734736
)
735737
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
var http = require('http');
2+
3+
function decorate(method) {
4+
return function(req, res) {
5+
return method.call(this, req, res);
6+
};
7+
}
8+
9+
function Server(routes) {
10+
this.routes = routes;
11+
}
12+
13+
Server.prototype = {
14+
requestHandler: function() {
15+
var routes = this.routes;
16+
return function(req, res) { // route handler
17+
var handler = routes[req.url] || routes['*'];
18+
19+
return handler.call(this, req, res);
20+
}.bind(this);
21+
},
22+
};
23+
24+
var routes = {
25+
'/foo/bar': decorate((req, res) => { // route handler
26+
res.end("foo");
27+
}),
28+
'/bar/foo': function(req, res) { // route handler
29+
res.end("bar");
30+
}
31+
};
32+
33+
var appServer = new Server(routes);
34+
var server = http.createServer(appServer.requestHandler());
35+
36+
server.listen(8080, () => {});

javascript/ql/test/library-tests/frameworks/NodeJSLib/tests.expected

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ test_isCreateServer
1010
| src/http.js:70:1:70:36 | http.cr ... dler()) |
1111
| src/https.js:4:14:10:2 | https.c ... foo;\\n}) |
1212
| src/https.js:12:1:16:2 | https.c ... r");\\n}) |
13+
| src/indirect.js:34:14:34:58 | http.cr ... dler()) |
1314
test_RequestInputAccess
1415
| src/http.js:6:26:6:32 | req.url | url | src/http.js:4:32:10:1 | functio ... .foo;\\n} |
1516
| src/http.js:8:3:8:20 | req.headers.cookie | cookie | src/http.js:4:32:10:1 | functio ... .foo;\\n} |
@@ -72,6 +73,7 @@ test_RouteSetup_getServer
7273
| src/http.js:70:1:70:36 | http.cr ... dler()) | src/http.js:70:1:70:36 | http.cr ... dler()) |
7374
| src/https.js:4:14:10:2 | https.c ... foo;\\n}) | src/https.js:4:14:10:2 | https.c ... foo;\\n}) |
7475
| src/https.js:12:1:16:2 | https.c ... r");\\n}) | src/https.js:12:1:16:2 | https.c ... r");\\n}) |
76+
| src/indirect.js:34:14:34:58 | http.cr ... dler()) | src/indirect.js:34:14:34:58 | http.cr ... dler()) |
7577
test_ClientRequest
7678
| src/http.js:18:1:18:30 | http.re ... uth" }) |
7779
| src/http.js:21:15:26:6 | http.re ... \\n }) |
@@ -94,6 +96,7 @@ test_ServerDefinition
9496
| src/http.js:70:1:70:36 | http.cr ... dler()) |
9597
| src/https.js:4:14:10:2 | https.c ... foo;\\n}) |
9698
| src/https.js:12:1:16:2 | https.c ... r");\\n}) |
99+
| src/indirect.js:34:14:34:58 | http.cr ... dler()) |
97100
test_HeaderAccess
98101
| src/http.js:9:3:9:17 | req.headers.foo | foo |
99102
| src/https.js:9:3:9:17 | req.headers.foo | foo |
@@ -159,6 +162,9 @@ test_RouteSetup_getARouteHandler
159162
| src/http.js:70:1:70:36 | http.cr ... dler()) | src/http.js:70:19:70:35 | getArrowHandler() |
160163
| src/https.js:4:14:10:2 | https.c ... foo;\\n}) | src/https.js:4:33:10:1 | functio ... .foo;\\n} |
161164
| src/https.js:12:1:16:2 | https.c ... r");\\n}) | src/https.js:12:20:16:1 | functio ... ar");\\n} |
165+
| src/indirect.js:34:14:34:58 | http.cr ... dler()) | src/indirect.js:14:19:21:3 | return of method requestHandler |
166+
| src/indirect.js:34:14:34:58 | http.cr ... dler()) | src/indirect.js:16:12:20:16 | functio ... d(this) |
167+
| src/indirect.js:34:14:34:58 | http.cr ... dler()) | src/indirect.js:34:32:34:57 | appServ ... ndler() |
162168
test_ClientRequest_getADataNode
163169
| src/http.js:27:16:27:73 | http.re ... POST'}) | src/http.js:50:16:50:22 | 'stuff' |
164170
| src/http.js:27:16:27:73 | http.re ... POST'}) | src/http.js:51:14:51:25 | 'more stuff' |

0 commit comments

Comments
 (0)