2
2
* Provides modeling for the Rack library.
3
3
*/
4
4
5
+ private import codeql.ruby.Concepts
5
6
private import codeql.ruby.controlflow.CfgNodes:: ExprNodes
6
7
private import codeql.ruby.DataFlow
7
8
private import codeql.ruby.typetracking.TypeTracker
@@ -17,48 +18,63 @@ module Rack {
17
18
*/
18
19
class AppCandidate extends DataFlow:: ClassNode {
19
20
private DataFlow:: MethodNode call ;
21
+ private PotentialResponseNode resp ;
20
22
21
23
AppCandidate ( ) {
22
24
call = this .getInstanceMethod ( "call" ) and
23
25
call .getNumberOfParameters ( ) = 1 and
24
- call .getReturn ( ) = trackRackResponse ( )
26
+ call .getReturn ( ) = trackRackResponse ( resp )
25
27
}
26
28
27
29
/**
28
30
* Gets the environment of the request, which is the lone parameter to the `call` method.
29
31
*/
30
32
DataFlow:: ParameterNode getEnv ( ) { result = call .getParameter ( 0 ) }
33
+
34
+ /** Gets the response returned from the request. */
35
+ PotentialResponseNode getResponse ( ) { result = resp }
31
36
}
32
37
33
- private DataFlow:: LocalSourceNode trackStatusCode ( TypeTracker t , int i ) {
38
+ private DataFlow:: LocalSourceNode trackInt ( TypeTracker t , int i ) {
34
39
t .start ( ) and
35
40
result .getConstantValue ( ) .isInt ( i )
36
41
or
37
- exists ( TypeTracker t2 | result = trackStatusCode ( t2 , i ) .track ( t2 , t ) )
42
+ exists ( TypeTracker t2 | result = trackInt ( t2 , i ) .track ( t2 , t ) )
38
43
}
39
44
40
- private DataFlow:: Node trackStatusCode ( int i ) {
41
- trackStatusCode ( TypeTracker:: end ( ) , i ) .flowsTo ( result )
42
- }
45
+ private DataFlow:: Node trackInt ( int i ) { trackInt ( TypeTracker:: end ( ) , i ) .flowsTo ( result ) }
43
46
44
- class ResponseNode extends DataFlow:: ArrayLiteralNode {
47
+ private class PotentialResponseNode extends DataFlow:: ArrayLiteralNode {
45
48
// [status, headers, body]
46
- ResponseNode ( ) { this .getNumberOfArguments ( ) = 3 }
49
+ PotentialResponseNode ( ) { this .getNumberOfArguments ( ) = 3 }
47
50
48
51
/**
49
52
* Gets an HTTP status code that may be returned in this response.
50
53
*/
51
- int getAStatusCode ( ) { this .getElement ( 0 ) = trackStatusCode ( result ) }
54
+ int getAStatusCode ( ) { this .getElement ( 0 ) = trackInt ( result ) }
52
55
}
53
56
54
- private DataFlow:: LocalSourceNode trackRackResponse ( TypeTracker t ) {
57
+ private DataFlow:: LocalSourceNode trackRackResponse ( TypeTracker t , PotentialResponseNode n ) {
55
58
t .start ( ) and
56
- result instanceof ResponseNode
59
+ result = n
57
60
or
58
- exists ( TypeTracker t2 | result = trackRackResponse ( t2 ) .track ( t2 , t ) )
61
+ exists ( TypeTracker t2 | result = trackRackResponse ( t2 , n ) .track ( t2 , t ) )
62
+ }
63
+
64
+ private DataFlow:: Node trackRackResponse ( PotentialResponseNode n ) {
65
+ trackRackResponse ( TypeTracker:: end ( ) , n ) .flowsTo ( result )
59
66
}
60
67
61
- private DataFlow:: Node trackRackResponse ( ) {
62
- trackRackResponse ( TypeTracker:: end ( ) ) .flowsTo ( result )
68
+ /** A `DataFlow::Node` returned from a rack request. */
69
+ class ResponseNode extends PotentialResponseNode , Http:: Server:: HttpResponse:: Range {
70
+ ResponseNode ( ) { this = any ( AppCandidate app ) .getResponse ( ) }
71
+
72
+ override DataFlow:: Node getBody ( ) { result = this .getElement ( 2 ) }
73
+
74
+ // TODO
75
+ override DataFlow:: Node getMimetypeOrContentTypeArg ( ) { none ( ) }
76
+
77
+ // TODO
78
+ override string getMimetypeDefault ( ) { none ( ) }
63
79
}
64
80
}
0 commit comments