@@ -13,15 +13,39 @@ private import App as A
1313/** Contains implementation details for modeling `Rack::Response`. */
1414module Private {
1515 /** 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 {
2017 /** Gets the headers returned with this response. */
21- DataFlow:: Node getHeaders ( ) { result = this . getElement ( 1 ) }
18+ abstract DataFlow:: Node getHeaders ( ) ;
2219
2320 /** 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 ) }
2549 }
2650}
2751
@@ -54,19 +78,30 @@ module Public {
5478 v .getStringlikeValue ( ) .toLowerCase ( ) = headerName .toLowerCase ( )
5579 ) )
5680 )
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+ )
5788 )
5889 }
5990
6091 /** A `DataFlow::Node` returned from a rack request. */
61- class ResponseNode extends Private:: PotentialResponseNode , Http:: Server:: HttpResponse:: Range {
62- ResponseNode ( ) { this = any ( A:: App:: AppCandidate app ) .getResponse ( ) }
92+ class ResponseNode extends Http:: Server:: HttpResponse:: Range instanceof Private:: PotentialResponseNode
93+ {
94+ ResponseNode ( ) { this = any ( A:: App:: RequestHandler handler ) .getAResponse ( ) }
6395
64- override DataFlow:: Node getBody ( ) { result = this .getElement ( 2 ) }
96+ override DataFlow:: Node getBody ( ) { result = this .( Private :: PotentialResponseNode ) . getBody ( ) }
6597
6698 override DataFlow:: Node getMimetypeOrContentTypeArg ( ) {
6799 result = getHeaderValue ( this , "content-type" )
68100 }
69101
102+ /** Gets the headers returned with this response. */
103+ DataFlow:: Node getHeaders ( ) { result = this .( Private:: PotentialResponseNode ) .getHeaders ( ) }
104+
70105 // TODO: is there a sensible value for this?
71106 override string getMimetypeDefault ( ) { none ( ) }
72107 }
0 commit comments