diff --git a/django/http/request.py b/django/http/request.py
index f7f89913ef..51a7e6c4f1 100644
a
|
b
|
class QueryDict(MultiValueDict):
|
416 | 416 | """ |
417 | 417 | q = cls('', mutable=True, encoding=encoding) |
418 | 418 | for key in iterable: |
419 | | q.appendlist(key, value) |
| 419 | q.appendlist(key, bytes_to_text(value, encoding)) |
420 | 420 | if not mutable: |
421 | 421 | q._mutable = False |
422 | 422 | return q |
… |
… |
class QueryDict(MultiValueDict):
|
471 | 471 | def appendlist(self, key, value): |
472 | 472 | self._assert_mutable() |
473 | 473 | key = bytes_to_text(key, self.encoding) |
474 | | value = bytes_to_text(value, self.encoding) |
475 | 474 | super().appendlist(key, value) |
476 | 475 | |
477 | 476 | def pop(self, key, *args): |
diff --git a/django/utils/http.py b/django/utils/http.py
index 4558c6874a..340f64c590 100644
a
|
b
|
from binascii import Error as BinasciiError
|
8 | 8 | from email.utils import formatdate |
9 | 9 | from urllib.parse import ( |
10 | 10 | ParseResult, SplitResult, _coerce_args, _splitnetloc, _splitparams, quote, |
11 | | quote_plus, scheme_chars, unquote, unquote_plus, |
| 11 | quote_plus, scheme_chars, unquote, unquote_plus, unquote_to_bytes, |
12 | 12 | urlencode as original_urlencode, uses_params, |
13 | 13 | ) |
14 | 14 | |
… |
… |
def limited_parse_qsl(qs, keep_blank_values=False, encoding='utf-8',
|
430 | 430 | name = nv[0].replace('+', ' ') |
431 | 431 | name = unquote(name, encoding=encoding, errors=errors) |
432 | 432 | value = nv[1].replace('+', ' ') |
433 | | value = unquote(value, encoding=encoding, errors=errors) |
| 433 | try: |
| 434 | value = unquote(value, encoding=encoding, errors='strict') |
| 435 | except UnicodeDecodeError: |
| 436 | value = unquote_to_bytes(value) |
434 | 437 | r.append((name, value)) |
435 | 438 | return r |
diff --git a/tests/requests/tests.py b/tests/requests/tests.py
index e1c25a2f6d..7cdc69fe9d 100644
a
|
b
|
class RequestsTests(SimpleTestCase):
|
380 | 380 | self.assertEqual(request.FILES, {}) |
381 | 381 | self.assertEqual(request.body, payload) |
382 | 382 | |
| 383 | def test_POST_binary_form_urlencoded(self): |
| 384 | payload = b'foo=%00%7f%80%ff&bar=value' |
| 385 | environ = {'REQUEST_METHOD': 'POST', |
| 386 | 'CONTENT_TYPE': 'application/x-www-form-urlencoded', |
| 387 | 'CONTENT_LENGTH': len(payload), |
| 388 | 'wsgi.input': BytesIO(payload)} |
| 389 | request = WSGIRequest(environ) |
| 390 | self.assertEqual(request.POST, {'foo': [b'\x00\x7f\x80\xff'], 'bar': ['value']}) |
| 391 | |
383 | 392 | def test_read_by_lines(self): |
384 | 393 | payload = FakePayload('name=value') |
385 | 394 | request = WSGIRequest({'REQUEST_METHOD': 'POST', |