diff --git a/spring-web/src/main/java/org/springframework/http/HttpHeaders.java b/spring-web/src/main/java/org/springframework/http/HttpHeaders.java index 68243145fb..d966c245c2 100644 --- a/spring-web/src/main/java/org/springframework/http/HttpHeaders.java +++ b/spring-web/src/main/java/org/springframework/http/HttpHeaders.java @@ -874,7 +874,7 @@ public class HttpHeaders implements MultiValueMap, Serializable /** * Set the {@link Locale} of the content language, * as specified by the {@literal Content-Language} header. - *

Use {@code set(CONTENT_LANGUAGE, ...)} if you need + *

Use {@code set(CONTENT_LANGUAGE, list)} if you need * to set multiple content languages.

* @since 5.0 */ diff --git a/spring-web/src/main/java/org/springframework/http/codec/EncoderHttpMessageWriter.java b/spring-web/src/main/java/org/springframework/http/codec/EncoderHttpMessageWriter.java index ddc71bbeea..af0dde1289 100644 --- a/spring-web/src/main/java/org/springframework/http/codec/EncoderHttpMessageWriter.java +++ b/spring-web/src/main/java/org/springframework/http/codec/EncoderHttpMessageWriter.java @@ -119,7 +119,8 @@ public class EncoderHttpMessageWriter implements HttpMessageWriter { if (inputStream instanceof Mono) { HttpHeaders headers = message.getHeaders(); - return Mono.from(body) + return body + .singleOrEmpty() .switchIfEmpty(Mono.defer(() -> { headers.setContentLength(0); return message.setComplete().then(Mono.empty()); diff --git a/spring-web/src/test/java/org/springframework/http/codec/EncoderHttpMessageWriterTests.java b/spring-web/src/test/java/org/springframework/http/codec/EncoderHttpMessageWriterTests.java index 095016237d..1f09ff8d33 100644 --- a/spring-web/src/test/java/org/springframework/http/codec/EncoderHttpMessageWriterTests.java +++ b/spring-web/src/test/java/org/springframework/http/codec/EncoderHttpMessageWriterTests.java @@ -33,6 +33,7 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; +import org.springframework.core.codec.CharSequenceEncoder; import org.springframework.core.io.buffer.DataBuffer; import org.springframework.core.io.buffer.DefaultDataBufferFactory; import org.springframework.http.MediaType; @@ -136,9 +137,7 @@ public class EncoderHttpMessageWriterTests { @Test public void useNegotiatedMediaTypeCharset() { - MediaType negotiatedMediaType = new MediaType("text", "html", ISO_8859_1); - HttpMessageWriter writer = getWriter(TEXT_PLAIN_UTF_8, TEXT_HTML); writer.write(Mono.just("body"), forClass(String.class), negotiatedMediaType, this.response, NO_HINTS); @@ -148,7 +147,6 @@ public class EncoderHttpMessageWriterTests { @Test public void useHttpOutputMessageMediaType() { - MediaType outputMessageMediaType = MediaType.TEXT_HTML; this.response.getHeaders().setContentType(outputMessageMediaType); @@ -161,16 +159,25 @@ public class EncoderHttpMessageWriterTests { @Test public void setContentLengthForMonoBody() { - DefaultDataBufferFactory factory = new DefaultDataBufferFactory(); DataBuffer buffer = factory.wrap("body".getBytes(StandardCharsets.UTF_8)); HttpMessageWriter writer = getWriter(Flux.just(buffer), MimeTypeUtils.TEXT_PLAIN); - writer.write(Mono.just("body"), forClass(String.class), TEXT_PLAIN, this.response, NO_HINTS).block(); assertEquals(4, this.response.getHeaders().getContentLength()); } + @Test // gh-22952 + public void monoBodyDoesNotCancelEncodedFlux() { + Mono inputStream = Mono.just("body") + .doOnCancel(() -> { + throw new AssertionError("Cancel signal not expected"); + }); + new EncoderHttpMessageWriter<>(CharSequenceEncoder.allMimeTypes()) + .write(inputStream, forClass(String.class), TEXT_PLAIN, this.response, NO_HINTS) + .block(); + } + @Test // SPR-17220 public void emptyBodyWritten() { HttpMessageWriter writer = getWriter(MimeTypeUtils.TEXT_PLAIN); diff --git a/src/docs/asciidoc/web/webmvc.adoc b/src/docs/asciidoc/web/webmvc.adoc index 7dafe93760..3a56b07d06 100644 --- a/src/docs/asciidoc/web/webmvc.adoc +++ b/src/docs/asciidoc/web/webmvc.adoc @@ -4515,8 +4515,7 @@ The following example shows how to achieve the same configuration in XML: [subs="verbatim"] ---- - - + @@ -4533,7 +4532,7 @@ bean so that it can be injected into others. You can also make the rewrite trans rely on `HttpServletResponse#encodeURL`. Note that, when using both `EncodedResourceResolver` (for example, for serving gzipped or -brotli-encoded resources) and `VersionedResourceResolver`, you must register them in this order. +brotli-encoded resources) and `VersionResourceResolver`, you must register them in this order. That ensures content-based versions are always computed reliably, based on the unencoded file. https://www.webjars.org/documentation[WebJars] are also supported through the