SPR-7909 - Sending large payloads with RestTemplate results in an OutOfMemoryError
This commit is contained in:
parent
33674933ea
commit
d0d6a07870
|
|
@ -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;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2010 the original author or authors.
|
* Copyright 2002-2011 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.http.client;
|
package org.springframework.http.client;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
|
@ -29,27 +28,32 @@ import org.springframework.util.Assert;
|
||||||
* @author Arjen Poutsma
|
* @author Arjen Poutsma
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractClientHttpRequest implements ClientHttpRequest {
|
abstract class AbstractClientHttpRequest implements ClientHttpRequest {
|
||||||
|
|
||||||
private boolean executed = false;
|
private boolean executed = false;
|
||||||
|
|
||||||
private final HttpHeaders headers = new HttpHeaders();
|
private final HttpHeaders headers = new HttpHeaders();
|
||||||
|
|
||||||
private final ByteArrayOutputStream bufferedOutput = new ByteArrayOutputStream();
|
|
||||||
|
|
||||||
|
|
||||||
public final HttpHeaders getHeaders() {
|
public final HttpHeaders getHeaders() {
|
||||||
return executed ? HttpHeaders.readOnlyHttpHeaders(headers) : this.headers;
|
return executed ? HttpHeaders.readOnlyHttpHeaders(headers) : this.headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final OutputStream getBody() throws IOException {
|
public final OutputStream getBody() throws IOException {
|
||||||
checkExecuted();
|
checkExecuted();
|
||||||
return this.bufferedOutput;
|
return getBodyInternal(this.headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract template method that returns the body.
|
||||||
|
*
|
||||||
|
* @param headers the HTTP headers
|
||||||
|
* @return the body output stream
|
||||||
|
*/
|
||||||
|
protected abstract OutputStream getBodyInternal(HttpHeaders headers) throws IOException;
|
||||||
|
|
||||||
public final ClientHttpResponse execute() throws IOException {
|
public final ClientHttpResponse execute() throws IOException {
|
||||||
checkExecuted();
|
checkExecuted();
|
||||||
ClientHttpResponse result = executeInternal(this.headers, this.bufferedOutput.toByteArray());
|
ClientHttpResponse result = executeInternal(this.headers);
|
||||||
this.executed = true;
|
this.executed = true;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -58,14 +62,13 @@ public abstract class AbstractClientHttpRequest implements ClientHttpRequest {
|
||||||
Assert.state(!this.executed, "ClientHttpRequest already executed");
|
Assert.state(!this.executed, "ClientHttpRequest already executed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract template method that writes the given headers and content to the HTTP request.
|
* Abstract template method that writes the given headers and content to the HTTP request.
|
||||||
|
*
|
||||||
* @param headers the HTTP headers
|
* @param headers the HTTP headers
|
||||||
* @param bufferedOutput the body content
|
|
||||||
* @return the response object for the executed request
|
* @return the response object for the executed request
|
||||||
*/
|
*/
|
||||||
protected abstract ClientHttpResponse executeInternal(HttpHeaders headers, byte[] bufferedOutput)
|
protected abstract ClientHttpResponse executeInternal(HttpHeaders headers) throws IOException;
|
||||||
throws IOException;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2010 the original author or authors.
|
* Copyright 2002-2011 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -28,19 +28,18 @@ import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.util.FileCopyUtils;
|
import org.springframework.util.FileCopyUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link ClientHttpRequest} implementation that uses standard J2SE facilities to execute requests.
|
* {@link ClientHttpRequest} implementation that uses standard J2SE facilities to execute buffered requests.
|
||||||
* Created via the {@link SimpleClientHttpRequestFactory}.
|
* Created via the {@link SimpleClientHttpRequestFactory}.
|
||||||
*
|
*
|
||||||
* @author Arjen Poutsma
|
* @author Arjen Poutsma
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
* @see SimpleClientHttpRequestFactory#createRequest(java.net.URI, HttpMethod)
|
* @see SimpleClientHttpRequestFactory#createRequest(java.net.URI, HttpMethod)
|
||||||
*/
|
*/
|
||||||
final class SimpleClientHttpRequest extends AbstractClientHttpRequest {
|
final class BufferingSimpleClientHttpRequest extends AbstractBufferingClientHttpRequest {
|
||||||
|
|
||||||
private final HttpURLConnection connection;
|
private final HttpURLConnection connection;
|
||||||
|
|
||||||
|
BufferingSimpleClientHttpRequest(HttpURLConnection connection) {
|
||||||
SimpleClientHttpRequest(HttpURLConnection connection) {
|
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2010 the original author or authors.
|
* Copyright 2002-2011 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -41,7 +41,7 @@ import org.springframework.http.HttpMethod;
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
* @see CommonsClientHttpRequestFactory#createRequest(java.net.URI, HttpMethod)
|
* @see CommonsClientHttpRequestFactory#createRequest(java.net.URI, HttpMethod)
|
||||||
*/
|
*/
|
||||||
final class CommonsClientHttpRequest extends AbstractClientHttpRequest {
|
final class CommonsClientHttpRequest extends AbstractBufferingClientHttpRequest {
|
||||||
|
|
||||||
private final HttpClient httpClient;
|
private final HttpClient httpClient;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2010 the original author or authors.
|
* Copyright 2002-2011 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -36,8 +36,14 @@ import org.springframework.util.Assert;
|
||||||
*/
|
*/
|
||||||
public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory {
|
public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory {
|
||||||
|
|
||||||
|
private static final int DEFAULT_CHUNK_SIZE = 4096;
|
||||||
|
|
||||||
private Proxy proxy;
|
private Proxy proxy;
|
||||||
|
|
||||||
|
private boolean bufferRequestBody = true;
|
||||||
|
|
||||||
|
private int chunkSize = DEFAULT_CHUNK_SIZE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the {@link Proxy} to use for this request factory.
|
* Sets the {@link Proxy} to use for this request factory.
|
||||||
*/
|
*/
|
||||||
|
|
@ -45,16 +51,48 @@ public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory
|
||||||
this.proxy = proxy;
|
this.proxy = proxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
|
/**
|
||||||
HttpURLConnection connection = openConnection(uri.toURL(), proxy);
|
* Indicates whether this request factory should buffer the {@linkplain ClientHttpRequest#getBody() request body}
|
||||||
prepareConnection(connection, httpMethod.name());
|
* internally.
|
||||||
return new SimpleClientHttpRequest(connection);
|
* <p>Default is {@code true}. When sending large amounts of data via POST or PUT, it is recommended to change this
|
||||||
|
* property to {@code false}, so as not to run out of memory. This will result in a {@link ClientHttpRequest}
|
||||||
|
* that either streams directly to the underlying {@link HttpURLConnection} (if the
|
||||||
|
* {@link org.springframework.http.HttpHeaders#getContentLength() Content-Length} is known in advance), or that will
|
||||||
|
* use "Chunked transfer encoding" (if the {@code Content-Length} is not known in advance).
|
||||||
|
*
|
||||||
|
* @see #setChunkSize(int)
|
||||||
|
* @see HttpURLConnection#setFixedLengthStreamingMode(int)
|
||||||
|
*/
|
||||||
|
public void setBufferRequestBody(boolean bufferRequestBody) {
|
||||||
|
this.bufferRequestBody = bufferRequestBody;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens and returns a connection to the given URL.
|
* Sets the number of bytes to write in each chunk when not buffering request bodies locally.
|
||||||
* <p>The default implementation uses the given {@linkplain #setProxy(java.net.Proxy) proxy} - if any - to open a
|
* <p>Note that this parameter is only used when {@link #setBufferRequestBody(boolean) bufferRequestBody} is set
|
||||||
* connection.
|
* to {@code false}, and the {@link org.springframework.http.HttpHeaders#getContentLength() Content-Length}
|
||||||
|
* is not known in advance.
|
||||||
|
*
|
||||||
|
* @see #setBufferRequestBody(boolean)
|
||||||
|
*/
|
||||||
|
public void setChunkSize(int chunkSize) {
|
||||||
|
this.chunkSize = chunkSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) throws IOException {
|
||||||
|
HttpURLConnection connection = openConnection(uri.toURL(), proxy);
|
||||||
|
prepareConnection(connection, httpMethod.name());
|
||||||
|
if (bufferRequestBody) {
|
||||||
|
return new BufferingSimpleClientHttpRequest(connection);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return new StreamingSimpleClientHttpRequest(connection, chunkSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens and returns a connection to the given URL. <p>The default implementation uses the given {@linkplain
|
||||||
|
* #setProxy(java.net.Proxy) proxy} - if any - to open a connection.
|
||||||
*
|
*
|
||||||
* @param url the URL to open a connection to
|
* @param url the URL to open a connection to
|
||||||
* @param proxy the proxy to use, may be {@code null}
|
* @param proxy the proxy to use, may be {@code null}
|
||||||
|
|
@ -68,8 +106,8 @@ public class SimpleClientHttpRequestFactory implements ClientHttpRequestFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Template method for preparing the given {@link HttpURLConnection}.
|
* Template method for preparing the given {@link HttpURLConnection}. <p>The default implementation prepares the
|
||||||
* <p>The default implementation prepares the connection for input and output, and sets the HTTP method.
|
* connection for input and output, and sets the HTTP method.
|
||||||
*
|
*
|
||||||
* @param connection the connection to prepare
|
* @param connection the connection to prepare
|
||||||
* @param httpMethod the HTTP request method ({@code GET}, {@code POST}, etc.)
|
* @param httpMethod the HTTP request method ({@code GET}, {@code POST}, etc.)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2010 the original author or authors.
|
* Copyright 2002-2011 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -26,7 +26,8 @@ import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link ClientHttpResponse} implementation that uses standard J2SE facilities.
|
* {@link ClientHttpResponse} implementation that uses standard J2SE facilities.
|
||||||
* Obtained via the {@link SimpleClientHttpRequest#execute()}.
|
* Obtained via {@link BufferingSimpleClientHttpRequest#execute()} and
|
||||||
|
* {@link StreamingSimpleClientHttpRequest#execute()}.
|
||||||
*
|
*
|
||||||
* @author Arjen Poutsma
|
* @author Arjen Poutsma
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2010 the original author or authors.
|
* Copyright 2002-2011 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -19,7 +19,6 @@ package org.springframework.http.converter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.OutputStreamWriter;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
|
|
@ -94,19 +93,25 @@ public class FormHttpMessageConverter implements HttpMessageConverter<MultiValue
|
||||||
this.partConverters.add(new ResourceHttpMessageConverter());
|
this.partConverters.add(new ResourceHttpMessageConverter());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Add a message body converter. Such a converters is used to convert objects to MIME parts. */
|
/**
|
||||||
|
* Add a message body converter. Such a converters is used to convert objects to MIME parts.
|
||||||
|
*/
|
||||||
public final void addPartConverter(HttpMessageConverter<?> partConverter) {
|
public final void addPartConverter(HttpMessageConverter<?> partConverter) {
|
||||||
Assert.notNull(partConverter, "'partConverter' must not be NULL");
|
Assert.notNull(partConverter, "'partConverter' must not be NULL");
|
||||||
this.partConverters.add(partConverter);
|
this.partConverters.add(partConverter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Set the message body converters to use. These converters are used to convert objects to MIME parts. */
|
/**
|
||||||
|
* Set the message body converters to use. These converters are used to convert objects to MIME parts.
|
||||||
|
*/
|
||||||
public final void setPartConverters(List<HttpMessageConverter<?>> partConverters) {
|
public final void setPartConverters(List<HttpMessageConverter<?>> partConverters) {
|
||||||
Assert.notEmpty(partConverters, "'partConverters' must not be empty");
|
Assert.notEmpty(partConverters, "'partConverters' must not be empty");
|
||||||
this.partConverters = partConverters;
|
this.partConverters = partConverters;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Sets the character set used for writing form data. */
|
/**
|
||||||
|
* Sets the character set used for writing form data.
|
||||||
|
*/
|
||||||
public void setCharset(Charset charset) {
|
public void setCharset(Charset charset) {
|
||||||
this.charset = charset;
|
this.charset = charset;
|
||||||
}
|
}
|
||||||
|
|
@ -196,7 +201,8 @@ public class FormHttpMessageConverter implements HttpMessageConverter<MultiValue
|
||||||
if (contentType != null) {
|
if (contentType != null) {
|
||||||
outputMessage.getHeaders().setContentType(contentType);
|
outputMessage.getHeaders().setContentType(contentType);
|
||||||
charset = contentType.getCharSet() != null ? contentType.getCharSet() : this.charset;
|
charset = contentType.getCharSet() != null ? contentType.getCharSet() : this.charset;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
outputMessage.getHeaders().setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
outputMessage.getHeaders().setContentType(MediaType.APPLICATION_FORM_URLENCODED);
|
||||||
charset = this.charset;
|
charset = this.charset;
|
||||||
}
|
}
|
||||||
|
|
@ -218,7 +224,9 @@ public class FormHttpMessageConverter implements HttpMessageConverter<MultiValue
|
||||||
builder.append('&');
|
builder.append('&');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FileCopyUtils.copy(builder.toString(), new OutputStreamWriter(outputMessage.getBody(), charset));
|
byte[] bytes = builder.toString().getBytes(charset.name());
|
||||||
|
outputMessage.getHeaders().setContentLength(bytes.length);
|
||||||
|
FileCopyUtils.copy(bytes, outputMessage.getBody());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeMultipart(MultiValueMap<String, Object> parts, HttpOutputMessage outputMessage)
|
private void writeMultipart(MultiValueMap<String, Object> parts, HttpOutputMessage outputMessage)
|
||||||
|
|
@ -328,7 +336,9 @@ public class FormHttpMessageConverter implements HttpMessageConverter<MultiValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Implementation of {@link org.springframework.http.HttpOutputMessage} used for writing multipart data. */
|
/**
|
||||||
|
* Implementation of {@link org.springframework.http.HttpOutputMessage} used for writing multipart data.
|
||||||
|
*/
|
||||||
private class MultipartHttpOutputMessage implements HttpOutputMessage {
|
private class MultipartHttpOutputMessage implements HttpOutputMessage {
|
||||||
|
|
||||||
private final HttpHeaders headers = new HttpHeaders();
|
private final HttpHeaders headers = new HttpHeaders();
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2010 the original author or authors.
|
* Copyright 2002-2011 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
package org.springframework.http.client;
|
package org.springframework.http.client;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
|
|
@ -45,12 +46,12 @@ import static org.junit.Assert.*;
|
||||||
|
|
||||||
public abstract class AbstractHttpRequestFactoryTestCase {
|
public abstract class AbstractHttpRequestFactoryTestCase {
|
||||||
|
|
||||||
private ClientHttpRequestFactory factory;
|
protected ClientHttpRequestFactory factory;
|
||||||
|
|
||||||
|
protected static String baseUrl;
|
||||||
|
|
||||||
private static Server jettyServer;
|
private static Server jettyServer;
|
||||||
|
|
||||||
private static String baseUrl;
|
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void startJettyServer() throws Exception {
|
public static void startJettyServer() throws Exception {
|
||||||
int port = FreePortScanner.getFreePort();
|
int port = FreePortScanner.getFreePort();
|
||||||
|
|
@ -64,7 +65,7 @@ public abstract class AbstractHttpRequestFactoryTestCase {
|
||||||
jettyContext.addServlet(new ServletHolder(new MethodServlet("GET")), "/methods/get");
|
jettyContext.addServlet(new ServletHolder(new MethodServlet("GET")), "/methods/get");
|
||||||
jettyContext.addServlet(new ServletHolder(new MethodServlet("HEAD")), "/methods/head");
|
jettyContext.addServlet(new ServletHolder(new MethodServlet("HEAD")), "/methods/head");
|
||||||
jettyContext.addServlet(new ServletHolder(new MethodServlet("OPTIONS")), "/methods/options");
|
jettyContext.addServlet(new ServletHolder(new MethodServlet("OPTIONS")), "/methods/options");
|
||||||
jettyContext.addServlet(new ServletHolder(new MethodServlet("POST")), "/methods/post");
|
jettyContext.addServlet(new ServletHolder(new PostServlet()), "/methods/post");
|
||||||
jettyContext.addServlet(new ServletHolder(new MethodServlet("PUT")), "/methods/put");
|
jettyContext.addServlet(new ServletHolder(new MethodServlet("PUT")), "/methods/put");
|
||||||
jettyContext.addServlet(new ServletHolder(new RedirectServlet("/status/ok")), "/redirect");
|
jettyContext.addServlet(new ServletHolder(new RedirectServlet("/status/ok")), "/redirect");
|
||||||
jettyServer.start();
|
jettyServer.start();
|
||||||
|
|
@ -87,8 +88,7 @@ public abstract class AbstractHttpRequestFactoryTestCase {
|
||||||
@Test
|
@Test
|
||||||
public void status() throws Exception {
|
public void status() throws Exception {
|
||||||
URI uri = new URI(baseUrl + "/status/notfound");
|
URI uri = new URI(baseUrl + "/status/notfound");
|
||||||
ClientHttpRequest request =
|
ClientHttpRequest request = factory.createRequest(uri, HttpMethod.GET);
|
||||||
factory.createRequest(uri, HttpMethod.GET);
|
|
||||||
assertEquals("Invalid HTTP method", HttpMethod.GET, request.getMethod());
|
assertEquals("Invalid HTTP method", HttpMethod.GET, request.getMethod());
|
||||||
assertEquals("Invalid HTTP URI", uri, request.getURI());
|
assertEquals("Invalid HTTP URI", uri, request.getURI());
|
||||||
ClientHttpResponse response = request.execute();
|
ClientHttpResponse response = request.execute();
|
||||||
|
|
@ -105,6 +105,7 @@ public abstract class AbstractHttpRequestFactoryTestCase {
|
||||||
String headerValue2 = "value2";
|
String headerValue2 = "value2";
|
||||||
request.getHeaders().add(headerName, headerValue2);
|
request.getHeaders().add(headerName, headerValue2);
|
||||||
byte[] body = "Hello World".getBytes("UTF-8");
|
byte[] body = "Hello World".getBytes("UTF-8");
|
||||||
|
request.getHeaders().setContentLength(body.length);
|
||||||
FileCopyUtils.copy(body, request.getBody());
|
FileCopyUtils.copy(body, request.getBody());
|
||||||
ClientHttpResponse response = request.execute();
|
ClientHttpResponse response = request.execute();
|
||||||
assertEquals("Invalid status code", HttpStatus.OK, response.getStatusCode());
|
assertEquals("Invalid status code", HttpStatus.OK, response.getStatusCode());
|
||||||
|
|
@ -159,6 +160,7 @@ public abstract class AbstractHttpRequestFactoryTestCase {
|
||||||
try {
|
try {
|
||||||
ClientHttpRequest request = factory.createRequest(new URI(baseUrl + "/methods/" + path), method);
|
ClientHttpRequest request = factory.createRequest(new URI(baseUrl + "/methods/" + path), method);
|
||||||
response = request.execute();
|
response = request.execute();
|
||||||
|
assertEquals("Invalid response status", HttpStatus.OK, response.getStatusCode());
|
||||||
assertEquals("Invalid method", path.toUpperCase(Locale.ENGLISH), request.getMethod().name());
|
assertEquals("Invalid method", path.toUpperCase(Locale.ENGLISH), request.getMethod().name());
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
|
@ -167,16 +169,18 @@ public abstract class AbstractHttpRequestFactoryTestCase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void redirect() throws Exception {
|
public void redirect() throws Exception {
|
||||||
ClientHttpResponse response = null;
|
ClientHttpResponse response = null;
|
||||||
try {
|
try {
|
||||||
ClientHttpRequest request = factory.createRequest(new URI(baseUrl + "/redirect"), HttpMethod.PUT);
|
ClientHttpRequest request = factory.createRequest(new URI(baseUrl + "/redirect"), HttpMethod.PUT);
|
||||||
response = request.execute();
|
response = request.execute();
|
||||||
assertEquals("Invalid Location value", new URI(baseUrl + "/status/ok"), response.getHeaders().getLocation());
|
assertEquals("Invalid Location value", new URI(baseUrl + "/status/ok"),
|
||||||
|
response.getHeaders().getLocation());
|
||||||
|
|
||||||
} finally {
|
}
|
||||||
|
finally {
|
||||||
if (response != null) {
|
if (response != null) {
|
||||||
response.close();
|
response.close();
|
||||||
response = null;
|
response = null;
|
||||||
|
|
@ -187,13 +191,14 @@ public abstract class AbstractHttpRequestFactoryTestCase {
|
||||||
response = request.execute();
|
response = request.execute();
|
||||||
assertNull("Invalid Location value", response.getHeaders().getLocation());
|
assertNull("Invalid Location value", response.getHeaders().getLocation());
|
||||||
|
|
||||||
} finally {
|
}
|
||||||
|
finally {
|
||||||
if (response != null) {
|
if (response != null) {
|
||||||
response.close();
|
response.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Servlet that sets a given status code. */
|
/** Servlet that sets a given status code. */
|
||||||
private static class StatusServlet extends GenericServlet {
|
private static class StatusServlet extends GenericServlet {
|
||||||
|
|
||||||
|
|
@ -221,6 +226,31 @@ public abstract class AbstractHttpRequestFactoryTestCase {
|
||||||
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
|
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
|
||||||
HttpServletRequest httpReq = (HttpServletRequest) req;
|
HttpServletRequest httpReq = (HttpServletRequest) req;
|
||||||
assertEquals("Invalid HTTP method", method, httpReq.getMethod());
|
assertEquals("Invalid HTTP method", method, httpReq.getMethod());
|
||||||
|
res.setContentLength(0);
|
||||||
|
((HttpServletResponse) res).setStatus(200);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class PostServlet extends MethodServlet {
|
||||||
|
|
||||||
|
private PostServlet() {
|
||||||
|
super("POST");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
|
||||||
|
super.service(req, res);
|
||||||
|
long contentLength = req.getContentLength();
|
||||||
|
if (contentLength != -1) {
|
||||||
|
InputStream in = req.getInputStream();
|
||||||
|
long byteCount = 0;
|
||||||
|
byte[] buffer = new byte[4096];
|
||||||
|
int bytesRead;
|
||||||
|
while ((bytesRead = in.read(buffer)) != -1) {
|
||||||
|
byteCount += bytesRead;
|
||||||
|
}
|
||||||
|
assertEquals("Invalid content-length", contentLength, byteCount);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2009 the original author or authors.
|
* Copyright 2002-2011 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
package org.springframework.http.client;
|
package org.springframework.http.client;
|
||||||
|
|
||||||
public class SimpleHttpRequestFactoryTests extends AbstractHttpRequestFactoryTestCase {
|
public class BufferedSimpleHttpRequestFactoryTests extends AbstractHttpRequestFactoryTestCase {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ClientHttpRequestFactory createRequestFactory() {
|
protected ClientHttpRequestFactory createRequestFactory() {
|
||||||
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2010 the original author or authors.
|
* Copyright 2002-2011 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -30,7 +30,6 @@ import org.apache.commons.fileupload.FileItemFactory;
|
||||||
import org.apache.commons.fileupload.FileUpload;
|
import org.apache.commons.fileupload.FileUpload;
|
||||||
import org.apache.commons.fileupload.RequestContext;
|
import org.apache.commons.fileupload.RequestContext;
|
||||||
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
|
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
|
||||||
import static org.junit.Assert.*;
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
|
@ -45,9 +44,9 @@ import org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter;
|
||||||
import org.springframework.util.LinkedMultiValueMap;
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
import org.springframework.util.MultiValueMap;
|
import org.springframework.util.MultiValueMap;
|
||||||
|
|
||||||
/**
|
import static org.junit.Assert.*;
|
||||||
* @author Arjen Poutsma
|
|
||||||
*/
|
/** @author Arjen Poutsma */
|
||||||
public class FormHttpMessageConverterTests {
|
public class FormHttpMessageConverterTests {
|
||||||
|
|
||||||
private FormHttpMessageConverter converter;
|
private FormHttpMessageConverter converter;
|
||||||
|
|
@ -60,13 +59,13 @@ public class FormHttpMessageConverterTests {
|
||||||
@Test
|
@Test
|
||||||
public void canRead() {
|
public void canRead() {
|
||||||
assertTrue(converter.canRead(MultiValueMap.class, new MediaType("application", "x-www-form-urlencoded")));
|
assertTrue(converter.canRead(MultiValueMap.class, new MediaType("application", "x-www-form-urlencoded")));
|
||||||
assertFalse(converter.canRead(MultiValueMap.class, new MediaType("multipart","form-data")));
|
assertFalse(converter.canRead(MultiValueMap.class, new MediaType("multipart", "form-data")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void canWrite() {
|
public void canWrite() {
|
||||||
assertTrue(converter.canWrite(MultiValueMap.class, new MediaType("application", "x-www-form-urlencoded")));
|
assertTrue(converter.canWrite(MultiValueMap.class, new MediaType("application", "x-www-form-urlencoded")));
|
||||||
assertTrue(converter.canWrite(MultiValueMap.class, new MediaType("multipart","form-data")));
|
assertTrue(converter.canWrite(MultiValueMap.class, new MediaType("multipart", "form-data")));
|
||||||
assertTrue(converter.canWrite(MultiValueMap.class, MediaType.ALL));
|
assertTrue(converter.canWrite(MultiValueMap.class, MediaType.ALL));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -77,7 +76,7 @@ public class FormHttpMessageConverterTests {
|
||||||
Charset iso88591 = Charset.forName("ISO-8859-1");
|
Charset iso88591 = Charset.forName("ISO-8859-1");
|
||||||
MockHttpInputMessage inputMessage = new MockHttpInputMessage(body.getBytes(iso88591));
|
MockHttpInputMessage inputMessage = new MockHttpInputMessage(body.getBytes(iso88591));
|
||||||
inputMessage.getHeaders().setContentType(new MediaType("application", "x-www-form-urlencoded", iso88591));
|
inputMessage.getHeaders().setContentType(new MediaType("application", "x-www-form-urlencoded", iso88591));
|
||||||
MultiValueMap<String, String> result = (MultiValueMap<String, String>) converter.read(null, inputMessage);
|
MultiValueMap<String, String> result = converter.read(null, inputMessage);
|
||||||
|
|
||||||
assertEquals("Invalid result", 3, result.size());
|
assertEquals("Invalid result", 3, result.size());
|
||||||
assertEquals("Invalid result", "value 1", result.getFirst("name 1"));
|
assertEquals("Invalid result", "value 1", result.getFirst("name 1"));
|
||||||
|
|
@ -97,19 +96,21 @@ public class FormHttpMessageConverterTests {
|
||||||
body.add("name 3", null);
|
body.add("name 3", null);
|
||||||
MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
|
MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
|
||||||
converter.write(body, MediaType.APPLICATION_FORM_URLENCODED, outputMessage);
|
converter.write(body, MediaType.APPLICATION_FORM_URLENCODED, outputMessage);
|
||||||
Charset iso88591 = Charset.forName("ISO-8859-1");
|
|
||||||
assertEquals("Invalid result", "name+1=value+1&name+2=value+2%2B1&name+2=value+2%2B2&name+3",
|
assertEquals("Invalid result", "name+1=value+1&name+2=value+2%2B1&name+2=value+2%2B2&name+3",
|
||||||
outputMessage.getBodyAsString(iso88591));
|
outputMessage.getBodyAsString(Charset.forName("UTF-8")));
|
||||||
assertEquals("Invalid content-type", new MediaType("application", "x-www-form-urlencoded"),
|
assertEquals("Invalid content-type", new MediaType("application", "x-www-form-urlencoded"),
|
||||||
outputMessage.getHeaders().getContentType());
|
outputMessage.getHeaders().getContentType());
|
||||||
|
assertEquals("Invalid content-length", outputMessage.getBodyAsBytes().length,
|
||||||
|
outputMessage.getHeaders().getContentLength());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void writeMultipart() throws Exception {
|
public void writeMultipart() throws Exception {
|
||||||
MultiValueMap<String, Object> parts = new LinkedMultiValueMap<String, Object>();
|
MultiValueMap<String, Object> parts = new LinkedMultiValueMap<String, Object>();
|
||||||
parts.add("name 1", "value 1");
|
parts.add("name 1", "value 1");
|
||||||
parts.add("name 2", "value 2+1");
|
parts.add("name 2", "value 2+1");
|
||||||
parts.add("name 2", "value 2+2");
|
parts.add("name 2", "value 2+2");
|
||||||
|
|
||||||
Resource logo = new ClassPathResource("/org/springframework/http/converter/logo.jpg");
|
Resource logo = new ClassPathResource("/org/springframework/http/converter/logo.jpg");
|
||||||
parts.add("logo", logo);
|
parts.add("logo", logo);
|
||||||
Source xml = new StreamSource(new StringReader("<root><child/></root>"));
|
Source xml = new StreamSource(new StringReader("<root><child/></root>"));
|
||||||
|
|
@ -122,7 +123,7 @@ public class FormHttpMessageConverterTests {
|
||||||
converter.write(parts, MediaType.MULTIPART_FORM_DATA, outputMessage);
|
converter.write(parts, MediaType.MULTIPART_FORM_DATA, outputMessage);
|
||||||
|
|
||||||
final MediaType contentType = outputMessage.getHeaders().getContentType();
|
final MediaType contentType = outputMessage.getHeaders().getContentType();
|
||||||
assertNotNull(contentType.getParameter("boundary"));
|
assertNotNull("No boundary found", contentType.getParameter("boundary"));
|
||||||
|
|
||||||
// see if Commons FileUpload can read what we wrote
|
// see if Commons FileUpload can read what we wrote
|
||||||
FileItemFactory fileItemFactory = new DiskFileItemFactory();
|
FileItemFactory fileItemFactory = new DiskFileItemFactory();
|
||||||
|
|
@ -157,6 +158,7 @@ public class FormHttpMessageConverterTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class MockHttpOutputMessageRequestContext implements RequestContext {
|
private static class MockHttpOutputMessageRequestContext implements RequestContext {
|
||||||
|
|
||||||
private final MockHttpOutputMessage outputMessage;
|
private final MockHttpOutputMessage outputMessage;
|
||||||
|
|
||||||
private MockHttpOutputMessageRequestContext(MockHttpOutputMessage outputMessage) {
|
private MockHttpOutputMessageRequestContext(MockHttpOutputMessage outputMessage) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue