@@ -516,8 +516,11 @@ private class ActionControllerProtectFromForgeryCall extends CsrfProtectionSetti
516516 */
517517private class SendFile extends FileSystemAccess:: Range , DataFlow:: CallNode {
518518 SendFile ( ) {
519- this .asExpr ( ) .getExpr ( ) instanceof ActionControllerContextCall and
520- this .getMethodName ( ) = "send_file"
519+ this .getMethodName ( ) = "send_file" and
520+ (
521+ this .asExpr ( ) .getExpr ( ) instanceof ActionControllerContextCall or
522+ this .getReceiver ( ) .asExpr ( ) .getExpr ( ) instanceof Response:: ResponseCall
523+ )
521524 }
522525
523526 override DataFlow:: Node getAPathArgument ( ) { result = this .getArgument ( 0 ) }
@@ -642,3 +645,94 @@ private module ParamsSummaries {
642645 }
643646 }
644647}
648+
649+ /**
650+ * Provides modeling for `ActionDispatch::Response`, which represents an HTTP
651+ * response.
652+ */
653+ private module Response {
654+ class ResponseCall extends ActionControllerContextCall {
655+ ResponseCall ( ) { this .getMethodName ( ) = "response" }
656+ }
657+
658+ class BodyWrite extends DataFlow:: CallNode , Http:: Server:: HttpResponse:: Range {
659+ BodyWrite ( ) {
660+ this .getReceiver ( ) .asExpr ( ) .getExpr ( ) instanceof ResponseCall and
661+ this .getMethodName ( ) = "body="
662+ }
663+
664+ override DataFlow:: Node getBody ( ) { result = this .getArgument ( 0 ) }
665+
666+ override DataFlow:: Node getMimetypeOrContentTypeArg ( ) { none ( ) }
667+
668+ override string getMimetypeDefault ( ) { result = "text/http" }
669+ }
670+
671+ class SendFileCall extends DataFlow:: CallNode , Http:: Server:: HttpResponse:: Range {
672+ SendFileCall ( ) {
673+ this .getReceiver ( ) .asExpr ( ) .getExpr ( ) instanceof ResponseCall and
674+ this .getMethodName ( ) = "send_file"
675+ }
676+
677+ override DataFlow:: Node getBody ( ) { result = this .getArgument ( 0 ) }
678+
679+ override DataFlow:: Node getMimetypeOrContentTypeArg ( ) { none ( ) }
680+
681+ override string getMimetypeDefault ( ) { result = "application/octet-stream" }
682+ }
683+
684+ class HeaderWrite extends DataFlow:: CallNode , Http:: Server:: HeaderWriteAccess:: Range {
685+ HeaderWrite ( ) {
686+ // response.header[key] = val
687+ // response.headers[key] = val
688+ exists ( MethodCall headerCall |
689+ headerCall .getMethodName ( ) = [ "header" , "headers" ] and
690+ headerCall .getReceiver ( ) instanceof ResponseCall
691+ |
692+ this .getReceiver ( ) .asExpr ( ) .getExpr ( ) = headerCall and
693+ this .getMethodName ( ) = "[]="
694+ )
695+ or
696+ // response.set_header(key) = val
697+ // response[header] = val
698+ // response.add_header(key, val)
699+ this .getReceiver ( ) .asExpr ( ) .getExpr ( ) instanceof ResponseCall and
700+ this .getMethodName ( ) = [ "set_header" , "[]=" , "add_header" ]
701+ }
702+
703+ override string getName ( ) {
704+ result = this .getArgument ( 0 ) .asExpr ( ) .getConstantValue ( ) .getString ( )
705+ }
706+
707+ override DataFlow:: Node getValue ( ) { result = this .getArgument ( 1 ) }
708+ }
709+
710+ class SpecificHeaderWrite extends DataFlow:: CallNode , Http:: Server:: HeaderWriteAccess:: Range {
711+ SpecificHeaderWrite ( ) {
712+ // response.<method> = val
713+ this .getReceiver ( ) .asExpr ( ) .getExpr ( ) instanceof ResponseCall and
714+ this .getMethodName ( ) =
715+ [
716+ "location=" , "cache_control=" , "_cache_control=" , "etag=" , "charset=" , "content_type=" ,
717+ "date=" , "last_modified=" , "weak_etag=" , "strong_etag="
718+ ]
719+ }
720+
721+ override string getName ( ) {
722+ this .getMethodName ( ) = "location=" and result = "location"
723+ or
724+ this .getMethodName ( ) = [ "_cache_control=" , "cache_control=" ] and result = "cache-control"
725+ or
726+ this .getMethodName ( ) = [ "etag=" , "weak_etag=" , "strong_etag=" ] and result = "etag"
727+ or
728+ // sets the charset part of the content-type header
729+ this .getMethodName ( ) = [ "charset=" , "content_type=" ] and result = "content-type"
730+ or
731+ this .getMethodName ( ) = "date=" and result = "date"
732+ or
733+ this .getMethodName ( ) = "last_modified=" and result = "last-modified"
734+ }
735+
736+ override DataFlow:: Node getValue ( ) { result = this .getArgument ( 0 ) }
737+ }
738+ }
0 commit comments