-
Notifications
You must be signed in to change notification settings - Fork 38.9k
Description
Duplicate response headers with Kotlin suspend function returning ResponseEntity after header adapter optimization
Affects: Spring Framework 7.0.5 (Spring Boot 4.0.3)
Maybe introduced in: 7ea11baff9 (Pass-through handling of Servlet headers, gh-36334)
Description
After the Servlet header adapter optimization introduced in gh-36334, response headers are duplicated when a Kotlin suspend fun controller method returns ResponseEntity<T> in Spring WebMVC.
The root cause is in ResponseBodyEmitterReturnValueHandler.handleReturnValue(). In the non-streaming path (single-value reactive type adapted to DeferredResult), headers that are already present in the HttpServletResponse are read back through the adapter and re-added via addHeader(), resulting in every header appearing twice.
First, the header is copied here.
Line 56 in 7ea11ba
this.headers = new HttpHeaders(new ServletResponseHeadersAdapter(servletResponse));
The http header is also duplicated in the outputMessage.
Lines 189 to 191 in 188cb9b
HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class); Assert.state(response != null, "No HttpServletResponse"); ServerHttpResponse outputMessage = new ServletServerHttpResponse(response);
response.addHeader causes a duplicate header in the original response.
Lines 218 to 222 in 188cb9b
outputMessage.getHeaders().forEach((headerName, headerValues) -> { for (String headerValue : headerValues) { response.addHeader(headerName, headerValue); } });
Steps to Reproduce
- Configure a
CorsFilteror@CrossOriginannotation - Define a Kotlin suspend controller that returns
ResponseEntity<T>:
@RestController
class MyController {
@GetMapping("/example")
suspend fun example(): ResponseEntity<String> {
return ResponseEntity.ok()
.header("X-Custom", "value")
.body("hello")
}
}- Send a cross-origin request to
/example - Observe the response headers
Expected Behavior
Each header appears once in the response
Actual Behavior
Headers are duplicated