@@ -13,15 +13,39 @@ private import App as A
13
13
/** Contains implementation details for modeling `Rack::Response`. */
14
14
module Private {
15
15
/** A `DataFlow::Node` that may be a rack response. This is detected heuristically, if something "looks like" a rack response syntactically then we consider it to be a potential response node. */
16
- class PotentialResponseNode extends DataFlow:: ArrayLiteralNode {
17
- // [status, headers, body]
18
- PotentialResponseNode ( ) { this .getNumberOfArguments ( ) = 3 }
19
-
16
+ abstract class PotentialResponseNode extends DataFlow:: Node {
20
17
/** Gets the headers returned with this response. */
21
- DataFlow:: Node getHeaders ( ) { result = this . getElement ( 1 ) }
18
+ abstract DataFlow:: Node getHeaders ( ) ;
22
19
23
20
/** Gets the body of this response. */
24
- DataFlow:: Node getBody ( ) { result = this .getElement ( 2 ) }
21
+ abstract DataFlow:: Node getBody ( ) ;
22
+ }
23
+
24
+ /** A rack response constructed directly using an array literal. */
25
+ private class PotentialArrayResponse extends PotentialResponseNode , DataFlow:: ArrayLiteralNode {
26
+ // [status, headers, body]
27
+ PotentialArrayResponse ( ) { this .getNumberOfArguments ( ) = 3 }
28
+
29
+ override DataFlow:: Node getHeaders ( ) { result = this .getElement ( 1 ) }
30
+
31
+ override DataFlow:: Node getBody ( ) { result = this .getElement ( 2 ) }
32
+ }
33
+
34
+ /** A rack response constructed by calling `finish` on an instance of `Rack::Response`. */
35
+ private class RackResponseConstruction extends PotentialResponseNode , DataFlow:: CallNode {
36
+ private DataFlow:: CallNode responseConstruction ;
37
+
38
+ // (body, status, headers)
39
+ RackResponseConstruction ( ) {
40
+ responseConstruction =
41
+ API:: getTopLevelMember ( "Rack" ) .getMember ( "Response" ) .getAnInstantiation ( ) and
42
+ this = responseConstruction .getAMethodCall ( ) and
43
+ this .getMethodName ( ) = "finish"
44
+ }
45
+
46
+ override DataFlow:: Node getHeaders ( ) { result = responseConstruction .getArgument ( 2 ) }
47
+
48
+ override DataFlow:: Node getBody ( ) { result = responseConstruction .getArgument ( 0 ) }
25
49
}
26
50
}
27
51
@@ -54,20 +78,29 @@ module Public {
54
78
v .getStringlikeValue ( ) .toLowerCase ( ) = headerName .toLowerCase ( )
55
79
) )
56
80
)
81
+ or
82
+ // pair in a `Rack::Response.new` constructor
83
+ exists ( DataFlow:: PairNode headerPair | headerPair = headers |
84
+ headerPair .getKey ( ) .getConstantValue ( ) .getStringlikeValue ( ) .toLowerCase ( ) =
85
+ headerName .toLowerCase ( ) and
86
+ result = headerPair .getValue ( )
87
+ )
57
88
)
58
89
}
59
90
60
91
/** A `DataFlow::Node` returned from a rack request. */
61
- class ResponseNode extends Private :: PotentialResponseNode , Http:: Server:: HttpResponse:: Range
92
+ class ResponseNode extends Http:: Server:: HttpResponse:: Range instanceof Private :: PotentialResponseNode
62
93
{
63
94
ResponseNode ( ) { this = any ( A:: App:: App app ) .getResponse ( ) }
64
95
65
- override DataFlow:: Node getBody ( ) { result = this .getElement ( 2 ) }
96
+ override DataFlow:: Node getBody ( ) { result = this .( Private :: PotentialResponseNode ) . getBody ( ) }
66
97
67
98
override DataFlow:: Node getMimetypeOrContentTypeArg ( ) {
68
99
result = getHeaderValue ( this , "content-type" )
69
100
}
70
101
102
+ DataFlow:: Node getHeaders ( ) { result = this .( Private:: PotentialResponseNode ) .getHeaders ( ) }
103
+
71
104
// TODO: is there a sensible value for this?
72
105
override string getMimetypeDefault ( ) { none ( ) }
73
106
}
0 commit comments