@@ -7,19 +7,40 @@ private import codeql.ruby.DataFlow
7
7
private import codeql.ruby.typetracking.TypeTracker
8
8
private import Response:: Private as RP
9
9
10
- /** A method node for a method named `call`. */
11
- private class CallMethodNode extends DataFlow:: MethodNode {
12
- CallMethodNode ( ) { this .getMethodName ( ) = "call" }
10
+ /**
11
+ * A callable node that takes a single argument and, if it has a method name,
12
+ * is called "call".
13
+ */
14
+ private class PotentialCallNode extends DataFlow:: CallableNode {
15
+ PotentialCallNode ( ) {
16
+ this .getNumberOfParameters ( ) = 1 and
17
+ (
18
+ this .( DataFlow:: MethodNode ) .getMethodName ( ) = "call" or
19
+ not this instanceof DataFlow:: MethodNode
20
+ )
21
+ }
22
+ }
23
+
24
+ /**
25
+ * A callable node that looks like it implements the rack specification.
26
+ */
27
+ private class CallNode extends PotentialCallNode {
28
+ private RP:: PotentialResponseNode resp ;
29
+
30
+ CallNode ( ) { resp = trackRackResponse ( this ) }
31
+
32
+ /** Gets the response returned from a request to this application. */
33
+ RP:: PotentialResponseNode getResponse ( ) { result = resp }
13
34
}
14
35
15
- private DataFlow:: LocalSourceNode trackRackResponse ( TypeBackTracker t , CallMethodNode call ) {
36
+ private DataFlow:: LocalSourceNode trackRackResponse ( TypeBackTracker t , DataFlow :: CallableNode call ) {
16
37
t .start ( ) and
17
38
result = call .getAReturnNode ( ) .getALocalSource ( )
18
39
or
19
40
exists ( TypeBackTracker t2 | result = trackRackResponse ( t2 , call ) .backtrack ( t2 , t ) )
20
41
}
21
42
22
- private RP:: PotentialResponseNode trackRackResponse ( CallMethodNode call ) {
43
+ private RP:: PotentialResponseNode trackRackResponse ( DataFlow :: CallableNode call ) {
23
44
result = trackRackResponse ( TypeBackTracker:: end ( ) , call )
24
45
}
25
46
@@ -28,12 +49,13 @@ private RP::PotentialResponseNode trackRackResponse(CallMethodNode call) {
28
49
*/
29
50
module App {
30
51
/**
52
+ * DEPRECATED: Use `App` instead.
31
53
* A class that may be a rack application.
32
54
* This is a class that has a `call` method that takes a single argument
33
55
* (traditionally called `env`) and returns a rack-compatible response.
34
56
*/
35
- class AppCandidate extends DataFlow:: ClassNode {
36
- private CallMethodNode call ;
57
+ deprecated class AppCandidate extends DataFlow:: ClassNode {
58
+ private CallNode call ;
37
59
private RP:: PotentialResponseNode resp ;
38
60
39
61
AppCandidate ( ) {
@@ -50,4 +72,61 @@ module App {
50
72
/** Gets the response returned from a request to this application. */
51
73
RP:: PotentialResponseNode getResponse ( ) { result = resp }
52
74
}
75
+
76
+ private newtype TApp =
77
+ TClassApp ( DataFlow:: ClassNode cn , CallNode call ) or
78
+ TAnonymousApp ( CallNode call )
79
+
80
+ /**
81
+ * A rack application. This is either some object that responds to `call`
82
+ * taking a single argument and returns a rack response, or a lambda or
83
+ * proc that takes a single `env` argument and returns a rack response.
84
+ */
85
+ abstract class App extends TApp {
86
+ string toString ( ) { result = "Rack application" }
87
+
88
+ abstract CallNode getCall ( ) ;
89
+
90
+ RP:: PotentialResponseNode getResponse ( ) { result = this .getCall ( ) .getResponse ( ) }
91
+
92
+ DataFlow:: ParameterNode getEnv ( ) { result = this .getCall ( ) .getParameter ( 0 ) }
93
+ }
94
+
95
+ /**
96
+ * A rack application using a `DataFlow::ClassNode`. The class has either
97
+ * an instance method or a singleton method named "call" which takes a
98
+ * single `env` argument and returns a rack response.
99
+ */
100
+ private class ClassApp extends TApp , App {
101
+ private DataFlow:: ClassNode cn ;
102
+ private CallNode call ;
103
+
104
+ ClassApp ( ) {
105
+ this = TClassApp ( cn , call ) and
106
+ call = [ cn .getInstanceMethod ( "call" ) , cn .getSingletonMethod ( "call" ) ]
107
+ }
108
+
109
+ override string toString ( ) { result = "Rack application: " + cn .toString ( ) }
110
+
111
+ override CallNode getCall ( ) { result = call }
112
+ }
113
+
114
+ /**
115
+ * A rack application that is either a lambda or a proc, which takes a
116
+ * single `env` argument and returns a rack response.
117
+ */
118
+ private class AnonymousApp extends TApp , App {
119
+ private CallNode call ;
120
+
121
+ AnonymousApp ( ) {
122
+ this = TAnonymousApp ( call ) and
123
+ not exists ( DataFlow:: ClassNode cn |
124
+ call = [ cn .getInstanceMethod ( _) , cn .getSingletonMethod ( _) ]
125
+ )
126
+ }
127
+
128
+ override string toString ( ) { result = "Rack application: " + call .toString ( ) }
129
+
130
+ override CallNode getCall ( ) { result = call }
131
+ }
53
132
}
0 commit comments