Skip to content

Commit f42d333

Browse files
committed
Ruby: Model Mime::Type
Add type summaries to recognise instances of Mime::Type, and recognise arguments to Mime::Type.match? and Mime::Type.=~ as regular expression interpretations.
1 parent b7be25e commit f42d333

File tree

4 files changed

+83
-0
lines changed

4 files changed

+83
-0
lines changed

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

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,55 @@
66
private import codeql.ruby.AST
77
private import codeql.ruby.Concepts
88
private import codeql.ruby.DataFlow
9+
private import codeql.ruby.Regexp as RE
10+
private import codeql.ruby.dataflow.FlowSummary
11+
private import codeql.ruby.frameworks.data.ModelsAsData
912

1013
/**
1114
* Models the `ActionDispatch` HTTP library, which is part of Rails.
1215
* Version: 7.1.0.
1316
*/
1417
module ActionDispatch {
18+
/**
19+
* Type summaries for the `Mime::Type` class, i.e. method calls that produce new
20+
* `Mime::Type` instances.
21+
*/
22+
private class MimeTypeTypeSummary extends ModelInput::TypeModelCsv {
23+
override predicate row(string row) {
24+
// package1;type1;package2;type2;path
25+
row =
26+
[
27+
// Mime[type] : Mime::Type (omitted)
28+
// Method names with brackets like [] cannot be represented in MaD.
29+
// Mime.fetch(type) : Mime::Type
30+
"actiondispatch;Mime::Type;;;Member[Mime].Method[fetch].ReturnValue",
31+
// Mime::Type.new(str) : Mime::Type
32+
"actiondispatch;Mime::Type;;;Member[Mime].Member[Type].Instance",
33+
// Mime::Type.lookup(str) : Mime::Type
34+
"actiondispatch;Mime::Type;;;Member[Mime].Member[Type].Method[lookup].ReturnValue",
35+
// Mime::Type.lookup_by_extension(str) : Mime::Type
36+
"actiondispatch;Mime::Type;;;Member[Mime].Member[Type].Method[lookup_by_extension].ReturnValue",
37+
// Mime::Type.register(str) : Mime::Type
38+
"actiondispatch;Mime::Type;;;Member[Mime].Member[Type].Method[register].ReturnValue",
39+
// Mime::Type.register_alias(str) : Mime::Type
40+
"actiondispatch;Mime::Type;;;Member[Mime].Member[Type].Method[register_alias].ReturnValue",
41+
]
42+
}
43+
}
44+
45+
/**
46+
* An argument to `Mime::Type#match?`, which is converted to a RegExp via
47+
* `Regexp.new`.
48+
*/
49+
class MimeTypeMatchRegExpInterpretation extends RE::RegExpInterpretation::Range {
50+
MimeTypeMatchRegExpInterpretation() {
51+
this =
52+
ModelOutput::getATypeNode("actiondispatch", "Mime::Type")
53+
.getAMethodCall(["match?", "=~"])
54+
.getArgument(0)
55+
}
56+
}
57+
1558
/**
1659
* Models routing configuration specified using the `ActionDispatch` library, which is part of Rails.
1760
*/

ruby/ql/test/library-tests/frameworks/ActionDispatch.expected

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,15 @@ underscore
5454
| HTTPServerRequest | httpserver_request |
5555
| LotsOfCapitalLetters | lots_of_capital_letters |
5656
| invalid | invalid |
57+
mimeTypeInstances
58+
| action_dispatch/mime_type.rb:2:6:2:28 | Use getMember("Mime").getMethod("fetch").getReturn() |
59+
| action_dispatch/mime_type.rb:3:6:3:32 | Use getMember("Mime").getMember("Type").getMethod("new").getReturn() |
60+
| action_dispatch/mime_type.rb:4:6:4:35 | Use getMember("Mime").getMember("Type").getMethod("lookup").getReturn() |
61+
| action_dispatch/mime_type.rb:5:6:5:43 | Use getMember("Mime").getMember("Type").getMethod("lookup_by_extension").getReturn() |
62+
| action_dispatch/mime_type.rb:6:6:6:47 | Use getMember("Mime").getMember("Type").getMethod("register").getReturn() |
63+
| action_dispatch/mime_type.rb:7:6:7:64 | Use getMember("Mime").getMember("Type").getMethod("register_alias").getReturn() |
64+
mimeTypeMatchRegExpInterpretations
65+
| action_dispatch/mime_type.rb:11:11:11:19 | "foo/bar" |
66+
| action_dispatch/mime_type.rb:12:7:12:15 | "foo/bar" |
67+
| action_dispatch/mime_type.rb:13:11:13:11 | s |
68+
| action_dispatch/mime_type.rb:14:7:14:7 | s |

ruby/ql/test/library-tests/frameworks/ActionDispatch.ql

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
private import ruby
22
private import codeql.ruby.frameworks.ActionDispatch
33
private import codeql.ruby.frameworks.ActionController
4+
private import codeql.ruby.ApiGraphs
5+
private import codeql.ruby.frameworks.data.ModelsAsData
6+
private import codeql.ruby.DataFlow
7+
private import codeql.ruby.Regexp as RE
48

59
query predicate actionDispatchRoutes(
610
ActionDispatch::Routing::Route r, string method, string path, string controller, string action
@@ -24,3 +28,13 @@ query predicate underscore(string input, string output) {
2428
"HTTPServerRequest", "LotsOfCapitalLetters"
2529
]
2630
}
31+
32+
query predicate mimeTypeInstances(API::Node n) {
33+
n = ModelOutput::getATypeNode("actiondispatch", "Mime::Type")
34+
}
35+
36+
query predicate mimeTypeMatchRegExpInterpretations(
37+
ActionDispatch::MimeTypeMatchRegExpInterpretation s
38+
) {
39+
any()
40+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
m1 = Mime["text/html"] # not recognised due to MaD limitation (can't parse method name)
2+
m2 = Mime.fetch("text/html")
3+
m3 = Mime::Type.new("text/html")
4+
m4 = Mime::Type.lookup("text/html")
5+
m5 = Mime::Type.lookup_by_extension("jpeg")
6+
m6 = Mime::Type.register("text/calendar", :ics)
7+
m7 = Mime::Type.register_alias("application/xml", :opf, %w(opf))
8+
9+
s = "foo/bar"
10+
11+
m2.match? "foo/bar"
12+
m3 =~ "foo/bar"
13+
m4.match? s
14+
m5 =~ s

0 commit comments

Comments
 (0)