Refs #21442 -- Increased test coverage of requests.

This commit is contained in:
David Smith 2023-11-25 14:57:45 +00:00 committed by Mariusz Felisiak
parent baf705f34a
commit 76280b4f4d
1 changed files with 271 additions and 0 deletions

View File

@ -4,6 +4,8 @@ from itertools import chain
from urllib.parse import urlencode from urllib.parse import urlencode
from django.core.exceptions import BadRequest, DisallowedHost from django.core.exceptions import BadRequest, DisallowedHost
from django.core.files.uploadedfile import InMemoryUploadedFile
from django.core.files.uploadhandler import MemoryFileUploadHandler
from django.core.handlers.wsgi import LimitedStream, WSGIRequest from django.core.handlers.wsgi import LimitedStream, WSGIRequest
from django.http import ( from django.http import (
HttpHeaders, HttpHeaders,
@ -17,6 +19,20 @@ from django.test import RequestFactory, SimpleTestCase, override_settings
from django.test.client import BOUNDARY, MULTIPART_CONTENT, FakePayload from django.test.client import BOUNDARY, MULTIPART_CONTENT, FakePayload
class ErrorFileUploadHandler(MemoryFileUploadHandler):
def handle_raw_input(
self, input_data, META, content_length, boundary, encoding=None
):
raise ValueError
class CustomFileUploadHandler(MemoryFileUploadHandler):
def handle_raw_input(
self, input_data, META, content_length, boundary, encoding=None
):
return ("_POST", "_FILES")
class RequestsTests(SimpleTestCase): class RequestsTests(SimpleTestCase):
def test_httprequest(self): def test_httprequest(self):
request = HttpRequest() request = HttpRequest()
@ -491,6 +507,261 @@ class RequestsTests(SimpleTestCase):
) )
self.assertEqual(request.POST, {}) self.assertEqual(request.POST, {})
@override_settings(
FILE_UPLOAD_HANDLERS=["requests_tests.tests.ErrorFileUploadHandler"]
)
def test_POST_multipart_handler_error(self):
payload = FakePayload(
"\r\n".join(
[
f"--{BOUNDARY}",
'Content-Disposition: form-data; name="name"',
"",
"value",
f"--{BOUNDARY}--",
]
)
)
request = WSGIRequest(
{
"REQUEST_METHOD": "POST",
"CONTENT_TYPE": MULTIPART_CONTENT,
"CONTENT_LENGTH": len(payload),
"wsgi.input": payload,
}
)
with self.assertRaises(ValueError):
request.POST
@override_settings(
FILE_UPLOAD_HANDLERS=["requests_tests.tests.CustomFileUploadHandler"]
)
def test_POST_multipart_handler_parses_input(self):
payload = FakePayload(
"\r\n".join(
[
f"--{BOUNDARY}",
'Content-Disposition: form-data; name="name"',
"",
"value",
f"--{BOUNDARY}--",
]
)
)
request = WSGIRequest(
{
"REQUEST_METHOD": "POST",
"CONTENT_TYPE": MULTIPART_CONTENT,
"CONTENT_LENGTH": len(payload),
"wsgi.input": payload,
}
)
self.assertEqual(request.POST, "_POST")
self.assertEqual(request.FILES, "_FILES")
def test_request_methods_with_content(self):
for method in ["GET", "PUT", "DELETE"]:
with self.subTest(method=method):
payload = FakePayload(urlencode({"key": "value"}))
request = WSGIRequest(
{
"REQUEST_METHOD": method,
"CONTENT_LENGTH": len(payload),
"CONTENT_TYPE": "application/x-www-form-urlencoded",
"wsgi.input": payload,
}
)
self.assertEqual(request.POST, {})
def test_POST_content_type_json(self):
payload = FakePayload(
"\r\n".join(
[
'{"pk": 1, "model": "store.book", "fields": {"name": "Mostly Ha',
'rmless", "author": ["Douglas", Adams"]}}',
]
)
)
request = WSGIRequest(
{
"REQUEST_METHOD": "POST",
"CONTENT_TYPE": "application/json",
"CONTENT_LENGTH": len(payload),
"wsgi.input": payload,
}
)
self.assertEqual(request.POST, {})
self.assertEqual(request.FILES, {})
_json_payload = [
'Content-Disposition: form-data; name="JSON"',
"Content-Type: application/json",
"",
'{"pk": 1, "model": "store.book", "fields": {"name": "Mostly Harmless", '
'"author": ["Douglas", Adams"]}}',
]
def test_POST_form_data_json(self):
payload = FakePayload(
"\r\n".join([f"--{BOUNDARY}", *self._json_payload, f"--{BOUNDARY}--"])
)
request = WSGIRequest(
{
"REQUEST_METHOD": "POST",
"CONTENT_TYPE": MULTIPART_CONTENT,
"CONTENT_LENGTH": len(payload),
"wsgi.input": payload,
}
)
self.assertEqual(
request.POST,
{
"JSON": [
'{"pk": 1, "model": "store.book", "fields": {"name": "Mostly '
'Harmless", "author": ["Douglas", Adams"]}}'
],
},
)
def test_POST_multipart_json(self):
payload = FakePayload(
"\r\n".join(
[
f"--{BOUNDARY}",
'Content-Disposition: form-data; name="name"',
"",
"value",
f"--{BOUNDARY}",
*self._json_payload,
f"--{BOUNDARY}--",
]
)
)
request = WSGIRequest(
{
"REQUEST_METHOD": "POST",
"CONTENT_TYPE": MULTIPART_CONTENT,
"CONTENT_LENGTH": len(payload),
"wsgi.input": payload,
}
)
self.assertEqual(
request.POST,
{
"name": ["value"],
"JSON": [
'{"pk": 1, "model": "store.book", "fields": {"name": "Mostly '
'Harmless", "author": ["Douglas", Adams"]}}'
],
},
)
def test_POST_multipart_json_csv(self):
payload = FakePayload(
"\r\n".join(
[
f"--{BOUNDARY}",
'Content-Disposition: form-data; name="name"',
"",
"value",
f"--{BOUNDARY}",
*self._json_payload,
f"--{BOUNDARY}",
'Content-Disposition: form-data; name="CSV"',
"Content-Type: text/csv",
"",
"Framework,ID.Django,1.Flask,2.",
f"--{BOUNDARY}--",
]
)
)
request = WSGIRequest(
{
"REQUEST_METHOD": "POST",
"CONTENT_TYPE": MULTIPART_CONTENT,
"CONTENT_LENGTH": len(payload),
"wsgi.input": payload,
}
)
self.assertEqual(
request.POST,
{
"name": ["value"],
"JSON": [
'{"pk": 1, "model": "store.book", "fields": {"name": "Mostly '
'Harmless", "author": ["Douglas", Adams"]}}'
],
"CSV": ["Framework,ID.Django,1.Flask,2."],
},
)
def test_POST_multipart_with_file(self):
payload = FakePayload(
"\r\n".join(
[
f"--{BOUNDARY}",
'Content-Disposition: form-data; name="name"',
"",
"value",
f"--{BOUNDARY}",
*self._json_payload,
f"--{BOUNDARY}",
'Content-Disposition: form-data; name="File"; filename="test.csv"',
"Content-Type: application/octet-stream",
"",
"Framework,ID",
"Django,1",
"Flask,2",
f"--{BOUNDARY}--",
]
)
)
request = WSGIRequest(
{
"REQUEST_METHOD": "POST",
"CONTENT_TYPE": MULTIPART_CONTENT,
"CONTENT_LENGTH": len(payload),
"wsgi.input": payload,
}
)
self.assertEqual(
request.POST,
{
"name": ["value"],
"JSON": [
'{"pk": 1, "model": "store.book", "fields": {"name": "Mostly '
'Harmless", "author": ["Douglas", Adams"]}}'
],
},
)
self.assertEqual(len(request.FILES), 1)
self.assertIsInstance((request.FILES["File"]), InMemoryUploadedFile)
def test_base64_invalid_encoding(self):
payload = FakePayload(
"\r\n".join(
[
f"--{BOUNDARY}",
'Content-Disposition: form-data; name="file"; filename="test.txt"',
"Content-Type: application/octet-stream",
"Content-Transfer-Encoding: base64",
"",
f"\r\nZsg£\r\n--{BOUNDARY}--",
]
)
)
request = WSGIRequest(
{
"REQUEST_METHOD": "POST",
"CONTENT_TYPE": MULTIPART_CONTENT,
"CONTENT_LENGTH": len(payload),
"wsgi.input": payload,
}
)
msg = "Could not decode base64 data."
with self.assertRaisesMessage(MultiPartParserError, msg):
request.POST
def test_POST_binary_only(self): def test_POST_binary_only(self):
payload = b"\r\n\x01\x00\x00\x00ab\x00\x00\xcd\xcc,@" payload = b"\r\n\x01\x00\x00\x00ab\x00\x00\xcd\xcc,@"
environ = { environ = {