Avoid default Content-Type on POST/PUT/PATCH with empty body - #3507
Open
seonwooj0810 wants to merge 1 commit into
Open
Avoid default Content-Type on POST/PUT/PATCH with empty body#3507seonwooj0810 wants to merge 1 commit into
seonwooj0810 wants to merge 1 commit into
Conversation
DefaultClient wrote a zero-length byte array to the connection's output stream whenever the HTTP method was not GET, even when the request body was empty. Opening that output stream makes HttpURLConnection create an internal "poster" and, as soon as one exists, the JDK defaults Content-Type to application/x-www-form-urlencoded if none was set - even though no bytes are actually written. This regressed in 12.0 (feign#1778, fixing the Content-Length: 0 case) and silently adds an incorrect Content-Type header, which can cause servers to reject the request with 415 Unsupported Media Type. Skip the output stream entirely for empty/absent bodies and set Content-Length: 0 directly, matching the existing null-body path. Fixes OpenFeign#2068 Signed-off-by: seonwoo_jung <79202163+seonwooj0810@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #2068
Problem
DefaultClientopens the connection's output stream and writes to it whenever the request body is non-null, even if it is a zero-length array.HttpURLConnectioncreates an internal "poster" as soon as an output stream is requested, and defaultsContent-Typetoapplication/x-www-form-urlencodedif none was explicitly set — regardless of whether any bytes are actually written. This is undocumented JDK behavior (see the JDK'sHttpURLConnectionsource referenced in the issue).This causes POST/PUT/PATCH requests with an empty body (e.g. an empty
Stringargument, which encodes to a non-null zero-lengthbyte[]) to silently get an incorrectContent-Typeheader, which can make servers reject the request with415 Unsupported Media Type.#2555 partially addressed this by no longer synthesizing a fake empty
byte[]for anullbody (avoiding the output stream in that specific case), but it left the output stream path in place for any body that is non-null withlength == 0— which is exactly what happens whenever a caller explicitly sends an empty body. That's why the issue was left open after #2555 merged.Fix
Skip
connection.getOutputStream()entirely whenever the body is empty (nullor zero-length) for methods that carry a body (POST/PUT/PATCH), and setContent-Length: 0directly instead — mirroring the existingnull-body path. Non-empty bodies are unaffected.Testing
Added
emptyStringBodyForPost()toAbstractClientTest/DefaultClientTest, asserting a POST with an explicit empty-string body does not get aContent-Typeheader. Confirmed the test fails onmaster(reproducing the reported header) and passes with this change.Ran the full test suite for
core,java11,googlehttpclient,okhttp,hc5,httpclient, andjaxrs2(all modules sharingAbstractClientTest) — all green, no regressions in otherClientimplementations.Verification done:
.java), no docs.master(greppedDefaultClient.convertAndSend) that the empty-non-null-body path still callsgetOutputStream()/write(), and reproduced the bug with a new test before applying the fix.spring-projects/*repo, so the triage gate doesn't apply; issue already carriesbug+help wantedlabels.