From e0ac000415aa95b06767f472e902429ccb76ab61 Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Tue, 24 Oct 2023 12:09:11 +0200 Subject: [PATCH] Allow repeatable writes in StreamingHttpOutputMessage This commit adds a repeatable property to StreamingHttpOutputMessage.Body, indicating that the body can be written multiple times. In HttpComponentsClientHttpRequest, this property is exposed via org.apache.hc.core5.http.HttpEntity.isRepeatable, to allow for redirects. Closes gh-31449 --- .../http/StreamingHttpOutputMessage.java | 14 +++++++++++++- .../client/BufferingClientHttpRequestWrapper.java | 13 ++++++++++++- .../client/HttpComponentsClientHttpRequest.java | 4 ++-- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/spring-web/src/main/java/org/springframework/http/StreamingHttpOutputMessage.java b/spring-web/src/main/java/org/springframework/http/StreamingHttpOutputMessage.java index a88b5ddb6677..b56856020f05 100644 --- a/spring-web/src/main/java/org/springframework/http/StreamingHttpOutputMessage.java +++ b/spring-web/src/main/java/org/springframework/http/StreamingHttpOutputMessage.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -50,6 +50,18 @@ interface Body { * @throws IOException in case of I/O errors */ void writeTo(OutputStream outputStream) throws IOException; + + /** + * Indicates whether this body is capable of + * {@linkplain #writeTo(OutputStream) writing its data} more than + * once. Default implementation returns {@code false}. + * @return {@code true} if this body can be written repeatedly, + * {@code false} otherwise + * @since 6.1 + */ + default boolean repeatable() { + return false; + } } } diff --git a/spring-web/src/main/java/org/springframework/http/client/BufferingClientHttpRequestWrapper.java b/spring-web/src/main/java/org/springframework/http/client/BufferingClientHttpRequestWrapper.java index 680921ffc04b..47adf2431db6 100644 --- a/spring-web/src/main/java/org/springframework/http/client/BufferingClientHttpRequestWrapper.java +++ b/spring-web/src/main/java/org/springframework/http/client/BufferingClientHttpRequestWrapper.java @@ -17,6 +17,7 @@ package org.springframework.http.client; import java.io.IOException; +import java.io.OutputStream; import java.net.URI; import org.springframework.http.HttpHeaders; @@ -55,7 +56,17 @@ protected ClientHttpResponse executeInternal(HttpHeaders headers, byte[] buffere this.request.getHeaders().putAll(headers); if (this.request instanceof StreamingHttpOutputMessage streamingHttpOutputMessage) { - streamingHttpOutputMessage.setBody(outputStream -> StreamUtils.copy(bufferedOutput, outputStream)); + streamingHttpOutputMessage.setBody(new StreamingHttpOutputMessage.Body() { + @Override + public void writeTo(OutputStream outputStream) throws IOException { + StreamUtils.copy(bufferedOutput, outputStream); + } + + @Override + public boolean repeatable() { + return true; + } + }); } else { StreamUtils.copy(bufferedOutput, this.request.getBody()); diff --git a/spring-web/src/main/java/org/springframework/http/client/HttpComponentsClientHttpRequest.java b/spring-web/src/main/java/org/springframework/http/client/HttpComponentsClientHttpRequest.java index ec1e6d33ee5f..a14d8ef8cbef 100644 --- a/spring-web/src/main/java/org/springframework/http/client/HttpComponentsClientHttpRequest.java +++ b/spring-web/src/main/java/org/springframework/http/client/HttpComponentsClientHttpRequest.java @@ -153,12 +153,12 @@ public void writeTo(OutputStream outStream) throws IOException { @Override public boolean isRepeatable() { - return false; + return this.body.repeatable(); } @Override public boolean isStreaming() { - return true; + return false; } @Override