Skip to content

Commit 422388a

Browse files
aiohttp multipart/form-data fix applied to corehttp (#32581)
* same aiohttp multipart/form-data fix applied to azure-core * add changelog entry * no backcompat in corehttp, need to access _data * bump version manually
1 parent def1f2b commit 422388a

File tree

5 files changed

+60
-15
lines changed

5 files changed

+60
-15
lines changed

sdk/core/corehttp/CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
# Release History
22

3+
## 1.0.0b2 (Unreleased)
4+
5+
### Features Added
6+
7+
### Breaking Changes
8+
9+
### Bugs Fixed
10+
11+
- Fixed an issue with `multipart/form-data` in the async transport where `data` was not getting encoded into the request body. #32473
12+
13+
### Other Changes
14+
315
## 1.0.0b1 (2023-10-18)
416

517
* Initial Release

sdk/core/corehttp/corehttp/_version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@
99
# regenerated.
1010
# --------------------------------------------------------------------------
1111

12-
VERSION = "1.0.0b1"
12+
VERSION = "1.0.0b2"

sdk/core/corehttp/corehttp/transport/aiohttp/_aiohttp.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ def _get_request_data(self, request: RestHttpRequest):
136136
:return: The request data
137137
"""
138138
if request._files: # pylint: disable=protected-access
139-
form_data = aiohttp.FormData()
139+
form_data = aiohttp.FormData(request._data or {}) # pylint: disable=protected-access
140140
for form_file, data in request._files.items(): # pylint: disable=protected-access
141141
content_type = data[2] if len(data) > 2 else None
142142
try:

sdk/core/corehttp/tests/async_tests/test_rest_http_response_async.py

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
# NOTE: These tests are heavily inspired from the httpx test suite: https://github.com/encode/httpx/tree/master/tests
88
# Thank you httpx for your wonderful tests!
9+
import io
910
import pytest
1011

1112
from corehttp.rest import HttpRequest, AsyncHttpResponse
@@ -220,14 +221,25 @@ async def test_urlencoded_content(send_request):
220221
)
221222

222223

223-
# @pytest.mark.asyncio
224-
# async def test_multipart_files_content(send_request):
225-
# request = HttpRequest(
226-
# "POST",
227-
# "/multipart/basic",
228-
# files={"fileContent": io.BytesIO(b"<file content>")},
229-
# )
230-
# await send_request(request)
224+
@pytest.mark.asyncio
225+
async def test_multipart_files_content(send_request):
226+
request = HttpRequest(
227+
"POST",
228+
"/multipart/basic",
229+
files={"fileContent": io.BytesIO(b"<file content>")},
230+
)
231+
await send_request(request)
232+
233+
234+
@pytest.mark.asyncio
235+
async def test_multipart_data_and_files_content(send_request):
236+
request = HttpRequest(
237+
"POST",
238+
"/multipart/data-and-files",
239+
data={"message": "Hello, world!"},
240+
files={"fileContent": io.BytesIO(b"<file content>")},
241+
)
242+
await send_request(request)
231243

232244

233245
@pytest.mark.asyncio

sdk/core/corehttp/tests/testserver_tests/coretestserver/coretestserver/test_routes/multipart.py

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ def basic():
2525
assert_with_message("content type", multipart_header_start, request.content_type[: len(multipart_header_start)])
2626
if request.files:
2727
# aiohttp
28-
assert_with_message("content length", 258, request.content_length)
28+
assert_with_message("content length", 228, request.content_length)
2929
assert_with_message("num files", 1, len(request.files))
3030
assert_with_message("has file named fileContent", True, bool(request.files.get("fileContent")))
3131
file_content = request.files["fileContent"]
@@ -37,7 +37,7 @@ def basic():
3737
)
3838
assert_with_message(
3939
"content disposition",
40-
'form-data; name="fileContent"; filename="fileContent"; filename*=utf-8\'\'fileContent',
40+
'form-data; name="fileContent"; filename="fileContent"',
4141
file_content.headers["Content-Disposition"],
4242
)
4343
elif request.form:
@@ -51,9 +51,30 @@ def basic():
5151

5252
@multipart_api.route("/data-and-files", methods=["POST"])
5353
def data_and_files():
54-
assert_with_message("content type", multipart_header_start, request.content_type[: len(multipart_header_start)])
55-
assert_with_message("message", "Hello, world!", request.form["message"])
56-
assert_with_message("message", "<file content>", request.form["fileContent"])
54+
if request.files:
55+
# aiohttp
56+
assert_with_message("content type", multipart_header_start, request.content_type[: len(multipart_header_start)])
57+
assert_with_message("has file named fileContent", True, bool(request.files.get("fileContent")))
58+
assert_with_message("message", "Hello, world!", request.form["message"])
59+
file_content = request.files["fileContent"]
60+
assert_with_message("file content type", "application/octet-stream", file_content.content_type)
61+
assert_with_message("file content length", 14, file_content.content_length)
62+
assert_with_message("filename", "fileContent", file_content.filename)
63+
assert_with_message(
64+
"has content disposition header", True, bool(file_content.headers.get("Content-Disposition"))
65+
)
66+
assert_with_message(
67+
"content disposition",
68+
'form-data; name="fileContent"; filename="fileContent"',
69+
file_content.headers["Content-Disposition"],
70+
)
71+
elif request.form:
72+
# requests
73+
assert_with_message("content type", multipart_header_start, request.content_type[: len(multipart_header_start)])
74+
assert_with_message("message", "Hello, world!", request.form["message"])
75+
assert_with_message("message", "<file content>", request.form["fileContent"])
76+
else:
77+
return Response(status=400)
5778
return Response(status=200)
5879

5980

0 commit comments

Comments
 (0)