Skip to content

Commit 2cac3a8

Browse files
committed
InterceptingClientHttpRequest adapts to StreamingHttpOutputMessage
Issue: SPR-16582 (cherry picked from commit 4173022)
1 parent 25a3019 commit 2cac3a8

12 files changed

+116
-57
lines changed

spring-web/src/main/java/org/springframework/http/HttpInputMessage.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -34,7 +34,7 @@ public interface HttpInputMessage extends HttpMessage {
3434
/**
3535
* Return the body of the message as an input stream.
3636
* @return the input stream body (never {@code null})
37-
* @throws IOException in case of I/O Errors
37+
* @throws IOException in case of I/O errors
3838
*/
3939
InputStream getBody() throws IOException;
4040

spring-web/src/main/java/org/springframework/http/HttpOutputMessage.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -34,7 +34,7 @@ public interface HttpOutputMessage extends HttpMessage {
3434
/**
3535
* Return the body of the message as an output stream.
3636
* @return the output stream body (never {@code null})
37-
* @throws IOException in case of I/O Errors
37+
* @throws IOException in case of I/O errors
3838
*/
3939
OutputStream getBody() throws IOException;
4040

spring-web/src/main/java/org/springframework/http/StreamingHttpOutputMessage.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -30,23 +30,23 @@
3030
public interface StreamingHttpOutputMessage extends HttpOutputMessage {
3131

3232
/**
33-
* Set the streaming body for this message.
34-
* @param body the streaming body
33+
* Set the streaming body callback for this message.
34+
* @param body the streaming body callback
3535
*/
3636
void setBody(Body body);
3737

3838

3939
/**
40-
* Defines the contract for bodies that can be written directly to an {@link OutputStream}.
41-
* It is useful with HTTP client libraries that provide indirect access to an
42-
* {@link OutputStream} via a callback mechanism.
40+
* Defines the contract for bodies that can be written directly to an
41+
* {@link OutputStream}. Useful with HTTP client libraries that provide
42+
* indirect access to an {@link OutputStream} via a callback mechanism.
4343
*/
4444
interface Body {
4545

4646
/**
4747
* Write this body to the given {@link OutputStream}.
4848
* @param outputStream the output stream to write to
49-
* @throws IOException in case of errors
49+
* @throws IOException in case of I/O errors
5050
*/
5151
void writeTo(OutputStream outputStream) throws IOException;
5252
}

spring-web/src/main/java/org/springframework/http/client/ClientHttpRequestInterceptor.java

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -21,36 +21,39 @@
2121
import org.springframework.http.HttpRequest;
2222

2323
/**
24-
* Intercepts client-side HTTP requests. Implementations of this interface can be {@linkplain
25-
* org.springframework.web.client.RestTemplate#setInterceptors(java.util.List) registered} with the
26-
* {@link org.springframework.web.client.RestTemplate RestTemplate}, as to modify the outgoing {@link ClientHttpRequest}
27-
* and/or the incoming {@link ClientHttpResponse}.
24+
* Intercepts client-side HTTP requests. Implementations of this interface can be
25+
* {@linkplain org.springframework.web.client.RestTemplate#setInterceptors registered}
26+
* with the {@link org.springframework.web.client.RestTemplate RestTemplate},
27+
* as to modify the outgoing {@link ClientHttpRequest} and/or the incoming
28+
* {@link ClientHttpResponse}.
2829
*
29-
* <p>The main entry point for interceptors is {@link #intercept(HttpRequest, byte[], ClientHttpRequestExecution)}.
30+
* <p>The main entry point for interceptors is
31+
* {@link #intercept(HttpRequest, byte[], ClientHttpRequestExecution)}.
3032
*
3133
* @author Arjen Poutsma
3234
* @since 3.1
3335
*/
3436
public interface ClientHttpRequestInterceptor {
3537

3638
/**
37-
* Intercept the given request, and return a response. The given {@link ClientHttpRequestExecution} allows
38-
* the interceptor to pass on the request and response to the next entity in the chain.
39-
*
39+
* Intercept the given request, and return a response. The given
40+
* {@link ClientHttpRequestExecution} allows the interceptor to pass on the
41+
* request and response to the next entity in the chain.
4042
* <p>A typical implementation of this method would follow the following pattern:
4143
* <ol>
4244
* <li>Examine the {@linkplain HttpRequest request} and body</li>
43-
* <li>Optionally {@linkplain org.springframework.http.client.support.HttpRequestWrapper wrap} the request to filter HTTP attributes.</li>
45+
* <li>Optionally {@linkplain org.springframework.http.client.support.HttpRequestWrapper
46+
* wrap} the request to filter HTTP attributes.</li>
4447
* <li>Optionally modify the body of the request.</li>
4548
* <li><strong>Either</strong>
4649
* <ul>
47-
* <li>execute the request using {@link ClientHttpRequestExecution#execute(org.springframework.http.HttpRequest, byte[])},</li>
50+
* <li>execute the request using
51+
* {@link ClientHttpRequestExecution#execute(org.springframework.http.HttpRequest, byte[])},</li>
4852
* <strong>or</strong>
4953
* <li>do not execute the request to block the execution altogether.</li>
5054
* </ul>
5155
* <li>Optionally wrap the response to filter HTTP attributes.</li>
5256
* </ol>
53-
*
5457
* @param request the request, containing method, URI, and headers
5558
* @param body the body of the request
5659
* @param execution the request execution

spring-web/src/main/java/org/springframework/http/client/HttpComponentsClientHttpRequestFactory.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -195,6 +195,7 @@ private void setLegacySocketTimeout(HttpClient client, int timeout) {
195195
* Indicates whether this request factory should buffer the request body internally.
196196
* <p>Default is {@code true}. When sending large amounts of data via POST or PUT, it is
197197
* recommended to change this property to {@code false}, so as not to run out of memory.
198+
* @since 4.0
198199
*/
199200
public void setBufferRequestBody(boolean bufferRequestBody) {
200201
this.bufferRequestBody = bufferRequestBody;

spring-web/src/main/java/org/springframework/http/client/InterceptingClientHttpRequest.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
1717
package org.springframework.http.client;
1818

1919
import java.io.IOException;
20+
import java.io.OutputStream;
2021
import java.net.URI;
2122
import java.util.Iterator;
2223
import java.util.List;
@@ -25,6 +26,7 @@
2526
import org.springframework.http.HttpHeaders;
2627
import org.springframework.http.HttpMethod;
2728
import org.springframework.http.HttpRequest;
29+
import org.springframework.http.StreamingHttpOutputMessage;
2830
import org.springframework.util.StreamUtils;
2931

3032
/**
@@ -80,7 +82,7 @@ public InterceptingRequestExecution() {
8082
}
8183

8284
@Override
83-
public ClientHttpResponse execute(HttpRequest request, byte[] body) throws IOException {
85+
public ClientHttpResponse execute(HttpRequest request, final byte[] body) throws IOException {
8486
if (this.iterator.hasNext()) {
8587
ClientHttpRequestInterceptor nextInterceptor = this.iterator.next();
8688
return nextInterceptor.intercept(request, body, this);
@@ -94,7 +96,18 @@ public ClientHttpResponse execute(HttpRequest request, byte[] body) throws IOExc
9496
}
9597
}
9698
if (body.length > 0) {
97-
StreamUtils.copy(body, delegate.getBody());
99+
if (delegate instanceof StreamingHttpOutputMessage) {
100+
StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage) delegate;
101+
streamingOutputMessage.setBody(new StreamingHttpOutputMessage.Body() {
102+
@Override
103+
public void writeTo(final OutputStream outputStream) throws IOException {
104+
StreamUtils.copy(body, outputStream);
105+
}
106+
});
107+
}
108+
else {
109+
StreamUtils.copy(body, delegate.getBody());
110+
}
98111
}
99112
return delegate.execute();
100113
}

spring-web/src/main/java/org/springframework/http/converter/AbstractHttpMessageConverter.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -205,8 +205,7 @@ public final void write(final T t, MediaType contentType, HttpOutputMessage outp
205205
addDefaultHeaders(headers, t, contentType);
206206

207207
if (outputMessage instanceof StreamingHttpOutputMessage) {
208-
StreamingHttpOutputMessage streamingOutputMessage =
209-
(StreamingHttpOutputMessage) outputMessage;
208+
StreamingHttpOutputMessage streamingOutputMessage = (StreamingHttpOutputMessage) outputMessage;
210209
streamingOutputMessage.setBody(new StreamingHttpOutputMessage.Body() {
211210
@Override
212211
public void writeTo(final OutputStream outputStream) throws IOException {

spring-web/src/main/java/org/springframework/http/converter/BufferedImageHttpMessageConverter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.

spring-web/src/test/java/org/springframework/http/client/AbstractHttpRequestFactoryTestCase.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -69,6 +69,7 @@ public void status() throws Exception {
6969
ClientHttpRequest request = factory.createRequest(uri, HttpMethod.GET);
7070
assertEquals("Invalid HTTP method", HttpMethod.GET, request.getMethod());
7171
assertEquals("Invalid HTTP URI", uri, request.getURI());
72+
7273
ClientHttpResponse response = request.execute();
7374
try {
7475
assertEquals("Invalid status code", HttpStatus.NOT_FOUND, response.getStatusCode());
@@ -82,13 +83,15 @@ public void status() throws Exception {
8283
public void echo() throws Exception {
8384
ClientHttpRequest request = factory.createRequest(new URI(baseUrl + "/echo"), HttpMethod.PUT);
8485
assertEquals("Invalid HTTP method", HttpMethod.PUT, request.getMethod());
86+
8587
String headerName = "MyHeader";
8688
String headerValue1 = "value1";
8789
request.getHeaders().add(headerName, headerValue1);
8890
String headerValue2 = "value2";
8991
request.getHeaders().add(headerName, headerValue2);
9092
final byte[] body = "Hello World".getBytes("UTF-8");
9193
request.getHeaders().setContentLength(body.length);
94+
9295
if (request instanceof StreamingHttpOutputMessage) {
9396
StreamingHttpOutputMessage streamingRequest =
9497
(StreamingHttpOutputMessage) request;
@@ -102,6 +105,7 @@ public void writeTo(OutputStream outputStream) throws IOException {
102105
else {
103106
StreamUtils.copy(body, request.getBody());
104107
}
108+
105109
ClientHttpResponse response = request.execute();
106110
try {
107111
assertEquals("Invalid status code", HttpStatus.OK, response.getStatusCode());
@@ -121,8 +125,7 @@ public void multipleWrites() throws Exception {
121125
ClientHttpRequest request = factory.createRequest(new URI(baseUrl + "/echo"), HttpMethod.POST);
122126
final byte[] body = "Hello World".getBytes("UTF-8");
123127
if (request instanceof StreamingHttpOutputMessage) {
124-
StreamingHttpOutputMessage streamingRequest =
125-
(StreamingHttpOutputMessage) request;
128+
StreamingHttpOutputMessage streamingRequest = (StreamingHttpOutputMessage) request;
126129
streamingRequest.setBody(new StreamingHttpOutputMessage.Body() {
127130
@Override
128131
public void writeTo(OutputStream outputStream) throws IOException {
@@ -136,16 +139,18 @@ public void writeTo(OutputStream outputStream) throws IOException {
136139
StreamUtils.copy(body, request.getBody());
137140
}
138141

139-
ClientHttpResponse response = request.execute();
142+
request.execute();
140143
FileCopyUtils.copy(body, request.getBody());
141144
}
142145

143146
@Test(expected = UnsupportedOperationException.class)
144147
public void headersAfterExecute() throws Exception {
145148
ClientHttpRequest request = factory.createRequest(new URI(baseUrl + "/echo"), HttpMethod.POST);
149+
146150
request.getHeaders().add("MyHeader", "value");
147151
byte[] body = "Hello World".getBytes("UTF-8");
148152
FileCopyUtils.copy(body, request.getBody());
153+
149154
ClientHttpResponse response = request.execute();
150155
try {
151156
request.getHeaders().add("MyHeader", "value");
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright 2002-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.http.client;
18+
19+
import org.junit.Test;
20+
21+
import org.springframework.http.HttpMethod;
22+
23+
/**
24+
* @author Juergen Hoeller
25+
*/
26+
public class InterceptingStreamingHttpComponentsTests extends AbstractHttpRequestFactoryTestCase {
27+
28+
@Override
29+
protected ClientHttpRequestFactory createRequestFactory() {
30+
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
31+
requestFactory.setBufferRequestBody(false);
32+
return new InterceptingClientHttpRequestFactory(requestFactory, null);
33+
}
34+
35+
@Override
36+
@Test
37+
public void httpMethods() throws Exception {
38+
assertHttpMethod("patch", HttpMethod.PATCH);
39+
}
40+
41+
}

spring-web/src/test/java/org/springframework/http/client/StreamingHttpComponentsClientHttpRequestFactoryTests.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -20,13 +20,14 @@
2020

2121
import org.springframework.http.HttpMethod;
2222

23-
public class StreamingHttpComponentsClientHttpRequestFactoryTests
24-
extends AbstractHttpRequestFactoryTestCase {
23+
/**
24+
* @author Arjen Poutsma
25+
*/
26+
public class StreamingHttpComponentsClientHttpRequestFactoryTests extends AbstractHttpRequestFactoryTestCase {
2527

2628
@Override
2729
protected ClientHttpRequestFactory createRequestFactory() {
28-
HttpComponentsClientHttpRequestFactory requestFactory =
29-
new HttpComponentsClientHttpRequestFactory();
30+
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
3031
requestFactory.setBufferRequestBody(false);
3132
return requestFactory;
3233
}

0 commit comments

Comments
 (0)