This commit adds integration tests and reference documentation
for multipart support in `RestClient` and `RestTestClient`.
Closes gh-35569
Closes gh-33263
Prior to this commit, the `FormHttpMessageConverter` would only support
`MultiValueMap` payloads for reading and writing. While this can be
useful when web forms contain multiple values under the same key, this
prevent developers from using a common `Map` type and factory methods
like `Map.of(...)`.
This commit relaxes constraints in `FormHttpMessageConverter` and
ensures that `Map` types are supported for reading and writing URL
encoded forms.
Note that when reading forms to a `Map`, only the first value for each
key will be considered and other values will be dropped if they exist.
Closes gh-36408
Prior to this commit, gh-36255 introduced the new
`MultipartHttpMessageConverter`, focusing on multipart message
conversion in a separate converter. The `FormHttpMessageConverter` did
conflate URL encoded forms and multipart messages in the same converter.
With the introduction of the new converter and related types in the same
package (with `Part`, `FormFieldPart` and `FilePart`), we can now
revisit this arrangement.
This commit restricts the `FormHttpMessageConverter` to URL encoded
forms only and as a result, changes its implementation to only consider
`MultiValueMap<String, String>` types for reading and writing HTTP
messages. Because type erasure, this converter is now a
`SmartHttpMessageConverter` to get better type information with
`ResolvableType`.
As a result, the `AllEncompassingFormHttpMessageConverter` is formally
deprecated and replaced by the `MultipartHttpMessageConverter`, by
setting part converters explicitly in its constructor.
Closes gh-36256
Prior to this commit, the `FormHttpMessageConverter` would write, but
not read, multipart HTTP messages. Reading multipart messages is
typicaly performed by Servlet containers with Spring's
`MultipartResolver` infrastructure.
This commit introduces a new `MultipartHttpMessageConverter` that copies
the existing feature for writing multipart messages, borrowed from
`FormHttpMessageConverter`. This also introduces a new `MultipartParser`
class that is an imperative port of the reactive variant, but keeping it
based on the `DataBuffer` abstraction. This will allow us to maintain
both side by side more easily.
This change also adds new `Part`, `FilePart` and `FormFieldPart` types
that will be used when converting multipart messages to
`MultiValueMap<String, Part>` maps.
Closes gh-36255
The `AbstractHttpMessageConverter#supportsRepeatableWrites`
contract is a protected method that message converters can override.
This method tells whether the current converter can write several
times the payload given as a parameter. This is mainly useful on the
client side, where we need to know if we can send the same HTTP
message again, after receiving an HTTP redirect status.
Because this method is protected, this limits our ability to call
it from a different package; this is needed for gh-33263.
This commit promotes this method to the main `HttpMessageConverter`
interface and deprecates the former.
Closes gh-36252
Prior to this commit, `HttpMessageConverters` would consider the JAXB
message converters when building `HttpMessageConverters` instances.
We noticed that, on the server side, the Jakarta JAXB dependency is very
common on the classpath and often brought transitively. At runtime, this
converter can use significant CPU resources when checking the
`canRead`/`canWrite` methods. This can happen when content types aren't
strictly called out on controller endpoints.
This commit changes the auto-detection mechanism in
`HttpMessageConverters` to not consider the JAXB message converter for
server use cases.
For client use cases, we keep considering this converter as the runtime
cost there is lower.
Closes gh-36302
Prior to this commit, the `DefaultRestClient` implementation would
look at the type of the returned value to decide whether the HTTP
response stream needs to be closed before returning.
As of gh-36380, this checks for `InputStream` and `InputStreamResource`
return types, effectively not considering `ResponseEntity<InputStream>`
and variants.
This commit ensures that `ResponseEntity` types are unwrapped before
checking for streaming types.
Fixes gh-36492
Although this commit also changes the visibility of some test methods
to package-private, the remainder of that task will be addressed in
conjunction with gh-36496.
Closes gh-36495
Updates the Content-Disposition header creation logic to use only
ISO-8859-1 characters for the fallback 'filename' parameter instead of
RFC 2047 encoded strings. Non-compatible characters are replaced with '_'.
This does not remove the ability to parse RFC 2047 encoded filenames.
Closes gh-36328
Signed-off-by: Tobias Fasching <tobias.fasching@outlook.com>
Prior to this commit, Spring web frameworks were using the
"application/x-ndjson" media type for streaming JSON payloads delimited
with newlines.
The "application/jsonl" media type seems to gain popularity in the
broader ecosystem and could supersede NDJSON in the future. This commit
adds support for JSON Lines as an alternative.
Closes gh-36485
Since the Spring Framework uses American English spelling, this commit
updates Javadoc and the reference manual to ensure consistency in that
regard. However, there are two exceptions to this rule that arise due
to their use within a technical context.
- We use "cancelled/cancelling" instead of "canceled/canceling" in
numerous places (including error messages).
- We use "implementor" instead of "implementer".
Closes gh-36470
Prior to this commit, the `setMessageConverters` method would have
private visibility. But `initBodyConvertFunction`, which is `protected`,
relies on the message converters being set in the first place.
While this works with `RestTemplate` because this is done automatically,
the `RestClient` does offer a builder method to configure a
`ResponseErrorHandler` and this makes it impossible to configure
converters in this case.
This commit aligns the method visibility by making it protected.
Closes gh-36434
Prior to this commit, our implementation of Server Sent Events (SSE),
`SseEmitter` (MVC) and `ServerSentEvent` (WebFlux), would not guard
against invalid characters if the application mistakenly inserts such
characters in the `id` or `event` types.
Both implementations would also behave differently when it comes
to escaping comment multi-line events.
This commit ensures that both implementations handle multi-line comment
events and reject invalid characters in id/event types.
This commit also optimizes `String` concatenation and memory usage
when writing data.
Fixes gh-36440
The RequestHeaderOverrideWrapper did not deduplicate in keySet()
across underlying headers and overrides.
A similar change in size() even if it was working correctly,
to align with keySet and make it more efficient.
Closes gh-36418
The methods to build a request in RestClientAdapter and WebClientAdapter
are now public to make it easier to create a custom adapter that wraps
the built-in ones and delegates for methods that can be the same.
Closes gh-36374
Prior to this commit, flush calls on the output stream returned by
`ServletServerHttpResponse#getBody` would be delegated to the Servlet
response output stream.
This can cause performance issues when `HttpMessageConverter` and other
web components write and flush multiple times to the response body.
Here, the Servlet container is in a better position to flush to the
network at the optimal time and buffer the response body until then.
This is particularly true for `HttpMessageConverters` when they flush
many times the output stream, sometimes due to the underlying codec
library. Instead of revisiting the entire message converter contract, we
are here ignoring flush calls to that output stream.
This change does not affect the client side, nor the
`ServletServerHttpResponse#flush` calls.
This commit also introduces a new Spring property
`"spring.http.response.flush.enabled"` that reverts this behavior change
if necessary.
Closes gh-36385
Prior to this commit, a few implementations of the `HttpMessageConverter`
contract were inheriting from abstract classes. Those classes were
performing extra `OutputStream#flush` on the response body even though
this is the responsibility of the super class. Such abstract classes
do flush already, after delegating to the `writeInternal` method.
This commit ensures that we remove such extra calls as they tend to
waste resources for no added benefit.
Closes gh-36383
This commit updates the target type detection in
`ResourceHttpMessageConverter` to only support target types that are
relevant: `InputStreamResource` for streaming, and types assignable from
`ByteArrayResource` for non-streaming cases.
Closes gh-36368