Python: Add rest_framework Response modeling

This commit is contained in:
Rasmus Wriedt Larsen
2021-11-01 14:50:03 +01:00
parent 13815fe728
commit a7e4e5ef83
5 changed files with 87 additions and 2 deletions

View File

@@ -259,4 +259,44 @@ private module RestFramework {
}
}
}
// ---------------------------------------------------------------------------
// response modeling
// ---------------------------------------------------------------------------
/**
* Provides models for the `rest_framework.response.Response` class
*
* See https://www.django-rest-framework.org/api-guide/responses/.
*/
module Response {
/** Gets a reference to the `rest_framework.response.Response` class. */
private API::Node classRef() {
result = API::moduleImport("rest_framework").getMember("response").getMember("Response")
}
/**
* A source of instances of `rest_framework.response.Response`, extend this class to model new instances.
*
* This can include instantiations of the class, return values from function
* calls, or a special parameter that will be set when functions are called by an external
* library.
*
* Use the predicate `Response::instance()` to get references to instances of `rest_framework.response.Response`.
*/
abstract class InstanceSource extends DataFlow::LocalSourceNode { }
/** A direct instantiation of `rest_framework.response.Response`. */
private class ClassInstantiation extends PrivateDjango::django::http::response::HttpResponse::InstanceSource,
DataFlow::CallCfgNode {
ClassInstantiation() { this = classRef().getACall() }
override DataFlow::Node getBody() { result in [this.getArg(0), this.getArgByName("data")] }
override DataFlow::Node getMimetypeOrContentTypeArg() {
result in [this.getArg(5), this.getArgByName("content_type")]
}
override string getMimetypeDefault() { none() }
}
}
}

View File

@@ -0,0 +1,34 @@
from rest_framework.decorators import api_view
from rest_framework.response import Response
@api_view()
def normal_response(request): # $ requestHandler
# has no pre-defined content type, since that will be negotiated
# see https://www.django-rest-framework.org/api-guide/responses/
data = "data"
resp = Response(data) # $ HttpResponse responseBody=data
return resp
@api_view()
def plain_text_response(request): # $ requestHandler
# this response is not the standard way to use the Djagno REST framework, but it
# certainly is possible -- notice that the response contains double quotes
data = 'this response will contain double quotes since it was a string'
resp = Response(data, None, None, None, None, "text/plain") # $ HttpResponse mimetype=text/plain responseBody=data
resp = Response(data=data, content_type="text/plain") # $ HttpResponse mimetype=text/plain responseBody=data
return resp
################################################################################
# Cookies
################################################################################
@api_view
def setting_cookie(request):
resp = Response() # $ HttpResponse
resp.set_cookie("key", "value") # $ CookieWrite CookieName="key" CookieValue="value"
resp.set_cookie(key="key4", value="value") # $ CookieWrite CookieName="key4" CookieValue="value"
resp.headers["Set-Cookie"] = "key2=value2" # $ MISSING: CookieWrite CookieRawHeader="key2=value2"
resp.cookies["key3"] = "value3" # $ CookieWrite CookieName="key3" CookieValue="value3"
resp.delete_cookie("key4") # $ CookieWrite CookieName="key4"
resp.delete_cookie(key="key4") # $ CookieWrite CookieName="key4"
return resp

View File

@@ -81,7 +81,7 @@ def test_taint(request: Request, routed_param): # $ requestHandler routedParamet
)
ensure_not_tainted(request.user.password)
return Response("ok")
return Response("ok") # $ HttpResponse responseBody="ok"
# class based view
@@ -105,7 +105,7 @@ class MyClass(APIView):
# same as for standard Django view
ensure_tainted(self.args, self.kwargs) # $ tainted
return Response("ok")
return Response("ok") # $ HttpResponse responseBody="ok"

View File

@@ -13,4 +13,5 @@ urlpatterns = [
path("api-auth/", include("rest_framework.urls", namespace="rest_framework")),
path("class-based-view/", views.MyClass.as_view()), # $routeSetup="lcass-based-view/"
path("function-based-view/", views.function_based_view), # $routeSetup="function-based-view/"
path("cookie-test/", views.cookie_test), # $routeSetup="function-based-view/"
]

View File

@@ -40,3 +40,13 @@ class MyClass(APIView):
@api_view(["GET", "POST"])
def function_based_view(request: Request):
return Response({"message": "Hello, world!"})
@api_view(["GET", "POST"])
def cookie_test(request: Request):
resp = Response("wat")
resp.set_cookie("key", "value") # $ CookieWrite CookieName="key" CookieValue="value"
resp.set_cookie(key="key4", value="value") # $ CookieWrite CookieName="key" CookieValue="value"
resp.headers["Set-Cookie"] = "key2=value2" # $ MISSING: CookieWrite CookieRawHeader="key2=value2"
resp.cookies["key3"] = "value3" # $ CookieWrite CookieName="key3" CookieValue="value3"
return resp