Skip to content

Commit cc48172

Browse files
committed
add support for events in http-proxy
1 parent ede1a40 commit cc48172

File tree

3 files changed

+59
-0
lines changed

3 files changed

+59
-0
lines changed

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,41 @@ private module HttpProxy {
5151

5252
override DataFlow::Node getADataNode() { none() }
5353
}
54+
55+
/**
56+
* Holds if an event handler for `event` has a HTTP request parameter at `req` and a HTTP response parameter at `res`.
57+
*/
58+
predicate routeHandlingEventHandler(string event, int req, int res) {
59+
event = ["start", "end"] and req = 0 and res = 1
60+
or
61+
event = ["proxyReq", "proxyRes", "econnreset"] and req = 1 and res = 2
62+
or
63+
event = "proxyReqWs" and req = 1 and res = -10 // -10 for non-existent.
64+
}
65+
66+
/**
67+
* An http proxy event handler.
68+
*/
69+
class ProxyListenerCallback extends NodeJSLib::RouteHandler, DataFlow::FunctionNode {
70+
string event;
71+
API::CallNode call;
72+
73+
ProxyListenerCallback() {
74+
call = any(CreateServerCall server).getReturn().getMember(["on", "once"]).getACall() and
75+
call.getParameter(0).getARhs().mayHaveStringValue(event) and
76+
this = call.getParameter(1).getARhs().getAFunctionValue()
77+
}
78+
79+
override Parameter getRequestParameter() {
80+
exists(int req | routeHandlingEventHandler(event, req, _) |
81+
result = getFunction().getParameter(req)
82+
)
83+
}
84+
85+
override Parameter getResponseParameter() {
86+
exists(int res | routeHandlingEventHandler(event, _, res) |
87+
result = getFunction().getParameter(res)
88+
)
89+
}
90+
}
5491
}

javascript/ql/test/library-tests/frameworks/NodeJSLib/src/http.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,14 @@ http.createServer(function (req, res) {
7373
req.on("data", chunk => { // RemoteFlowSource
7474
res.send(chunk);
7575
})
76+
});
77+
78+
var httpProxy = require('http-proxy');
79+
var proxy = httpProxy.createProxyServer({});
80+
81+
proxy.on('proxyReq', function(proxyReq, req, res, options) {
82+
req.on("data", chunk => { // RemoteFlowSource
83+
res.send(chunk);
84+
});
85+
res.end("bla");
7686
});

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ test_ResponseExpr
5656
| src/http.js:68:17:68:19 | res | src/http.js:68:12:68:27 | (req,res) => f() |
5757
| src/http.js:72:34:72:36 | res | src/http.js:72:19:76:1 | functio ... \\n })\\n} |
5858
| src/http.js:74:5:74:7 | res | src/http.js:72:19:76:1 | functio ... \\n })\\n} |
59+
| src/http.js:81:46:81:48 | res | src/http.js:81:22:86:1 | functio ... la");\\n} |
60+
| src/http.js:83:5:83:7 | res | src/http.js:81:22:86:1 | functio ... la");\\n} |
61+
| src/http.js:85:3:85:5 | res | src/http.js:81:22:86:1 | functio ... la");\\n} |
5962
| src/https.js:4:47:4:49 | res | src/https.js:4:33:10:1 | functio ... .foo;\\n} |
6063
| src/https.js:7:3:7:5 | res | src/https.js:4:33:10:1 | functio ... .foo;\\n} |
6164
| src/https.js:12:34:12:36 | res | src/https.js:12:20:16:1 | functio ... ar");\\n} |
@@ -150,6 +153,9 @@ test_RouteHandler_getAResponseExpr
150153
| src/http.js:68:12:68:27 | (req,res) => f() | src/http.js:68:17:68:19 | res |
151154
| src/http.js:72:19:76:1 | functio ... \\n })\\n} | src/http.js:72:34:72:36 | res |
152155
| src/http.js:72:19:76:1 | functio ... \\n })\\n} | src/http.js:74:5:74:7 | res |
156+
| src/http.js:81:22:86:1 | functio ... la");\\n} | src/http.js:81:46:81:48 | res |
157+
| src/http.js:81:22:86:1 | functio ... la");\\n} | src/http.js:83:5:83:7 | res |
158+
| src/http.js:81:22:86:1 | functio ... la");\\n} | src/http.js:85:3:85:5 | res |
153159
| src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:4:47:4:49 | res |
154160
| src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:7:3:7:5 | res |
155161
| src/https.js:12:20:16:1 | functio ... ar");\\n} | src/https.js:12:34:12:36 | res |
@@ -189,6 +195,7 @@ test_ResponseSendArgument
189195
| src/http.js:14:13:14:17 | "foo" | src/http.js:12:19:16:1 | functio ... ar");\\n} |
190196
| src/http.js:15:11:15:15 | "bar" | src/http.js:12:19:16:1 | functio ... ar");\\n} |
191197
| src/http.js:64:11:64:16 | "bar2" | src/http.js:62:19:65:1 | functio ... r2");\\n} |
198+
| src/http.js:85:11:85:15 | "bla" | src/http.js:81:22:86:1 | functio ... la");\\n} |
192199
| src/https.js:14:13:14:17 | "foo" | src/https.js:12:20:16:1 | functio ... ar");\\n} |
193200
| src/https.js:15:11:15:15 | "bar" | src/https.js:12:20:16:1 | functio ... ar");\\n} |
194201
| src/indirect.js:26:13:26:17 | "foo" | src/indirect.js:25:24:27:3 | (req, r ... ");\\n } |
@@ -235,6 +242,7 @@ test_RemoteFlowSources
235242
| src/http.js:40:23:40:30 | authInfo |
236243
| src/http.js:45:23:45:27 | error |
237244
| src/http.js:73:18:73:22 | chunk |
245+
| src/http.js:82:18:82:22 | chunk |
238246
| src/https.js:6:26:6:32 | req.url |
239247
| src/https.js:8:3:8:20 | req.headers.cookie |
240248
| src/https.js:9:3:9:17 | req.headers.foo |
@@ -273,6 +281,8 @@ test_RequestExpr
273281
| src/http.js:68:13:68:15 | req | src/http.js:68:12:68:27 | (req,res) => f() |
274282
| src/http.js:72:29:72:31 | req | src/http.js:72:19:76:1 | functio ... \\n })\\n} |
275283
| src/http.js:73:3:73:5 | req | src/http.js:72:19:76:1 | functio ... \\n })\\n} |
284+
| src/http.js:81:41:81:43 | req | src/http.js:81:22:86:1 | functio ... la");\\n} |
285+
| src/http.js:82:3:82:5 | req | src/http.js:81:22:86:1 | functio ... la");\\n} |
276286
| src/https.js:4:42:4:44 | req | src/https.js:4:33:10:1 | functio ... .foo;\\n} |
277287
| src/https.js:6:26:6:28 | req | src/https.js:4:33:10:1 | functio ... .foo;\\n} |
278288
| src/https.js:8:3:8:5 | req | src/https.js:4:33:10:1 | functio ... .foo;\\n} |
@@ -312,6 +322,8 @@ test_RouteHandler_getARequestExpr
312322
| src/http.js:68:12:68:27 | (req,res) => f() | src/http.js:68:13:68:15 | req |
313323
| src/http.js:72:19:76:1 | functio ... \\n })\\n} | src/http.js:72:29:72:31 | req |
314324
| src/http.js:72:19:76:1 | functio ... \\n })\\n} | src/http.js:73:3:73:5 | req |
325+
| src/http.js:81:22:86:1 | functio ... la");\\n} | src/http.js:81:41:81:43 | req |
326+
| src/http.js:81:22:86:1 | functio ... la");\\n} | src/http.js:82:3:82:5 | req |
315327
| src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:4:42:4:44 | req |
316328
| src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:6:26:6:28 | req |
317329
| src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:8:3:8:5 | req |

0 commit comments

Comments
 (0)