Merge pull request #20101 from mschwager/main

Fix #19294, Ruby NetHttpRequest improvements
This commit is contained in:
Tom Hvitved
2025-08-12 14:42:32 +02:00
committed by GitHub
4 changed files with 44 additions and 5 deletions

View File

@@ -0,0 +1,7 @@
---
category: fix
---
* Made the following changes to `NetHttpRequest`
* Adds `connectionNode`, like other Ruby HTTP clients
* Makes `requestNode` and `connectionNode` public so subclasses can use them
* Adds detection of `Net::HTTP.start`, a common way to make HTTP requests in Ruby

View File

@@ -12,38 +12,55 @@ private import codeql.ruby.DataFlow
/**
* A `Net::HTTP` call which initiates an HTTP request.
* ```ruby
* # one-off request
* Net::HTTP.get("http://example.com/")
* Net::HTTP.post("http://example.com/", "some_data")
* req = Net::HTTP.new("example.com")
* response = req.get("/")
*
* # connection re-use
* Net::HTTP.start("http://example.com") do |http|
* http.get("/")
* end
* ```
*/
class NetHttpRequest extends Http::Client::Request::Range instanceof DataFlow::CallNode {
private DataFlow::CallNode request;
private API::Node requestNode;
API::Node requestNode;
API::Node connectionNode;
private boolean returnsResponseBody;
NetHttpRequest() {
exists(string method |
request = requestNode.asSource() and
this = request
this = request and
requestNode = connectionNode.getReturn(method)
|
// Net::HTTP.get(...)
method in ["get", "get_response"] and
requestNode = API::getTopLevelMember("Net").getMember("HTTP").getReturn(method) and
connectionNode = API::getTopLevelMember("Net").getMember("HTTP") and
returnsResponseBody = true
or
// Net::HTTP.post(...).body
method in ["post", "post_form"] and
requestNode = API::getTopLevelMember("Net").getMember("HTTP").getReturn(method) and
connectionNode = API::getTopLevelMember("Net").getMember("HTTP") and
returnsResponseBody = false
or
// Net::HTTP.new(..).get(..).body
// Net::HTTP.start(..) do |http| http.get(..) end
method in [
"get", "get2", "request_get", "head", "head2", "request_head", "delete", "put", "patch",
"post", "post2", "request_post", "request"
] and
requestNode = API::getTopLevelMember("Net").getMember("HTTP").getInstance().getReturn(method) and
connectionNode =
[
API::getTopLevelMember("Net").getMember("HTTP").getInstance(),
API::getTopLevelMember("Net")
.getMember("HTTP")
.getMethod("start")
.getBlock()
.getParameter(0)
] and
returnsResponseBody = false
)
}

View File

@@ -46,6 +46,8 @@ httpRequests
| NetHttp.rb:16:6:16:19 | call to patch |
| NetHttp.rb:24:3:24:33 | call to get |
| NetHttp.rb:29:1:29:32 | call to post |
| NetHttp.rb:33:1:33:22 | call to request |
| NetHttp.rb:36:3:36:15 | call to get |
| OpenURI.rb:3:9:3:41 | call to open |
| OpenURI.rb:6:9:6:34 | call to open |
| OpenURI.rb:9:9:9:38 | call to open |
@@ -123,6 +125,8 @@ getFramework
| NetHttp.rb:16:6:16:19 | call to patch | Net::HTTP |
| NetHttp.rb:24:3:24:33 | call to get | Net::HTTP |
| NetHttp.rb:29:1:29:32 | call to post | Net::HTTP |
| NetHttp.rb:33:1:33:22 | call to request | Net::HTTP |
| NetHttp.rb:36:3:36:15 | call to get | Net::HTTP |
| OpenURI.rb:3:9:3:41 | call to open | OpenURI |
| OpenURI.rb:6:9:6:34 | call to open | OpenURI |
| OpenURI.rb:9:9:9:38 | call to open | OpenURI |
@@ -292,6 +296,9 @@ getAUrlPart
| NetHttp.rb:24:3:24:33 | call to get | NetHttp.rb:24:17:24:22 | domain |
| NetHttp.rb:24:3:24:33 | call to get | NetHttp.rb:24:29:24:32 | path |
| NetHttp.rb:29:1:29:32 | call to post | NetHttp.rb:29:16:29:18 | uri |
| NetHttp.rb:33:1:33:22 | call to request | NetHttp.rb:31:22:31:42 | "https://example.com" |
| NetHttp.rb:33:1:33:22 | call to request | NetHttp.rb:33:14:33:21 | root_get |
| NetHttp.rb:36:3:36:15 | call to get | NetHttp.rb:36:12:36:14 | "/" |
| OpenURI.rb:3:9:3:41 | call to open | OpenURI.rb:3:21:3:40 | "http://example.com" |
| OpenURI.rb:6:9:6:34 | call to open | OpenURI.rb:6:14:6:33 | "http://example.com" |
| OpenURI.rb:9:9:9:38 | call to open | OpenURI.rb:9:18:9:37 | "http://example.com" |

View File

@@ -27,3 +27,11 @@ end
get("example.com", "/").body
Net::HTTP.post(uri, "some_body") # note: response body not accessed
http = Net::HTTP.new("https://example.com")
root_get = Net::HTTP::Get.new("/")
http.request(root_get)
Net::HTTP.start("https://example.com") do |http|
http.get("/")
end