Browse Source
git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@3918 50f2f4bb-b051-0410-bef5-90022cba6387pull/1/head
12 changed files with 385 additions and 62 deletions
@ -0,0 +1,61 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2011 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 |
||||||
|
* |
||||||
|
* http://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.ByteArrayOutputStream; |
||||||
|
import java.io.IOException; |
||||||
|
import java.io.OutputStream; |
||||||
|
|
||||||
|
import org.springframework.http.HttpHeaders; |
||||||
|
|
||||||
|
/** |
||||||
|
* Abstract base for {@link ClientHttpRequest} that buffers output in a byte array before sending it over the wire. |
||||||
|
* |
||||||
|
* @author Arjen Poutsma |
||||||
|
* @since 3.0.6 |
||||||
|
*/ |
||||||
|
abstract class AbstractBufferingClientHttpRequest extends AbstractClientHttpRequest { |
||||||
|
|
||||||
|
private ByteArrayOutputStream bufferedOutput = new ByteArrayOutputStream(); |
||||||
|
|
||||||
|
@Override |
||||||
|
protected OutputStream getBodyInternal(HttpHeaders headers) throws IOException { |
||||||
|
return this.bufferedOutput; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected ClientHttpResponse executeInternal(HttpHeaders headers) throws IOException { |
||||||
|
byte[] bytes = this.bufferedOutput.toByteArray(); |
||||||
|
if (headers.getContentLength() == -1) { |
||||||
|
headers.setContentLength(bytes.length); |
||||||
|
} |
||||||
|
ClientHttpResponse result = executeInternal(headers, bytes); |
||||||
|
this.bufferedOutput = null; |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Abstract template method that writes the given headers and content to the HTTP request. |
||||||
|
* @param headers the HTTP headers |
||||||
|
* @param bufferedOutput the body content |
||||||
|
* @return the response object for the executed request |
||||||
|
*/ |
||||||
|
protected abstract ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput) |
||||||
|
throws IOException; |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,112 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2011 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 |
||||||
|
* |
||||||
|
* http://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.FilterOutputStream; |
||||||
|
import java.io.IOException; |
||||||
|
import java.io.OutputStream; |
||||||
|
import java.net.HttpURLConnection; |
||||||
|
import java.net.URI; |
||||||
|
import java.net.URISyntaxException; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import org.springframework.http.HttpHeaders; |
||||||
|
import org.springframework.http.HttpMethod; |
||||||
|
|
||||||
|
/** |
||||||
|
* {@link ClientHttpRequest} implementation that uses standard J2SE facilities to execute streaming requests. |
||||||
|
* Created via the {@link SimpleClientHttpRequestFactory}. |
||||||
|
* |
||||||
|
* @author Arjen Poutsma |
||||||
|
* @since 3.0 |
||||||
|
* @see SimpleClientHttpRequestFactory#createRequest(java.net.URI, HttpMethod) |
||||||
|
*/ |
||||||
|
public class StreamingSimpleClientHttpRequest extends AbstractClientHttpRequest { |
||||||
|
|
||||||
|
private final HttpURLConnection connection; |
||||||
|
|
||||||
|
private final int chunkSize; |
||||||
|
|
||||||
|
private OutputStream body; |
||||||
|
|
||||||
|
StreamingSimpleClientHttpRequest(HttpURLConnection connection, int chunkSize) { |
||||||
|
this.connection = connection; |
||||||
|
this.chunkSize = chunkSize; |
||||||
|
} |
||||||
|
|
||||||
|
public HttpMethod getMethod() { |
||||||
|
return HttpMethod.valueOf(this.connection.getRequestMethod()); |
||||||
|
} |
||||||
|
|
||||||
|
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 (body == null) { |
||||||
|
int contentLength = (int) headers.getContentLength(); |
||||||
|
if (contentLength >= 0) { |
||||||
|
this.connection.setFixedLengthStreamingMode(contentLength); |
||||||
|
} |
||||||
|
else { |
||||||
|
this.connection.setChunkedStreamingMode(chunkSize); |
||||||
|
} |
||||||
|
for (Map.Entry<String, List<String>> entry : headers.entrySet()) { |
||||||
|
String headerName = entry.getKey(); |
||||||
|
for (String headerValue : entry.getValue()) { |
||||||
|
this.connection.addRequestProperty(headerName, headerValue); |
||||||
|
} |
||||||
|
} |
||||||
|
this.connection.connect(); |
||||||
|
this.body = this.connection.getOutputStream(); |
||||||
|
} |
||||||
|
return new NonClosingOutputStream(body); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected ClientHttpResponse executeInternal(HttpHeaders headers) throws IOException { |
||||||
|
try { |
||||||
|
if (body != null) { |
||||||
|
body.close(); |
||||||
|
} |
||||||
|
} |
||||||
|
catch (IOException ex) { |
||||||
|
// ignore
|
||||||
|
} |
||||||
|
return new SimpleClientHttpResponse(this.connection); |
||||||
|
} |
||||||
|
|
||||||
|
private static class NonClosingOutputStream extends FilterOutputStream { |
||||||
|
|
||||||
|
private NonClosingOutputStream(OutputStream out) { |
||||||
|
super(out); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void close() throws IOException { |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,67 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2011 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 |
||||||
|
* |
||||||
|
* http://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.Random; |
||||||
|
|
||||||
|
import org.junit.Ignore; |
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
import org.springframework.http.HttpMethod; |
||||||
|
import org.springframework.http.HttpStatus; |
||||||
|
|
||||||
|
import static org.junit.Assert.*; |
||||||
|
|
||||||
|
public class StreamingSimpleHttpRequestFactoryTests extends AbstractHttpRequestFactoryTestCase { |
||||||
|
|
||||||
|
@Override |
||||||
|
protected ClientHttpRequestFactory createRequestFactory() { |
||||||
|
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); |
||||||
|
factory.setStreaming(true); |
||||||
|
return factory; |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
@Ignore |
||||||
|
public void largeFileUpload() throws Exception { |
||||||
|
Random rnd = new Random(); |
||||||
|
ClientHttpResponse response = null; |
||||||
|
try { |
||||||
|
ClientHttpRequest request = factory.createRequest(new URI(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(); |
||||||
|
assertEquals("Invalid response status", HttpStatus.OK, response.getStatusCode()); |
||||||
|
} |
||||||
|
finally { |
||||||
|
if (response != null) { |
||||||
|
response.close(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
Loading…
Reference in new issue