Skip to content

Commit c75ddc2

Browse files
Fix Content-Length for unicode file contents with multipart (#1537)
1 parent 68cf1ff commit c75ddc2

2 files changed

Lines changed: 25 additions & 6 deletions

File tree

httpx/_multipart.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,7 @@ def render_headers(self) -> bytes:
4040

4141
def render_data(self) -> bytes:
4242
if not hasattr(self, "_data"):
43-
self._data = (
44-
self.value
45-
if isinstance(self.value, bytes)
46-
else self.value.encode("utf-8")
47-
)
43+
self._data = to_bytes(self.value)
4844

4945
return self._data
5046

@@ -88,7 +84,7 @@ def get_length(self) -> int:
8884
headers = self.render_headers()
8985

9086
if isinstance(self.file, (str, bytes)):
91-
return len(headers) + len(self.file)
87+
return len(headers) + len(to_bytes(self.file))
9288

9389
# Let's do our best not to read `file` into memory.
9490
try:

tests/test_multipart.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,29 @@ def test_multipart_encode(tmp_path: typing.Any) -> None:
133133
assert content == b"".join(stream)
134134

135135

136+
def test_multipart_encode_unicode_file_contents() -> None:
137+
files = {"file": ("name.txt", "<únicode string>")}
138+
139+
with mock.patch("os.urandom", return_value=os.urandom(16)):
140+
boundary = os.urandom(16).hex()
141+
142+
headers, stream = encode_request(files=files)
143+
assert isinstance(stream, typing.Iterable)
144+
145+
content = (
146+
'--{0}\r\nContent-Disposition: form-data; name="file";'
147+
' filename="name.txt"\r\n'
148+
"Content-Type: text/plain\r\n\r\n<únicode string>\r\n"
149+
"--{0}--\r\n"
150+
"".format(boundary).encode("utf-8")
151+
)
152+
assert headers == {
153+
"Content-Type": f"multipart/form-data; boundary={boundary}",
154+
"Content-Length": str(len(content)),
155+
}
156+
assert content == b"".join(stream)
157+
158+
136159
def test_multipart_encode_files_allows_filenames_as_none() -> None:
137160
files = {"file": (None, io.BytesIO(b"<file content>"))}
138161
with mock.patch("os.urandom", return_value=os.urandom(16)):

0 commit comments

Comments
 (0)