Browse Source
This commit ensures that ClientHttpRequest implementations implement StreamingHttpOutputMessage, so that they do not expose an OutputStream, but store a handle capable of writing to a stream instead. Closes gh-30557pull/30570/head
21 changed files with 421 additions and 711 deletions
@ -0,0 +1,83 @@
@@ -0,0 +1,83 @@
|
||||
/* |
||||
* 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. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.http.client; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.OutputStream; |
||||
|
||||
import org.springframework.http.HttpHeaders; |
||||
import org.springframework.http.StreamingHttpOutputMessage; |
||||
import org.springframework.lang.Nullable; |
||||
import org.springframework.util.Assert; |
||||
import org.springframework.util.FastByteArrayOutputStream; |
||||
|
||||
/** |
||||
* Abstract base for {@link ClientHttpRequest} that also implement |
||||
* {@link StreamingHttpOutputMessage}. Ensures that headers and |
||||
* body are not written multiple times. |
||||
* |
||||
* @author Arjen Poutsma |
||||
* @since 6.1 |
||||
*/ |
||||
abstract class AbstractStreamingClientHttpRequest extends AbstractClientHttpRequest |
||||
implements StreamingHttpOutputMessage { |
||||
|
||||
@Nullable |
||||
private Body body; |
||||
|
||||
@Nullable |
||||
private FastByteArrayOutputStream bodyStream; |
||||
|
||||
|
||||
@Override |
||||
protected final OutputStream getBodyInternal(HttpHeaders headers) { |
||||
Assert.state(this.body == null, "Invoke either getBody or setBody; not both"); |
||||
|
||||
if (this.bodyStream == null) { |
||||
this.bodyStream = new FastByteArrayOutputStream(1024); |
||||
} |
||||
return this.bodyStream; |
||||
} |
||||
|
||||
@Override |
||||
public final void setBody(Body body) { |
||||
Assert.notNull(body, "Body must not be null"); |
||||
assertNotExecuted(); |
||||
Assert.state(this.bodyStream == null, "Invoke either getBody or setBody; not both"); |
||||
|
||||
this.body = body; |
||||
} |
||||
|
||||
@Override |
||||
protected final ClientHttpResponse executeInternal(HttpHeaders headers) throws IOException { |
||||
if (this.body == null && this.bodyStream != null) { |
||||
this.body = outputStream -> this.bodyStream.writeTo(outputStream); |
||||
} |
||||
return executeInternal(headers, this.body); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Abstract template method that writes the given headers and content to the HTTP request. |
||||
* @param headers the HTTP headers |
||||
* @param body the HTTP body, may be {@code null} if no body was {@linkplain #setBody(Body) set} |
||||
* @return the response object for the executed request |
||||
* @since 6.1 |
||||
*/ |
||||
protected abstract ClientHttpResponse executeInternal(HttpHeaders headers, @Nullable Body body) throws IOException; |
||||
|
||||
} |
||||
@ -1,183 +0,0 @@
@@ -1,183 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2022 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. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.http.client; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.io.OutputStream; |
||||
import java.net.URI; |
||||
import java.net.URISyntaxException; |
||||
import java.util.List; |
||||
import java.util.Set; |
||||
|
||||
import org.apache.hc.client5.http.classic.HttpClient; |
||||
import org.apache.hc.core5.function.Supplier; |
||||
import org.apache.hc.core5.http.ClassicHttpRequest; |
||||
import org.apache.hc.core5.http.ClassicHttpResponse; |
||||
import org.apache.hc.core5.http.Header; |
||||
import org.apache.hc.core5.http.HttpEntity; |
||||
import org.apache.hc.core5.http.HttpResponse; |
||||
import org.apache.hc.core5.http.protocol.HttpContext; |
||||
|
||||
import org.springframework.http.HttpHeaders; |
||||
import org.springframework.http.HttpMethod; |
||||
import org.springframework.http.StreamingHttpOutputMessage; |
||||
import org.springframework.lang.Nullable; |
||||
import org.springframework.util.Assert; |
||||
|
||||
/** |
||||
* {@link ClientHttpRequest} implementation based on |
||||
* Apache HttpComponents HttpClient in streaming mode. |
||||
* |
||||
* <p>Created via the {@link HttpComponentsClientHttpRequestFactory}. |
||||
* |
||||
* @author Arjen Poutsma |
||||
* @since 4.0 |
||||
* @see HttpComponentsClientHttpRequestFactory#createRequest(java.net.URI, org.springframework.http.HttpMethod) |
||||
*/ |
||||
final class HttpComponentsStreamingClientHttpRequest extends AbstractClientHttpRequest |
||||
implements StreamingHttpOutputMessage { |
||||
|
||||
private final HttpClient httpClient; |
||||
|
||||
private final ClassicHttpRequest httpRequest; |
||||
|
||||
private final HttpContext httpContext; |
||||
|
||||
@Nullable |
||||
private Body body; |
||||
|
||||
|
||||
HttpComponentsStreamingClientHttpRequest(HttpClient client, ClassicHttpRequest request, HttpContext context) { |
||||
this.httpClient = client; |
||||
this.httpRequest = request; |
||||
this.httpContext = context; |
||||
} |
||||
|
||||
@Override |
||||
public HttpMethod getMethod() { |
||||
return HttpMethod.valueOf(this.httpRequest.getMethod()); |
||||
} |
||||
|
||||
@Override |
||||
public URI getURI() { |
||||
try { |
||||
return this.httpRequest.getUri(); |
||||
} |
||||
catch (URISyntaxException ex) { |
||||
throw new IllegalStateException(ex.getMessage(), ex); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void setBody(Body body) { |
||||
assertNotExecuted(); |
||||
this.body = body; |
||||
} |
||||
|
||||
@Override |
||||
protected OutputStream getBodyInternal(HttpHeaders headers) { |
||||
throw new UnsupportedOperationException("getBody not supported"); |
||||
} |
||||
|
||||
@SuppressWarnings("deprecation") // execute(ClassicHttpRequest, HttpContext)
|
||||
@Override |
||||
protected ClientHttpResponse executeInternal(HttpHeaders headers) throws IOException { |
||||
HttpComponentsClientHttpRequest.addHeaders(this.httpRequest, headers); |
||||
|
||||
if (this.body != null) { |
||||
HttpEntity requestEntity = new StreamingHttpEntity(getHeaders(), this.body); |
||||
this.httpRequest.setEntity(requestEntity); |
||||
} |
||||
HttpResponse httpResponse = this.httpClient.execute(this.httpRequest, this.httpContext); |
||||
Assert.isInstanceOf(ClassicHttpResponse.class, httpResponse, |
||||
"HttpResponse not an instance of ClassicHttpResponse"); |
||||
return new HttpComponentsClientHttpResponse((ClassicHttpResponse) httpResponse); |
||||
} |
||||
|
||||
|
||||
private static class StreamingHttpEntity implements HttpEntity { |
||||
|
||||
private final HttpHeaders headers; |
||||
|
||||
private final StreamingHttpOutputMessage.Body body; |
||||
|
||||
public StreamingHttpEntity(HttpHeaders headers, StreamingHttpOutputMessage.Body body) { |
||||
this.headers = headers; |
||||
this.body = body; |
||||
} |
||||
|
||||
@Override |
||||
public boolean isRepeatable() { |
||||
return false; |
||||
} |
||||
|
||||
@Override |
||||
public boolean isChunked() { |
||||
return false; |
||||
} |
||||
|
||||
@Override |
||||
public long getContentLength() { |
||||
return this.headers.getContentLength(); |
||||
} |
||||
|
||||
@Override |
||||
@Nullable |
||||
public String getContentType() { |
||||
return this.headers.getFirst(HttpHeaders.CONTENT_TYPE); |
||||
} |
||||
|
||||
@Override |
||||
@Nullable |
||||
public String getContentEncoding() { |
||||
return this.headers.getFirst(HttpHeaders.CONTENT_ENCODING); |
||||
} |
||||
|
||||
@Override |
||||
public InputStream getContent() throws IOException, IllegalStateException { |
||||
throw new IllegalStateException("No content available"); |
||||
} |
||||
|
||||
@Override |
||||
public void writeTo(OutputStream outputStream) throws IOException { |
||||
this.body.writeTo(outputStream); |
||||
} |
||||
|
||||
@Override |
||||
public boolean isStreaming() { |
||||
return true; |
||||
} |
||||
|
||||
@Override |
||||
@Nullable |
||||
public Supplier<List<? extends Header>> getTrailers() { |
||||
return null; |
||||
} |
||||
|
||||
@Override |
||||
@Nullable |
||||
public Set<String> getTrailerNames() { |
||||
return null; |
||||
} |
||||
|
||||
@Override |
||||
public void close() throws IOException { |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -1,111 +0,0 @@
@@ -1,111 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2022 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. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.http.client; |
||||
|
||||
import java.io.IOException; |
||||
import java.io.OutputStream; |
||||
import java.net.HttpURLConnection; |
||||
import java.net.URI; |
||||
import java.net.URISyntaxException; |
||||
|
||||
import org.springframework.http.HttpHeaders; |
||||
import org.springframework.http.HttpMethod; |
||||
import org.springframework.lang.Nullable; |
||||
import org.springframework.util.StreamUtils; |
||||
|
||||
/** |
||||
* {@link ClientHttpRequest} implementation that uses standard JDK facilities to |
||||
* execute streaming requests. Created via the {@link SimpleClientHttpRequestFactory}. |
||||
* |
||||
* @author Arjen Poutsma |
||||
* @since 3.0 |
||||
* @see SimpleClientHttpRequestFactory#createRequest(java.net.URI, HttpMethod) |
||||
* @see org.springframework.http.client.support.HttpAccessor |
||||
* @see org.springframework.web.client.RestTemplate |
||||
*/ |
||||
final class SimpleStreamingClientHttpRequest extends AbstractClientHttpRequest { |
||||
|
||||
private final HttpURLConnection connection; |
||||
|
||||
private final int chunkSize; |
||||
|
||||
@Nullable |
||||
private OutputStream body; |
||||
|
||||
private final boolean outputStreaming; |
||||
|
||||
|
||||
SimpleStreamingClientHttpRequest(HttpURLConnection connection, int chunkSize, boolean outputStreaming) { |
||||
this.connection = connection; |
||||
this.chunkSize = chunkSize; |
||||
this.outputStreaming = outputStreaming; |
||||
} |
||||
|
||||
@Override |
||||
public HttpMethod getMethod() { |
||||
return HttpMethod.valueOf(this.connection.getRequestMethod()); |
||||
} |
||||
|
||||
@Override |
||||
public URI getURI() { |
||||
try { |
||||
return this.connection.getURL().toURI(); |
||||
} |
||||
catch (URISyntaxException ex) { |
||||
throw new IllegalStateException("Could not get HttpURLConnection URI: " + ex.getMessage(), ex); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
protected OutputStream getBodyInternal(HttpHeaders headers) throws IOException { |
||||
if (this.body == null) { |
||||
if (this.outputStreaming) { |
||||
long contentLength = headers.getContentLength(); |
||||
if (contentLength >= 0) { |
||||
this.connection.setFixedLengthStreamingMode(contentLength); |
||||
} |
||||
else { |
||||
this.connection.setChunkedStreamingMode(this.chunkSize); |
||||
} |
||||
} |
||||
SimpleBufferingClientHttpRequest.addHeaders(this.connection, headers); |
||||
this.connection.connect(); |
||||
this.body = this.connection.getOutputStream(); |
||||
} |
||||
return StreamUtils.nonClosing(this.body); |
||||
} |
||||
|
||||
@Override |
||||
protected ClientHttpResponse executeInternal(HttpHeaders headers) throws IOException { |
||||
try { |
||||
if (this.body != null) { |
||||
this.body.close(); |
||||
} |
||||
else { |
||||
SimpleBufferingClientHttpRequest.addHeaders(this.connection, headers); |
||||
this.connection.connect(); |
||||
// Immediately trigger the request in a no-output scenario as well
|
||||
this.connection.getResponseCode(); |
||||
} |
||||
} |
||||
catch (IOException ex) { |
||||
// ignore
|
||||
} |
||||
return new SimpleClientHttpResponse(this.connection); |
||||
} |
||||
|
||||
} |
||||
@ -1,102 +0,0 @@
@@ -1,102 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2019 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. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.http.client; |
||||
|
||||
import java.io.ByteArrayInputStream; |
||||
import java.io.IOException; |
||||
import java.io.InputStream; |
||||
import java.net.HttpURLConnection; |
||||
import java.net.ProtocolException; |
||||
import java.net.URL; |
||||
|
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.http.HttpMethod; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
public class BufferedSimpleHttpRequestFactoryTests extends AbstractHttpRequestFactoryTests { |
||||
|
||||
@Override |
||||
protected ClientHttpRequestFactory createRequestFactory() { |
||||
return new SimpleClientHttpRequestFactory(); |
||||
} |
||||
|
||||
@Override |
||||
@Test |
||||
public void httpMethods() throws Exception { |
||||
try { |
||||
assertHttpMethod("patch", HttpMethod.PATCH); |
||||
} |
||||
catch (ProtocolException ex) { |
||||
// Currently HttpURLConnection does not support HTTP PATCH
|
||||
} |
||||
} |
||||
|
||||
@Test |
||||
public void prepareConnectionWithRequestBody() throws Exception { |
||||
URL uri = new URL("https://example.com"); |
||||
testRequestBodyAllowed(uri, "GET", false); |
||||
testRequestBodyAllowed(uri, "HEAD", false); |
||||
testRequestBodyAllowed(uri, "OPTIONS", false); |
||||
testRequestBodyAllowed(uri, "TRACE", false); |
||||
testRequestBodyAllowed(uri, "PUT", true); |
||||
testRequestBodyAllowed(uri, "POST", true); |
||||
testRequestBodyAllowed(uri, "DELETE", true); |
||||
} |
||||
|
||||
@Test |
||||
public void deleteWithoutBodyDoesNotRaiseException() throws Exception { |
||||
HttpURLConnection connection = new TestHttpURLConnection(new URL("https://example.com")); |
||||
((SimpleClientHttpRequestFactory) this.factory).prepareConnection(connection, "DELETE"); |
||||
SimpleBufferingClientHttpRequest request = new SimpleBufferingClientHttpRequest(connection, false); |
||||
request.execute(); |
||||
} |
||||
|
||||
private void testRequestBodyAllowed(URL uri, String httpMethod, boolean allowed) throws IOException { |
||||
HttpURLConnection connection = new TestHttpURLConnection(uri); |
||||
((SimpleClientHttpRequestFactory) this.factory).prepareConnection(connection, httpMethod); |
||||
assertThat(connection.getDoOutput()).isEqualTo(allowed); |
||||
} |
||||
|
||||
|
||||
private static class TestHttpURLConnection extends HttpURLConnection { |
||||
|
||||
public TestHttpURLConnection(URL uri) { |
||||
super(uri); |
||||
} |
||||
|
||||
@Override |
||||
public void connect() throws IOException { |
||||
} |
||||
|
||||
@Override |
||||
public void disconnect() { |
||||
} |
||||
|
||||
@Override |
||||
public boolean usingProxy() { |
||||
return false; |
||||
} |
||||
|
||||
@Override |
||||
public InputStream getInputStream() throws IOException { |
||||
return new ByteArrayInputStream(new byte[0]); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -1,29 +0,0 @@
@@ -1,29 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2013 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. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.http.client; |
||||
|
||||
|
||||
public class NoOutputStreamingBufferedSimpleHttpRequestFactoryTests extends AbstractHttpRequestFactoryTests { |
||||
|
||||
@Override |
||||
protected ClientHttpRequestFactory createRequestFactory() { |
||||
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); |
||||
factory.setOutputStreaming(false); |
||||
return factory; |
||||
} |
||||
|
||||
} |
||||
@ -1,29 +0,0 @@
@@ -1,29 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2013 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. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.http.client; |
||||
|
||||
|
||||
public class NoOutputStreamingStreamingSimpleHttpRequestFactoryTests extends AbstractHttpRequestFactoryTests { |
||||
|
||||
@Override |
||||
protected ClientHttpRequestFactory createRequestFactory() { |
||||
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); |
||||
factory.setBufferRequestBody(false); |
||||
factory.setOutputStreaming(false); |
||||
return factory; |
||||
} |
||||
} |
||||
@ -1,41 +0,0 @@
@@ -1,41 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2018 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. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.http.client; |
||||
|
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.http.HttpMethod; |
||||
|
||||
/** |
||||
* @author Arjen Poutsma |
||||
*/ |
||||
public class StreamingHttpComponentsClientHttpRequestFactoryTests extends AbstractHttpRequestFactoryTests { |
||||
|
||||
@Override |
||||
protected ClientHttpRequestFactory createRequestFactory() { |
||||
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); |
||||
requestFactory.setBufferRequestBody(false); |
||||
return requestFactory; |
||||
} |
||||
|
||||
@Override |
||||
@Test |
||||
public void httpMethods() throws Exception { |
||||
assertHttpMethod("patch", HttpMethod.PATCH); |
||||
} |
||||
|
||||
} |
||||
@ -1,98 +0,0 @@
@@ -1,98 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2022 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. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.springframework.http.client; |
||||
|
||||
import java.io.OutputStream; |
||||
import java.net.URI; |
||||
import java.util.Collections; |
||||
import java.util.Random; |
||||
|
||||
import org.junit.jupiter.api.Disabled; |
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.http.HttpHeaders; |
||||
import org.springframework.http.HttpMethod; |
||||
import org.springframework.http.HttpStatus; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
/** |
||||
* @author Arjen Poutsma |
||||
*/ |
||||
public class StreamingSimpleClientHttpRequestFactoryTests extends AbstractHttpRequestFactoryTests { |
||||
|
||||
@Override |
||||
protected ClientHttpRequestFactory createRequestFactory() { |
||||
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); |
||||
factory.setBufferRequestBody(false); |
||||
return factory; |
||||
} |
||||
|
||||
@Test // SPR-8809
|
||||
public void interceptor() throws Exception { |
||||
final String headerName = "MyHeader"; |
||||
final String headerValue = "MyValue"; |
||||
ClientHttpRequestInterceptor interceptor = (request, body, execution) -> { |
||||
request.getHeaders().add(headerName, headerValue); |
||||
return execution.execute(request, body); |
||||
}; |
||||
InterceptingClientHttpRequestFactory factory = new InterceptingClientHttpRequestFactory( |
||||
createRequestFactory(), Collections.singletonList(interceptor)); |
||||
|
||||
ClientHttpResponse response = null; |
||||
try { |
||||
ClientHttpRequest request = factory.createRequest(URI.create(baseUrl + "/echo"), HttpMethod.GET); |
||||
response = request.execute(); |
||||
assertThat(response.getStatusCode()).as("Invalid response status").isEqualTo(HttpStatus.OK); |
||||
HttpHeaders responseHeaders = response.getHeaders(); |
||||
assertThat(responseHeaders.getFirst(headerName)).as("Custom header invalid").isEqualTo(headerValue); |
||||
} |
||||
finally { |
||||
if (response != null) { |
||||
response.close(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
@Disabled |
||||
public void largeFileUpload() throws Exception { |
||||
Random rnd = new Random(); |
||||
ClientHttpResponse response = null; |
||||
try { |
||||
ClientHttpRequest request = factory.createRequest(URI.create(baseUrl + "/methods/post"), HttpMethod.POST); |
||||
final int BUF_SIZE = 4096; |
||||
final int ITERATIONS = Integer.MAX_VALUE / BUF_SIZE; |
||||
// final int contentLength = ITERATIONS * BUF_SIZE;
|
||||
// request.getHeaders().setContentLength(contentLength);
|
||||
OutputStream body = request.getBody(); |
||||
for (int i = 0; i < ITERATIONS; i++) { |
||||
byte[] buffer = new byte[BUF_SIZE]; |
||||
rnd.nextBytes(buffer); |
||||
body.write(buffer); |
||||
} |
||||
response = request.execute(); |
||||
assertThat(response.getStatusCode()).as("Invalid response status").isEqualTo(HttpStatus.OK); |
||||
} |
||||
finally { |
||||
if (response != null) { |
||||
response.close(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue