@@ -2074,7 +2074,11 @@ private module Django {
20742074 // TODO: This doesn't handle attribute assignment. Should be OK, but analysis is not as complete as with
20752075 // points-to and `.lookup`, which would handle `post = my_post_handler` inside class def
20762076 result = this .getAMethod ( ) and
2077- result .getName ( ) = HTTP:: httpVerbLower ( )
2077+ (
2078+ result .getName ( ) = HTTP:: httpVerbLower ( )
2079+ or
2080+ result .getName ( ) = "get_redirect_url"
2081+ )
20782082 }
20792083
20802084 /**
@@ -2124,6 +2128,8 @@ private module Django {
21242128 /**
21252129 * A function that is a django route handler, meaning it handles incoming requests
21262130 * with the django framework.
2131+ *
2132+ * Most functions take a django HttpRequest as a parameter (but not all).
21272133 */
21282134 private class DjangoRouteHandler extends Function {
21292135 DjangoRouteHandler ( ) {
@@ -2132,6 +2138,12 @@ private module Django {
21322138 any ( DjangoViewClass vc ) .getARequestHandler ( ) = this
21332139 }
21342140
2141+ /**
2142+ * Gets the index of the parameter where the first routed parameter can be passed --
2143+ * that is, the one just after any possible `self` or HttpRequest parameters.
2144+ */
2145+ int getFirstPossibleRoutedParamIndex ( ) { result = 1 + this .getRequestParamIndex ( ) }
2146+
21352147 /** Gets the index of the request parameter. */
21362148 int getRequestParamIndex ( ) {
21372149 not this .isMethod ( ) and
@@ -2145,6 +2157,26 @@ private module Django {
21452157 Parameter getRequestParam ( ) { result = this .getArg ( this .getRequestParamIndex ( ) ) }
21462158 }
21472159
2160+ /**
2161+ * A method named `get_redirect_url` on a django view class.
2162+ *
2163+ * See https://docs.djangoproject.com/en/3.1/ref/class-based-views/base/#django.views.generic.base.RedirectView.get_redirect_url
2164+ *
2165+ * Note: this function only does something on a subclass of `RedirectView`, but since
2166+ * classes can be considered django view classes without us knowing their super-classes,
2167+ * we need to consider _any_ django view class. I don't expect any problems to come from this.
2168+ */
2169+ private class GetRedirectUrlFunction extends DjangoRouteHandler {
2170+ GetRedirectUrlFunction ( ) {
2171+ this .getName ( ) = "get_redirect_url" and
2172+ any ( DjangoViewClass vc ) .getARequestHandler ( ) = this
2173+ }
2174+
2175+ override int getFirstPossibleRoutedParamIndex ( ) { result = 1 }
2176+
2177+ override int getRequestParamIndex ( ) { none ( ) }
2178+ }
2179+
21482180 /** A data-flow node that sets up a route on a server, using the django framework. */
21492181 abstract private class DjangoRouteSetup extends HTTP:: Server:: RouteSetup:: Range , DataFlow:: CfgNode {
21502182 /** Gets the data-flow node that is used as the argument for the view handler. */
@@ -2175,7 +2207,7 @@ private module Django {
21752207 // parameter. This should give us more RemoteFlowSources but could also lead to
21762208 // more FPs. If this turns out to be the wrong tradeoff, we can always change our mind.
21772209 result in [ this .getArg ( _) , this .getArgByName ( _) ] and
2178- not result = any ( int i | i <= this .getRequestParamIndex ( ) | this .getArg ( i ) )
2210+ not result = any ( int i | i < this .getFirstPossibleRoutedParamIndex ( ) | this .getArg ( i ) )
21792211 }
21802212
21812213 override string getFramework ( ) { result = "Django" }
@@ -2215,7 +2247,8 @@ private module Django {
22152247 exists ( DjangoRouteHandler routeHandler | routeHandler = this .getARequestHandler ( ) |
22162248 not exists ( this .getUrlPattern ( ) ) and
22172249 result in [ routeHandler .getArg ( _) , routeHandler .getArgByName ( _) ] and
2218- not result = any ( int i | i <= routeHandler .getRequestParamIndex ( ) | routeHandler .getArg ( i ) )
2250+ not result =
2251+ any ( int i | i < routeHandler .getFirstPossibleRoutedParamIndex ( ) | routeHandler .getArg ( i ) )
22192252 )
22202253 or
22212254 exists ( string name |
@@ -2237,7 +2270,8 @@ private module Django {
22372270 exists ( DjangoRouteHandler routeHandler | routeHandler = this .getARequestHandler ( ) |
22382271 not exists ( this .getUrlPattern ( ) ) and
22392272 result in [ routeHandler .getArg ( _) , routeHandler .getArgByName ( _) ] and
2240- not result = any ( int i | i <= routeHandler .getRequestParamIndex ( ) | routeHandler .getArg ( i ) )
2273+ not result =
2274+ any ( int i | i < routeHandler .getFirstPossibleRoutedParamIndex ( ) | routeHandler .getArg ( i ) )
22412275 )
22422276 or
22432277 exists ( DjangoRouteHandler routeHandler , DjangoRouteRegex regex |
@@ -2249,7 +2283,9 @@ private module Django {
22492283 not exists ( regex .getGroupName ( _, _) ) and
22502284 // first group will have group number 1
22512285 result =
2252- routeHandler .getArg ( routeHandler .getRequestParamIndex ( ) + regex .getGroupNumber ( _, _) )
2286+ routeHandler
2287+ .getArg ( routeHandler .getFirstPossibleRoutedParamIndex ( ) - 1 +
2288+ regex .getGroupNumber ( _, _) )
22532289 or
22542290 result = routeHandler .getArgByName ( regex .getGroupName ( _, _) )
22552291 )
@@ -2445,4 +2481,31 @@ private module Django {
24452481
24462482 override string getMimetypeDefault ( ) { none ( ) }
24472483 }
2484+
2485+ // ---------------------------------------------------------------------------
2486+ // RedirectView handling
2487+ // ---------------------------------------------------------------------------
2488+ /**
2489+ * A return from a method named `get_redirect_url` on a django view class.
2490+ *
2491+ * Note that in reality, this only does something on a subclass of `RedirectView` --
2492+ * but until API graphs makes this easy to model, I took a shortcut in modeling
2493+ * preciseness.
2494+ *
2495+ * See https://docs.djangoproject.com/en/3.1/ref/class-based-views/base/#redirectview
2496+ */
2497+ private class DjangoRedirectViewGetRedirectUrlReturn extends HTTP:: Server:: HttpRedirectResponse:: Range ,
2498+ DataFlow:: CfgNode {
2499+ DjangoRedirectViewGetRedirectUrlReturn ( ) {
2500+ node = any ( GetRedirectUrlFunction f ) .getAReturnValueFlowNode ( )
2501+ }
2502+
2503+ override DataFlow:: Node getRedirectLocation ( ) { result = this }
2504+
2505+ override DataFlow:: Node getBody ( ) { none ( ) }
2506+
2507+ override DataFlow:: Node getMimetypeOrContentTypeArg ( ) { none ( ) }
2508+
2509+ override string getMimetypeDefault ( ) { none ( ) }
2510+ }
24482511}
0 commit comments