[azure-core] Fix wrong content-type on multipart request with no file (#39163)#47831
[azure-core] Fix wrong content-type on multipart request with no file (#39163)#47831manmohanmirkar123 wants to merge 3 commits into
Conversation
When a multipart payload's file part is optional and omitted, azure-core inferred the request was not multipart (because `files` was empty) and set Content-Type to application/x-www-form-urlencoded. Add an `is_multipart_payload` flag to HttpRequest so callers can mark such a request as multipart; when set, the urlencoded content-type is not applied and the transport sets the correct multipart boundary. Fixes Azure#39163
|
Thank you for your contribution @manmohanmirkar123! We will review the pull request and get back to you soon. |
|
@microsoft-github-policy-service agree |
There was a problem hiding this comment.
Pull request overview
This PR targets azure-core’s REST HttpRequest body handling to avoid incorrectly forcing Content-Type: application/x-www-form-urlencoded for multipart form payloads when the (optional) file part is omitted, which breaks TypeSpec-generated multipart requests (issue #39163).
Changes:
- Threads a new internal
is_multipart_payloadintent flag intoHttpRequest._set_bodyto avoid applying the urlencodedContent-Type. - Adds regression tests covering the new multipart-without-file scenario and ensuring the default urlencoded behavior remains unchanged.
- Adds an unreleased changelog entry documenting the fix.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| sdk/core/azure-core/azure/core/rest/_rest_py3.py | Adds is_multipart_payload plumbing into request body setup to avoid urlencoded Content-Type for intended multipart payloads. |
| sdk/core/azure-core/tests/test_rest_http_request.py | Adds regression tests for multipart form data without files and for default urlencoding behavior. |
| sdk/core/azure-core/CHANGELOG.md | Documents the behavioral change under an unreleased version entry. |
| if files: | ||
| default_headers, self._files = set_multipart_body(files) | ||
| if data: | ||
| default_headers, self._data = set_urlencoded_body(data, has_files=bool(files)) | ||
| # Treat the payload as multipart when explicitly requested, so a multipart | ||
| # request whose only file part is optional (and omitted) is not encoded as | ||
| # application/x-www-form-urlencoded. | ||
| default_headers, self._data = set_urlencoded_body( | ||
| data, has_files=bool(files) or is_multipart_payload | ||
| ) |
| assert "Content-Type" not in request.headers | ||
| assert request.content == {"test": "123"} |
|
|
||
| ### Bugs Fixed | ||
|
|
||
| - Fixed `HttpRequest` setting a `Content-Type` of `application/x-www-form-urlencoded` on multipart requests that carry form data but no file (e.g. when the file part is optional and omitted). Such requests can now be flagged with the internal `is_multipart_payload` keyword so the transport sets the correct multipart `Content-Type`. #39163 |
Addresses review feedback: previously `is_multipart_payload` only suppressed the urlencoded Content-Type, but transports decide multipart vs urlencoded based on `request.files`, so a data-only payload was still sent urlencoded. When `is_multipart_payload` is set and no files are provided, encode the form fields as file-less multipart parts (name, (None, value)) in `self._files` and clear `self._data`, so both the requests and aiohttp transports build a real multipart/form-data body. Update the regression test to assert the multipart parts and the changelog to match the wire behavior.
|
Thanks for the review — addressed the multipart feedback in |
The CHANGELOG has a `1.42.0 (Unreleased)` section for the multipart fix, but `_version.py` was still `1.41.0` (already released), so the changelog verification failed. Bump the package version to match.
Summary
Fixes #39163.
When a multipart payload's file part is optional and omitted,
azure-coreinferred that the request was not multipart — because it decided based solely on whetherfileswas non-empty — and setContent-Type: application/x-www-form-urlencoded. This mislabels a request that should be sent asmultipart/form-data(e.g. a TypeSpec-defined body whose only file part is optional).Change
Add an
is_multipart_payloadflag toHttpRequest, threaded into_set_body. When set, the urlencodedContent-Typeis not applied, so the transport can set the correctmultipart/form-databoundary even when no file is present.Default behavior is unchanged: a
data-only request without the flag is still urlencoded.Testing
test_rest_http_request.py:Content-Typedata-only request without the flag still setsapplication/x-www-form-urlencodedChangelog
Added a
Bugs Fixedentry under an unreleasedazure-coresection.