@@ -82,39 +82,50 @@ class MimetypeCall extends DataFlow::CallNode {
8282 string getMimeType ( ) { mimeTypeMatches ( this .getExtension ( ) , result ) }
8383}
8484
85+ bindingset [ headerName]
86+ private DataFlow:: Node getHeaderValue ( ResponseNode resp , string headerName ) {
87+ exists ( DataFlow:: Node headers | headers = resp .getHeaders ( ) |
88+ // set via `headers.<header_name>=`
89+ exists (
90+ DataFlow:: CallNode contentTypeAssignment , Assignment assignment ,
91+ DataFlow:: PostUpdateNode postUpdateHeaders
92+ |
93+ contentTypeAssignment .getMethodName ( ) = headerName .replaceAll ( "-" , "_" ) .toLowerCase ( ) + "=" and
94+ assignment =
95+ contentTypeAssignment .getArgument ( 0 ) .( DataFlow:: OperationNode ) .asOperationAstNode ( ) and
96+ postUpdateHeaders .( DataFlow:: LocalSourceNode ) .flowsTo ( headers ) and
97+ postUpdateHeaders .getPreUpdateNode ( ) = contentTypeAssignment .getReceiver ( )
98+ |
99+ result .asExpr ( ) .getExpr ( ) = assignment .getRightOperand ( )
100+ )
101+ or
102+ // set within a hash
103+ exists ( DataFlow:: HashLiteralNode headersHash | headersHash .flowsTo ( headers ) |
104+ result =
105+ headersHash
106+ .getElementFromKey ( any ( ConstantValue v |
107+ v .getStringlikeValue ( ) .toLowerCase ( ) = headerName .toLowerCase ( )
108+ ) )
109+ )
110+ )
111+ }
112+
85113/** A `DataFlow::Node` returned from a rack request. */
86114class ResponseNode extends PotentialResponseNode , Http:: Server:: HttpResponse:: Range {
87115 ResponseNode ( ) { this = any ( AppCandidate app ) .getResponse ( ) }
88116
89117 override DataFlow:: Node getBody ( ) { result = this .getElement ( 2 ) }
90118
91119 override DataFlow:: Node getMimetypeOrContentTypeArg ( ) {
92- exists ( DataFlow:: Node headers | headers = this .getHeaders ( ) |
93- // set via `headers.content_type=`
94- exists (
95- DataFlow:: CallNode contentTypeAssignment , Assignment assignment ,
96- DataFlow:: PostUpdateNode postUpdateHeaders
97- |
98- contentTypeAssignment .getMethodName ( ) = "content_type=" and
99- assignment =
100- contentTypeAssignment .getArgument ( 0 ) .( DataFlow:: OperationNode ) .asOperationAstNode ( ) and
101- postUpdateHeaders .( DataFlow:: LocalSourceNode ) .flowsTo ( headers ) and
102- postUpdateHeaders .getPreUpdateNode ( ) = contentTypeAssignment .getReceiver ( )
103- |
104- result .asExpr ( ) .getExpr ( ) = assignment .getRightOperand ( )
105- )
106- or
107- // set within a hash
108- exists ( DataFlow:: HashLiteralNode headersHash | headersHash .flowsTo ( headers ) |
109- result =
110- headersHash
111- .getElementFromKey ( any ( ConstantValue v |
112- v .getStringlikeValue ( ) .toLowerCase ( ) = "content-type"
113- ) )
114- )
115- )
120+ result = getHeaderValue ( this , "content-type" )
116121 }
117122
118123 // TODO
119124 override string getMimetypeDefault ( ) { none ( ) }
120125}
126+
127+ class RedirectResponse extends ResponseNode , Http:: Server:: HttpRedirectResponse:: Range {
128+ RedirectResponse ( ) { this .getAStatusCode ( ) = [ 300 , 301 , 302 , 303 , 307 , 308 ] }
129+
130+ override DataFlow:: Node getRedirectLocation ( ) { result = getHeaderValue ( this , "location" ) }
131+ }
0 commit comments