@@ -35,7 +35,7 @@ private module Django {
3535 * WARNING: Only holds for a few predefined attributes.
3636 */
3737 private DataFlow:: Node django_attr ( DataFlow:: TypeTracker t , string attr_name ) {
38- attr_name in [ "db" , "urls" , "http" , "conf" , "views" ] and
38+ attr_name in [ "db" , "urls" , "http" , "conf" , "views" , "shortcuts" ] and
3939 (
4040 t .start ( ) and
4141 result = DataFlow:: importNode ( "django" + "." + attr_name )
@@ -724,7 +724,8 @@ private module Django {
724724 *
725725 * Use the predicate `HttpResponseRedirect::instance()` to get references to instances of `django.http.response.HttpResponseRedirect`.
726726 */
727- abstract class InstanceSource extends HttpResponse:: InstanceSource , DataFlow:: Node { }
727+ abstract class InstanceSource extends HttpResponse:: InstanceSource ,
728+ HTTP:: Server:: HttpRedirectResponse:: Range , DataFlow:: Node { }
728729
729730 /** A direct instantiation of `django.http.response.HttpResponseRedirect`. */
730731 private class ClassInstantiation extends InstanceSource , DataFlow:: CfgNode {
@@ -739,6 +740,10 @@ private module Django {
739740 result .asCfgNode ( ) in [ node .getArg ( 1 ) , node .getArgByName ( "content" ) ]
740741 }
741742
743+ override DataFlow:: Node getRedirectLocation ( ) {
744+ result .asCfgNode ( ) in [ node .getArg ( 0 ) , node .getArgByName ( "redirect_to" ) ]
745+ }
746+
742747 // How to support the `headers` argument here?
743748 override DataFlow:: Node getMimetypeOrContentTypeArg ( ) { none ( ) }
744749
@@ -790,7 +795,8 @@ private module Django {
790795 *
791796 * Use the predicate `HttpResponsePermanentRedirect::instance()` to get references to instances of `django.http.response.HttpResponsePermanentRedirect`.
792797 */
793- abstract class InstanceSource extends HttpResponse:: InstanceSource , DataFlow:: Node { }
798+ abstract class InstanceSource extends HttpResponse:: InstanceSource ,
799+ HTTP:: Server:: HttpRedirectResponse:: Range , DataFlow:: Node { }
794800
795801 /** A direct instantiation of `django.http.response.HttpResponsePermanentRedirect`. */
796802 private class ClassInstantiation extends InstanceSource , DataFlow:: CfgNode {
@@ -805,6 +811,10 @@ private module Django {
805811 result .asCfgNode ( ) in [ node .getArg ( 1 ) , node .getArgByName ( "content" ) ]
806812 }
807813
814+ override DataFlow:: Node getRedirectLocation ( ) {
815+ result .asCfgNode ( ) in [ node .getArg ( 0 ) , node .getArgByName ( "redirect_to" ) ]
816+ }
817+
808818 // How to support the `headers` argument here?
809819 override DataFlow:: Node getMimetypeOrContentTypeArg ( ) { none ( ) }
810820
@@ -1907,6 +1917,62 @@ private module Django {
19071917 }
19081918 }
19091919 }
1920+
1921+ // -------------------------------------------------------------------------
1922+ // django.shortcuts
1923+ // -------------------------------------------------------------------------
1924+ /** Gets a reference to the `django.shortcuts` module. */
1925+ DataFlow:: Node shortcuts ( ) { result = django_attr ( "shortcuts" ) }
1926+
1927+ /** Provides models for the `django.shortcuts` module */
1928+ module shortcuts {
1929+ /**
1930+ * Gets a reference to the attribute `attr_name` of the `django.shortcuts` module.
1931+ * WARNING: Only holds for a few predefined attributes.
1932+ */
1933+ private DataFlow:: Node shortcuts_attr ( DataFlow:: TypeTracker t , string attr_name ) {
1934+ attr_name in [ "redirect" ] and
1935+ (
1936+ t .start ( ) and
1937+ result = DataFlow:: importNode ( "django.shortcuts" + "." + attr_name )
1938+ or
1939+ t .startInAttr ( attr_name ) and
1940+ result = shortcuts ( )
1941+ )
1942+ or
1943+ // Due to bad performance when using normal setup with `shortcuts_attr(t2, attr_name).track(t2, t)`
1944+ // we have inlined that code and forced a join
1945+ exists ( DataFlow:: TypeTracker t2 |
1946+ exists ( DataFlow:: StepSummary summary |
1947+ shortcuts_attr_first_join ( t2 , attr_name , result , summary ) and
1948+ t = t2 .append ( summary )
1949+ )
1950+ )
1951+ }
1952+
1953+ pragma [ nomagic]
1954+ private predicate shortcuts_attr_first_join (
1955+ DataFlow:: TypeTracker t2 , string attr_name , DataFlow:: Node res ,
1956+ DataFlow:: StepSummary summary
1957+ ) {
1958+ DataFlow:: StepSummary:: step ( shortcuts_attr ( t2 , attr_name ) , res , summary )
1959+ }
1960+
1961+ /**
1962+ * Gets a reference to the attribute `attr_name` of the `django.shortcuts` module.
1963+ * WARNING: Only holds for a few predefined attributes.
1964+ */
1965+ private DataFlow:: Node shortcuts_attr ( string attr_name ) {
1966+ result = shortcuts_attr ( DataFlow:: TypeTracker:: end ( ) , attr_name )
1967+ }
1968+
1969+ /**
1970+ * Gets a reference to the `django.shortcuts.redirect` function
1971+ *
1972+ * See https://docs.djangoproject.com/en/3.1/topics/http/shortcuts/#redirect
1973+ */
1974+ DataFlow:: Node redirect ( ) { result = shortcuts_attr ( "redirect" ) }
1975+ }
19101976 }
19111977
19121978 // ---------------------------------------------------------------------------
@@ -2230,4 +2296,39 @@ private module Django {
22302296 )
22312297 }
22322298 }
2299+
2300+ // ---------------------------------------------------------------------------
2301+ // django.shortcuts.redirect
2302+ // ---------------------------------------------------------------------------
2303+ /**
2304+ * A call to `django.shortcuts.redirect`.
2305+ *
2306+ * Note: This works differently depending on what argument is used.
2307+ * _One_ option is to redirect to a full URL.
2308+ *
2309+ * See https://docs.djangoproject.com/en/3.1/topics/http/shortcuts/#redirect
2310+ */
2311+ private class DjangoShortcutsRedirectCall extends HTTP:: Server:: HttpRedirectResponse:: Range ,
2312+ DataFlow:: CfgNode {
2313+ override CallNode node ;
2314+
2315+ DjangoShortcutsRedirectCall ( ) { node .getFunction ( ) = django:: shortcuts:: redirect ( ) .asCfgNode ( ) }
2316+
2317+ /**
2318+ * Gets the data-flow node that specifies the location of this HTTP redirect response.
2319+ *
2320+ * Note: For `django.shortcuts.redirect`, the result might not be a full URL
2321+ * (as usually expected by this method), but could be a relative URL,
2322+ * a string identifying a view, or a Django model.
2323+ */
2324+ override DataFlow:: Node getRedirectLocation ( ) {
2325+ result .asCfgNode ( ) in [ node .getArg ( 0 ) , node .getArgByName ( "to" ) ]
2326+ }
2327+
2328+ override DataFlow:: Node getBody ( ) { none ( ) }
2329+
2330+ override DataFlow:: Node getMimetypeOrContentTypeArg ( ) { none ( ) }
2331+
2332+ override string getMimetypeDefault ( ) { none ( ) }
2333+ }
22332334}
0 commit comments