|
13 | 13 | RawPostDataException, |
14 | 14 | UnreadablePostError, |
15 | 15 | ) |
16 | | -from django.http.multipartparser import MAX_TOTAL_HEADER_SIZE, MultiPartParserError |
| 16 | +from django.http.multipartparser import ( |
| 17 | + MAX_TOTAL_HEADER_SIZE, |
| 18 | + MultiPartParser, |
| 19 | + MultiPartParserError, |
| 20 | +) |
17 | 21 | from django.http.request import split_domain_port |
18 | 22 | from django.test import RequestFactory, SimpleTestCase, override_settings |
19 | 23 | from django.test.client import BOUNDARY, MULTIPART_CONTENT, FakePayload |
@@ -1112,6 +1116,72 @@ def test_deepcopy(self): |
1112 | 1116 | request.session["key"] = "value" |
1113 | 1117 | self.assertEqual(request_copy.session, {}) |
1114 | 1118 |
|
| 1119 | + def test_custom_multipart_parser_class(self): |
| 1120 | + |
| 1121 | + class CustomMultiPartParser(MultiPartParser): |
| 1122 | + def parse(self): |
| 1123 | + post, files = super().parse() |
| 1124 | + post._mutable = True |
| 1125 | + post["custom_parser_used"] = "yes" |
| 1126 | + post._mutable = False |
| 1127 | + return post, files |
| 1128 | + |
| 1129 | + class CustomWSGIRequest(WSGIRequest): |
| 1130 | + multipart_parser_class = CustomMultiPartParser |
| 1131 | + |
| 1132 | + payload = FakePayload( |
| 1133 | + "\r\n".join( |
| 1134 | + [ |
| 1135 | + "--boundary", |
| 1136 | + 'Content-Disposition: form-data; name="name"', |
| 1137 | + "", |
| 1138 | + "value", |
| 1139 | + "--boundary--", |
| 1140 | + ] |
| 1141 | + ) |
| 1142 | + ) |
| 1143 | + request = CustomWSGIRequest( |
| 1144 | + { |
| 1145 | + "REQUEST_METHOD": "POST", |
| 1146 | + "CONTENT_TYPE": "multipart/form-data; boundary=boundary", |
| 1147 | + "CONTENT_LENGTH": len(payload), |
| 1148 | + "wsgi.input": payload, |
| 1149 | + } |
| 1150 | + ) |
| 1151 | + self.assertEqual(request.POST.get("custom_parser_used"), "yes") |
| 1152 | + self.assertEqual(request.POST.get("name"), "value") |
| 1153 | + |
| 1154 | + def test_multipart_parser_class_immutable_after_parse(self): |
| 1155 | + payload = FakePayload( |
| 1156 | + "\r\n".join( |
| 1157 | + [ |
| 1158 | + "--boundary", |
| 1159 | + 'Content-Disposition: form-data; name="name"', |
| 1160 | + "", |
| 1161 | + "value", |
| 1162 | + "--boundary--", |
| 1163 | + ] |
| 1164 | + ) |
| 1165 | + ) |
| 1166 | + request = WSGIRequest( |
| 1167 | + { |
| 1168 | + "REQUEST_METHOD": "POST", |
| 1169 | + "CONTENT_TYPE": "multipart/form-data; boundary=boundary", |
| 1170 | + "CONTENT_LENGTH": len(payload), |
| 1171 | + "wsgi.input": payload, |
| 1172 | + } |
| 1173 | + ) |
| 1174 | + |
| 1175 | + # Access POST to trigger parsing. |
| 1176 | + request.POST |
| 1177 | + |
| 1178 | + msg = ( |
| 1179 | + "You cannot set the multipart parser class after the upload has been " |
| 1180 | + "processed." |
| 1181 | + ) |
| 1182 | + with self.assertRaisesMessage(RuntimeError, msg): |
| 1183 | + request.multipart_parser_class = MultiPartParser |
| 1184 | + |
1115 | 1185 |
|
1116 | 1186 | class HostValidationTests(SimpleTestCase): |
1117 | 1187 | poisoned_hosts = [ |
|
0 commit comments