From 2b90646877e70d053ca452df704c0a977639a3f9 Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Tue, 17 Oct 2023 10:56:58 -0700 Subject: [PATCH 1/3] capture request.data for aiohttp multipart-formdata --- sdk/core/azure-core/azure/core/pipeline/transport/_aiohttp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/core/azure-core/azure/core/pipeline/transport/_aiohttp.py b/sdk/core/azure-core/azure/core/pipeline/transport/_aiohttp.py index 9c525533211a..aef5f64c601f 100644 --- a/sdk/core/azure-core/azure/core/pipeline/transport/_aiohttp.py +++ b/sdk/core/azure-core/azure/core/pipeline/transport/_aiohttp.py @@ -164,7 +164,7 @@ def _get_request_data(self, request): :return: The request data """ if request.files: - form_data = aiohttp.FormData() + form_data = aiohttp.FormData(request.data or {}) for form_file, data in request.files.items(): content_type = data[2] if len(data) > 2 else None try: From ce06f5632109a7fe93e6b58ab1af770ea5e794d1 Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Tue, 17 Oct 2023 10:57:09 -0700 Subject: [PATCH 2/3] add tests --- .../test_rest_http_response_async.py | 27 +++++++++++----- .../coretestserver/test_routes/multipart.py | 31 ++++++++++++++++--- 2 files changed, 45 insertions(+), 13 deletions(-) diff --git a/sdk/core/azure-core/tests/async_tests/test_rest_http_response_async.py b/sdk/core/azure-core/tests/async_tests/test_rest_http_response_async.py index 5945aafb4abf..d59b3ea44faf 100644 --- a/sdk/core/azure-core/tests/async_tests/test_rest_http_response_async.py +++ b/sdk/core/azure-core/tests/async_tests/test_rest_http_response_async.py @@ -221,14 +221,25 @@ async def test_urlencoded_content(send_request): ) -# @pytest.mark.asyncio -# async def test_multipart_files_content(send_request): -# request = HttpRequest( -# "POST", -# "/multipart/basic", -# files={"fileContent": io.BytesIO(b"")}, -# ) -# await send_request(request) +@pytest.mark.asyncio +async def test_multipart_files_content(send_request): + request = HttpRequest( + "POST", + "/multipart/basic", + files={"fileContent": io.BytesIO(b"")}, + ) + await send_request(request) + + +@pytest.mark.asyncio +async def test_multipart_data_and_files_content(send_request): + request = HttpRequest( + "POST", + "/multipart/data-and-files", + data={"message": "Hello, world!"}, + files={"fileContent": io.BytesIO(b"")}, + ) + await send_request(request) @pytest.mark.asyncio diff --git a/sdk/core/azure-core/tests/testserver_tests/coretestserver/coretestserver/test_routes/multipart.py b/sdk/core/azure-core/tests/testserver_tests/coretestserver/coretestserver/test_routes/multipart.py index 19bcf537db46..48849b1382e1 100644 --- a/sdk/core/azure-core/tests/testserver_tests/coretestserver/coretestserver/test_routes/multipart.py +++ b/sdk/core/azure-core/tests/testserver_tests/coretestserver/coretestserver/test_routes/multipart.py @@ -26,7 +26,7 @@ def basic(): assert_with_message("content type", multipart_header_start, request.content_type[: len(multipart_header_start)]) if request.files: # aiohttp - assert_with_message("content length", 258, request.content_length) + assert_with_message("content length", 228, request.content_length) assert_with_message("num files", 1, len(request.files)) assert_with_message("has file named fileContent", True, bool(request.files.get("fileContent"))) file_content = request.files["fileContent"] @@ -38,7 +38,7 @@ def basic(): ) assert_with_message( "content disposition", - 'form-data; name="fileContent"; filename="fileContent"; filename*=utf-8\'\'fileContent', + 'form-data; name="fileContent"; filename="fileContent"', file_content.headers["Content-Disposition"], ) elif request.form: @@ -52,9 +52,30 @@ def basic(): @multipart_api.route("/data-and-files", methods=["POST"]) def data_and_files(): - assert_with_message("content type", multipart_header_start, request.content_type[: len(multipart_header_start)]) - assert_with_message("message", "Hello, world!", request.form["message"]) - assert_with_message("message", "", request.form["fileContent"]) + if request.files: + # aiohttp + assert_with_message("content type", multipart_header_start, request.content_type[: len(multipart_header_start)]) + assert_with_message("has file named fileContent", True, bool(request.files.get("fileContent"))) + assert_with_message("message", "Hello, world!", request.form["message"]) + file_content = request.files["fileContent"] + assert_with_message("file content type", "application/octet-stream", file_content.content_type) + assert_with_message("file content length", 14, file_content.content_length) + assert_with_message("filename", "fileContent", file_content.filename) + assert_with_message( + "has content disposition header", True, bool(file_content.headers.get("Content-Disposition")) + ) + assert_with_message( + "content disposition", + 'form-data; name="fileContent"; filename="fileContent"', + file_content.headers["Content-Disposition"], + ) + elif request.form: + # requests + assert_with_message("content type", multipart_header_start, request.content_type[: len(multipart_header_start)]) + assert_with_message("message", "Hello, world!", request.form["message"]) + assert_with_message("message", "", request.form["fileContent"]) + else: + return Response(status=400) return Response(status=200) From c1a3f8f1c7fbe65ff517585e3413664783a2451c Mon Sep 17 00:00:00 2001 From: Krista Pratico Date: Wed, 18 Oct 2023 14:15:15 -0700 Subject: [PATCH 3/3] add changelog entry --- sdk/core/azure-core/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sdk/core/azure-core/CHANGELOG.md b/sdk/core/azure-core/CHANGELOG.md index 3da8217bdc40..c9f2bd3803db 100644 --- a/sdk/core/azure-core/CHANGELOG.md +++ b/sdk/core/azure-core/CHANGELOG.md @@ -8,6 +8,8 @@ ### Bugs Fixed +- Fixed an issue with `multipart/form-data` in the async transport where `data` was not getting encoded into the request body. #32473 + ### Other Changes ## 1.29.4 (2023-09-07)