diff --git a/google-http-client/src/main/java/com/google/api/client/http/MultipartContent.java b/google-http-client/src/main/java/com/google/api/client/http/MultipartContent.java
index 4fdc0b586..43a58b446 100644
--- a/google-http-client/src/main/java/com/google/api/client/http/MultipartContent.java
+++ b/google-http-client/src/main/java/com/google/api/client/http/MultipartContent.java
@@ -24,6 +24,7 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.UUID;
/**
* Serializes MIME multipart content as specified by RFC 2046: Multipurpose Internet
* Mail Extensions: The Multipart/mixed (primary) subtype.
*
- *
By default the media type is {@code "multipart/related; boundary=__END_OF_PART__"}, but this
+ *
By default the media type is {@code "multipart/related; boundary=__END_OF_PART____"}, but this
* may be customized by calling {@link #setMediaType(HttpMediaType)}, {@link #getMediaType()}, or
* {@link #setBoundary(String)}.
*
@@ -47,10 +48,14 @@ public class MultipartContent extends AbstractHttpContent {
private static final String TWO_DASHES = "--";
/** Parts of the HTTP multipart request. */
- private ArrayList parts = new ArrayList();
+ private ArrayList parts = new ArrayList<>();
public MultipartContent() {
- super(new HttpMediaType("multipart/related").setParameter("boundary", "__END_OF_PART__"));
+ this("__END_OF_PART__" + UUID.randomUUID().toString() + "__");
+ }
+
+ public MultipartContent(String boundary) {
+ super(new HttpMediaType("multipart/related").setParameter("boundary", boundary));
}
public void writeTo(OutputStream out) throws IOException {
@@ -152,7 +157,7 @@ public MultipartContent addPart(Part part) {
* changing the return type, but nothing else.
*/
public MultipartContent setParts(Collection parts) {
- this.parts = new ArrayList(parts);
+ this.parts = new ArrayList<>(parts);
return this;
}
@@ -164,7 +169,7 @@ public MultipartContent setParts(Collection parts) {
* changing the return type, but nothing else.
*/
public MultipartContent setContentParts(Collection extends HttpContent> contentParts) {
- this.parts = new ArrayList(contentParts.size());
+ this.parts = new ArrayList<>(contentParts.size());
for (HttpContent contentPart : contentParts) {
addPart(new Part(contentPart));
}
diff --git a/google-http-client/src/test/java/com/google/api/client/http/MultipartContentTest.java b/google-http-client/src/test/java/com/google/api/client/http/MultipartContentTest.java
index 76f725b61..14e0e5990 100644
--- a/google-http-client/src/test/java/com/google/api/client/http/MultipartContentTest.java
+++ b/google-http-client/src/test/java/com/google/api/client/http/MultipartContentTest.java
@@ -15,6 +15,7 @@
package com.google.api.client.http;
import com.google.api.client.json.Json;
+import com.google.api.client.util.Charsets;
import com.google.api.client.util.StringUtils;
import java.io.ByteArrayOutputStream;
import junit.framework.TestCase;
@@ -26,55 +27,76 @@
*/
public class MultipartContentTest extends TestCase {
+ private static final String BOUNDARY = "__END_OF_PART__";
private static final String CRLF = "\r\n";
private static final String CONTENT_TYPE = Json.MEDIA_TYPE;
- private static final String HEADERS =
- "Content-Length: 3"
- + CRLF
- + "Content-Type: application/json; charset=UTF-8"
- + CRLF
- + "content-transfer-encoding: binary"
- + CRLF;
+ private static final String HEADERS = headers("application/json; charset=UTF-8", "foo");
+
+ private static String headers(String contentType, String value) {
+ return "Content-Length: " + value.length() + CRLF
+ + "Content-Type: " + contentType + CRLF
+ + "content-transfer-encoding: binary" + CRLF;
+ }
+
+ public void testRandomContent() throws Exception {
+ MultipartContent content = new MultipartContent();
+ String boundaryString = content.getBoundary();
+ assertNotNull(boundaryString);
+ assertTrue(boundaryString.startsWith(BOUNDARY));
+ assertTrue(boundaryString.endsWith("__"));
+ assertEquals("multipart/related; boundary=" + boundaryString, content.getType());
+
+ final String[][] VALUES = new String[][] {
+ {"Hello world", "text/plain"},
+ {"Hi", "application/xml"},
+ {"{x:1,y:2}", "application/json"}
+ };
+ StringBuilder expectedStringBuilder = new StringBuilder();
+ for (String[] valueTypePair: VALUES) {
+ String contentValue = valueTypePair[0];
+ String contentType = valueTypePair[1];
+ content.addPart(new MultipartContent.Part(ByteArrayContent.fromString(contentType, contentValue)));
+ expectedStringBuilder.append("--").append(boundaryString).append(CRLF)
+ .append(headers(contentType, contentValue)).append(CRLF)
+ .append(contentValue).append(CRLF);
+ }
+ expectedStringBuilder.append("--").append(boundaryString).append("--").append(CRLF);
+ // write to string
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ content.writeTo(out);
+ String expectedContent = expectedStringBuilder.toString();
+ assertEquals(expectedContent, out.toString(Charsets.UTF_8.name()));
+ assertEquals(StringUtils.getBytesUtf8(expectedContent).length, content.getLength());
+ }
public void testContent() throws Exception {
- subtestContent("--__END_OF_PART__--" + CRLF, null);
+ subtestContent("--" + BOUNDARY + "--" + CRLF, null);
subtestContent(
- "--__END_OF_PART__" + CRLF + HEADERS + CRLF + "foo" + CRLF + "--__END_OF_PART__--" + CRLF,
- null,
+ "--" + BOUNDARY + CRLF
+ + HEADERS + CRLF
+ + "foo" + CRLF
+ + "--" + BOUNDARY + "--" + CRLF,
+ null,
"foo");
subtestContent(
- "--__END_OF_PART__"
- + CRLF
- + HEADERS
- + CRLF
- + "foo"
- + CRLF
- + "--__END_OF_PART__"
- + CRLF
- + HEADERS
- + CRLF
- + "bar"
- + CRLF
- + "--__END_OF_PART__--"
- + CRLF,
- null,
+ "--" + BOUNDARY + CRLF
+ + HEADERS + CRLF
+ + "foo" + CRLF
+ + "--" + BOUNDARY + CRLF
+ + HEADERS + CRLF
+ + "bar" + CRLF
+ + "--" + BOUNDARY + "--" + CRLF,
+ null,
"foo",
"bar");
subtestContent(
- "--myboundary"
- + CRLF
- + HEADERS
- + CRLF
- + "foo"
- + CRLF
- + "--myboundary"
- + CRLF
- + HEADERS
- + CRLF
- + "bar"
- + CRLF
- + "--myboundary--"
- + CRLF,
+ "--myboundary" + CRLF
+ + HEADERS + CRLF
+ + "foo" + CRLF
+ + "--myboundary" + CRLF
+ + HEADERS + CRLF
+ + "bar" + CRLF
+ + "--myboundary--" + CRLF,
"myboundary",
"foo",
"bar");
@@ -83,7 +105,7 @@ public void testContent() throws Exception {
private void subtestContent(String expectedContent, String boundaryString, String... contents)
throws Exception {
// multipart content
- MultipartContent content = new MultipartContent();
+ MultipartContent content = new MultipartContent(boundaryString == null ? BOUNDARY : boundaryString);
for (String contentValue : contents) {
content.addPart(
new MultipartContent.Part(ByteArrayContent.fromString(CONTENT_TYPE, contentValue)));
@@ -94,11 +116,11 @@ private void subtestContent(String expectedContent, String boundaryString, Strin
// write to string
ByteArrayOutputStream out = new ByteArrayOutputStream();
content.writeTo(out);
- assertEquals(expectedContent, out.toString());
+ assertEquals(expectedContent, out.toString(Charsets.UTF_8.name()));
assertEquals(StringUtils.getBytesUtf8(expectedContent).length, content.getLength());
assertEquals(
boundaryString == null
- ? "multipart/related; boundary=__END_OF_PART__"
+ ? "multipart/related; boundary=" + BOUNDARY
: "multipart/related; boundary=" + boundaryString,
content.getType());
}