Skip to content

Commit ca1fc44

Browse files
committed
Model the HTTPClient http client
1 parent 3a4ddc4 commit ca1fc44

File tree

5 files changed

+80
-0
lines changed

5 files changed

+80
-0
lines changed

ql/lib/codeql/ruby/frameworks/HTTPClients.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ private import codeql.ruby.frameworks.http_clients.Excon
77
private import codeql.ruby.frameworks.http_clients.Faraday
88
private import codeql.ruby.frameworks.http_clients.RestClient
99
private import codeql.ruby.frameworks.http_clients.HTTParty
10+
private import codeql.ruby.frameworks.http_clients.HTTPClient
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
private import ruby
2+
private import codeql.ruby.Concepts
3+
private import codeql.ruby.ApiGraphs
4+
5+
/**
6+
* A call that makes an HTTP request using `HTTPClient`.
7+
* ```ruby
8+
* HTTPClient.get("http://example.com").body
9+
* HTTPClient.get_content("http://example.com")
10+
* ```
11+
*/
12+
class HTTPClientRequest extends HTTP::Client::Request::Range {
13+
DataFlow::Node request;
14+
DataFlow::CallNode responseBody;
15+
16+
HTTPClientRequest() {
17+
exists(API::Node requestNode, string method |
18+
request = requestNode.getAnImmediateUse() and
19+
method in [
20+
"get", "head", "delete", "options", "post", "put", "trace", "get_content", "post_content"
21+
]
22+
|
23+
requestNode = API::getTopLevelMember("HTTPClient").getReturn(method) and
24+
(
25+
// The `get_content` and `post_content` methods return the response body as a string.
26+
// The other methods return a `HTTPClient::Message` object which has various methods
27+
// that return the response body.
28+
method in ["get_content", "post_content"] and responseBody = request
29+
or
30+
not method in ["get_content", "put_content"] and
31+
responseBody = requestNode.getAMethodCall(["body", "http_body", "content", "dump"])
32+
) and
33+
this = request.asExpr().getExpr()
34+
)
35+
}
36+
37+
override DataFlow::Node getResponseBody() { result = responseBody }
38+
39+
override string getFramework() { result = "HTTPClient" }
40+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
| HTTPClient.rb:3:9:3:45 | call to get | HTTPClient.rb:4:1:4:10 | call to body |
2+
| HTTPClient.rb:6:9:6:65 | call to post | HTTPClient.rb:7:1:7:13 | call to content |
3+
| HTTPClient.rb:9:9:9:64 | call to put | HTTPClient.rb:10:1:10:15 | call to http_body |
4+
| HTTPClient.rb:12:9:12:48 | call to delete | HTTPClient.rb:13:1:13:10 | call to dump |
5+
| HTTPClient.rb:15:9:15:46 | call to head | HTTPClient.rb:16:1:16:10 | call to body |
6+
| HTTPClient.rb:18:9:18:49 | call to options | HTTPClient.rb:19:1:19:13 | call to content |
7+
| HTTPClient.rb:21:9:21:47 | call to trace | HTTPClient.rb:22:1:22:15 | call to http_body |
8+
| HTTPClient.rb:24:9:24:53 | call to get_content | HTTPClient.rb:24:9:24:53 | call to get_content |
9+
| HTTPClient.rb:26:10:26:74 | call to post_content | HTTPClient.rb:26:10:26:74 | call to post_content |
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import codeql.ruby.frameworks.http_clients.HTTPClient
2+
import codeql.ruby.DataFlow
3+
4+
query DataFlow::Node httpClientRequests(HTTPClientRequest e) { result = e.getResponseBody() }
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
require "httpclient"
2+
3+
resp1 = HTTPClient.get("http://example.com/")
4+
resp1.body
5+
6+
resp2 = HTTPClient.post("http://example.com/", body: "some_data")
7+
resp2.content
8+
9+
resp3 = HTTPClient.put("http://example.com/", body: "some_data")
10+
resp3.http_body
11+
12+
resp5 = HTTPClient.delete("http://example.com/")
13+
resp5.dump
14+
15+
resp6 = HTTPClient.head("http://example.com/")
16+
resp6.body
17+
18+
resp7 = HTTPClient.options("http://example.com/")
19+
resp7.content
20+
21+
resp8 = HTTPClient.trace("http://example.com/")
22+
resp8.http_body
23+
24+
resp9 = HTTPClient.get_content("http://example.com/")
25+
26+
resp10 = HTTPClient.post_content("http://example.com/", body: "some_data")

0 commit comments

Comments
 (0)