@@ -2074,7 +2074,11 @@ private module Django {
2074
2074
// TODO: This doesn't handle attribute assignment. Should be OK, but analysis is not as complete as with
2075
2075
// points-to and `.lookup`, which would handle `post = my_post_handler` inside class def
2076
2076
result = this .getAMethod ( ) and
2077
- result .getName ( ) = HTTP:: httpVerbLower ( )
2077
+ (
2078
+ result .getName ( ) = HTTP:: httpVerbLower ( )
2079
+ or
2080
+ result .getName ( ) = "get_redirect_url"
2081
+ )
2078
2082
}
2079
2083
2080
2084
/**
@@ -2124,6 +2128,8 @@ private module Django {
2124
2128
/**
2125
2129
* A function that is a django route handler, meaning it handles incoming requests
2126
2130
* with the django framework.
2131
+ *
2132
+ * Most functions take a django HttpRequest as a parameter (but not all).
2127
2133
*/
2128
2134
private class DjangoRouteHandler extends Function {
2129
2135
DjangoRouteHandler ( ) {
@@ -2132,6 +2138,12 @@ private module Django {
2132
2138
any ( DjangoViewClass vc ) .getARequestHandler ( ) = this
2133
2139
}
2134
2140
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
+
2135
2147
/** Gets the index of the request parameter. */
2136
2148
int getRequestParamIndex ( ) {
2137
2149
not this .isMethod ( ) and
@@ -2145,6 +2157,26 @@ private module Django {
2145
2157
Parameter getRequestParam ( ) { result = this .getArg ( this .getRequestParamIndex ( ) ) }
2146
2158
}
2147
2159
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
+
2148
2180
/** A data-flow node that sets up a route on a server, using the django framework. */
2149
2181
abstract private class DjangoRouteSetup extends HTTP:: Server:: RouteSetup:: Range , DataFlow:: CfgNode {
2150
2182
/** Gets the data-flow node that is used as the argument for the view handler. */
@@ -2175,7 +2207,7 @@ private module Django {
2175
2207
// parameter. This should give us more RemoteFlowSources but could also lead to
2176
2208
// more FPs. If this turns out to be the wrong tradeoff, we can always change our mind.
2177
2209
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 ) )
2179
2211
}
2180
2212
2181
2213
override string getFramework ( ) { result = "Django" }
@@ -2215,7 +2247,8 @@ private module Django {
2215
2247
exists ( DjangoRouteHandler routeHandler | routeHandler = this .getARequestHandler ( ) |
2216
2248
not exists ( this .getUrlPattern ( ) ) and
2217
2249
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 ) )
2219
2252
)
2220
2253
or
2221
2254
exists ( string name |
@@ -2237,7 +2270,8 @@ private module Django {
2237
2270
exists ( DjangoRouteHandler routeHandler | routeHandler = this .getARequestHandler ( ) |
2238
2271
not exists ( this .getUrlPattern ( ) ) and
2239
2272
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 ) )
2241
2275
)
2242
2276
or
2243
2277
exists ( DjangoRouteHandler routeHandler , DjangoRouteRegex regex |
@@ -2249,7 +2283,9 @@ private module Django {
2249
2283
not exists ( regex .getGroupName ( _, _) ) and
2250
2284
// first group will have group number 1
2251
2285
result =
2252
- routeHandler .getArg ( routeHandler .getRequestParamIndex ( ) + regex .getGroupNumber ( _, _) )
2286
+ routeHandler
2287
+ .getArg ( routeHandler .getFirstPossibleRoutedParamIndex ( ) - 1 +
2288
+ regex .getGroupNumber ( _, _) )
2253
2289
or
2254
2290
result = routeHandler .getArgByName ( regex .getGroupName ( _, _) )
2255
2291
)
@@ -2445,4 +2481,31 @@ private module Django {
2445
2481
2446
2482
override string getMimetypeDefault ( ) { none ( ) }
2447
2483
}
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
+ }
2448
2511
}
0 commit comments