Post HTTPCLIENT-1372 cleanups; all multipart entity generation logic moved to MultipartEntityBuilder

git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@1495409 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Oleg Kalnichevski 2013-06-21 12:28:58 +00:00
parent f596896b32
commit 9056303b5c
13 changed files with 321 additions and 272 deletions

View File

@ -33,7 +33,6 @@ import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import org.apache.http.entity.mime.content.ContentBody;
@ -94,11 +93,9 @@ abstract class AbstractMultipartForm {
private static final ByteArrayBuffer CR_LF = encode(MIME.DEFAULT_CHARSET, "\r\n");
private static final ByteArrayBuffer TWO_DASHES = encode(MIME.DEFAULT_CHARSET, "--");
private final String subType;
protected final Charset charset;
private final String boundary;
private final List<FormBodyPart> parts;
/**
* Creates an instance with the specified settings.
@ -115,7 +112,6 @@ abstract class AbstractMultipartForm {
this.subType = subType;
this.charset = charset != null ? charset : MIME.DEFAULT_CHARSET;
this.boundary = boundary;
this.parts = new ArrayList<FormBodyPart>();
}
public AbstractMultipartForm(final String subType, final String boundary) {
@ -130,27 +126,18 @@ abstract class AbstractMultipartForm {
return this.charset;
}
public List<FormBodyPart> getBodyParts() {
return this.parts;
}
public void addBodyPart(final FormBodyPart part) {
if (part == null) {
return;
}
this.parts.add(part);
}
public abstract List<FormBodyPart> getBodyParts();
public String getBoundary() {
return this.boundary;
}
private void doWriteTo(
void doWriteTo(
final OutputStream out,
final boolean writeContent) throws IOException {
final ByteArrayBuffer boundary = encode(this.charset, getBoundary());
for (final FormBodyPart part: this.parts) {
for (final FormBodyPart part: getBodyParts()) {
writeBytes(TWO_DASHES, out);
writeBytes(boundary, out);
writeBytes(CR_LF, out);
@ -201,7 +188,7 @@ abstract class AbstractMultipartForm {
*/
public long getTotalLength() {
long contentLen = 0;
for (final FormBodyPart part: this.parts) {
for (final FormBodyPart part: getBodyParts()) {
final ContentBody body = part.getBody();
final long len = body.getContentLength();
if (len >= 0) {

View File

@ -30,6 +30,7 @@ package org.apache.http.entity.mime;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.List;
/**
* HttpBrowserCompatibleMultipart represents a collection of MIME multipart encoded
@ -39,22 +40,20 @@ import java.nio.charset.Charset;
*/
class HttpBrowserCompatibleMultipart extends AbstractMultipartForm {
/**
* Creates an instance with the specified settings.
*
* @param subType mime subtype - must not be {@code null}
* @param charset the character set to use. May be {@code null},
* in which case {@link MIME#DEFAULT_CHARSET} - i.e. US-ASCII - is used.
* @param boundary to use - must not be {@code null}
* @throws IllegalArgumentException if charset is null or boundary is null
*/
private final List<FormBodyPart> parts;
public HttpBrowserCompatibleMultipart(
final String subType, final Charset charset, final String boundary) {
final String subType,
final Charset charset,
final String boundary,
final List<FormBodyPart> parts) {
super(subType, charset, boundary);
this.parts = parts;
}
public HttpBrowserCompatibleMultipart(final String subType, final String boundary) {
this(subType, null, boundary);
@Override
public List<FormBodyPart> getBodyParts() {
return this.parts;
}
/**

View File

@ -30,6 +30,8 @@ package org.apache.http.entity.mime;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
/**
* HttpMultipart represents a collection of MIME multipart encoded content bodies. This class is
@ -44,6 +46,7 @@ import java.nio.charset.Charset;
public class HttpMultipart extends AbstractMultipartForm {
private final HttpMultipartMode mode;
private final List<FormBodyPart> parts;
/**
* Creates an instance with the specified settings.
@ -60,6 +63,7 @@ public class HttpMultipart extends AbstractMultipartForm {
final HttpMultipartMode mode) {
super(subType, charset, boundary);
this.mode = mode;
this.parts = new ArrayList<FormBodyPart>();
}
/**
@ -107,4 +111,16 @@ public class HttpMultipart extends AbstractMultipartForm {
}
}
@Override
public List<FormBodyPart> getBodyParts() {
return this.parts;
}
public void addBodyPart(final FormBodyPart part) {
if (part == null) {
return;
}
this.parts.add(part);
}
}

View File

@ -1,59 +0,0 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.entity.mime;
import java.nio.charset.Charset;
/**
*
* @since 4.3
*/
public class HttpMultipartFactory {
/** Non-instantiable */
private HttpMultipartFactory() {
}
/** Create an appropriate AbstractMultipartForm instance */
public static AbstractMultipartForm getInstance(
final String subType, final Charset charset, final String boundary,
final HttpMultipartMode mode) {
// If needed, this can be replaced with a registry in time
switch (mode) {
case STRICT:
return new HttpStrictMultipart(subType, charset, boundary);
case BROWSER_COMPATIBLE:
return new HttpBrowserCompatibleMultipart(subType, charset, boundary);
case RFC6532:
return new HttpRFC6532Multipart(subType, charset, boundary);
default:
throw new IllegalArgumentException("Unknown multipart mode");
}
}
}

View File

@ -30,6 +30,7 @@ package org.apache.http.entity.mime;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.List;
/**
* HttpRFC6532Multipart represents a collection of MIME multipart encoded content bodies,
@ -40,26 +41,22 @@ import java.nio.charset.Charset;
*/
class HttpRFC6532Multipart extends AbstractMultipartForm {
/**
* Creates an instance with the specified settings.
*
* @param subType mime subtype - must not be {@code null}
* @param charset the character set to use. May be {@code null},
* in which case {@link MIME#DEFAULT_CHARSET} - i.e. US-ASCII - is used.
* @param boundary to use - must not be {@code null}
* @throws IllegalArgumentException if charset is null or boundary is null
*/
public HttpRFC6532Multipart(final String subType, final Charset charset, final String boundary) {
private final List<FormBodyPart> parts;
public HttpRFC6532Multipart(
final String subType,
final Charset charset,
final String boundary,
final List<FormBodyPart> parts) {
super(subType, charset, boundary);
this.parts = parts;
}
public HttpRFC6532Multipart(final String subType, final String boundary) {
this(subType, null, boundary);
@Override
public List<FormBodyPart> getBodyParts() {
return this.parts;
}
/**
* Write the multipart header fields; depends on the style.
*/
@Override
protected void formatMultipartHeader(
final FormBodyPart part,

View File

@ -30,6 +30,7 @@ package org.apache.http.entity.mime;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.List;
/**
* HttpStrictMultipart represents a collection of MIME multipart encoded content bodies,
@ -40,26 +41,22 @@ import java.nio.charset.Charset;
*/
class HttpStrictMultipart extends AbstractMultipartForm {
/**
* Creates an instance with the specified settings.
*
* @param subType mime subtype - must not be {@code null}
* @param charset the character set to use. May be {@code null},
* in which case {@link MIME#DEFAULT_CHARSET} - i.e. US-ASCII - is used.
* @param boundary to use - must not be {@code null}
* @throws IllegalArgumentException if charset is null or boundary is null
*/
public HttpStrictMultipart(final String subType, final Charset charset, final String boundary) {
private final List<FormBodyPart> parts;
public HttpStrictMultipart(
final String subType,
final Charset charset,
final String boundary,
final List<FormBodyPart> parts) {
super(subType, charset, boundary);
this.parts = parts;
}
public HttpStrictMultipart(final String subType, final String boundary) {
this(subType, null, boundary);
@Override
public List<FormBodyPart> getBodyParts() {
return this.parts;
}
/**
* Write the multipart header fields; depends on the style.
*/
@Override
protected void formatMultipartHeader(
final FormBodyPart part,

View File

@ -27,6 +27,8 @@
package org.apache.http.entity.mime;
import org.apache.http.Consts;
import java.nio.charset.Charset;
/**
@ -43,9 +45,9 @@ public final class MIME {
public static final String ENC_BINARY = "binary";
/** The default character set to be used, i.e. "US-ASCII" */
public static final Charset DEFAULT_CHARSET = Charset.forName("US-ASCII");
public static final Charset DEFAULT_CHARSET = Consts.ASCII;
/** UTF-8 is used for RFC6532 */
public static final Charset UTF8_CHARSET = Charset.forName("UTF-8");
public static final Charset UTF8_CHARSET = Consts.UTF_8;
}

View File

@ -36,14 +36,15 @@ import java.util.Random;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.entity.mime.content.ContentBody;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HTTP;
/**
* Multipart/form coded HTTP entity consisting of multiple body parts.
*
* @since 4.0
*
* @deprecated 4.3 Use {@link MultipartEntityBuilder}.
*/
@Deprecated
public class MultipartEntity implements HttpEntity {
/**
@ -53,12 +54,8 @@ public class MultipartEntity implements HttpEntity {
"-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
.toCharArray();
private final AbstractMultipartForm multipart;
private final Header contentType;
// @GuardedBy("dirty") // we always read dirty before accessing length
private long length;
private volatile boolean dirty; // used to decide whether to recalculate length
private final MultipartEntityBuilder builder;
private volatile MultipartFormEntity entity;
/**
* Creates an instance using the specified parameters
@ -71,29 +68,13 @@ public class MultipartEntity implements HttpEntity {
final String boundary,
final Charset charset) {
super();
final String b = boundary != null ? boundary : generateBoundary();
this.multipart = HttpMultipartFactory.getInstance("form-data", charset, b, mode != null ? mode : HttpMultipartMode.STRICT);
this.contentType = new BasicHeader(HTTP.CONTENT_TYPE, generateContentType(b, charset));
this.dirty = true;
this.builder = new MultipartEntityBuilder()
.setMode(mode)
.setCharset(charset)
.setBoundary(boundary);
this.entity = null;
}
/**
* Creates an instance using the specified parameters
* @param multipart the part encoder to use, may not be {@code null}
* @param boundary the boundary string, may be {@code null}, in which case {@link #generateBoundary()} is invoked to create the string
* @param charset the character set to use, may be {@code null}, in which case {@link MIME#DEFAULT_CHARSET} - i.e. US-ASCII - is used.
*/
public MultipartEntity(
final AbstractMultipartForm multipart,
final String boundary,
final Charset charset) {
super();
final String b = boundary != null ? boundary : generateBoundary();
this.multipart = multipart;
this.contentType = new BasicHeader(HTTP.CONTENT_TYPE, generateContentType(b, charset));
this.dirty = true;
}
/**
* Creates an instance using the specified {@link HttpMultipartMode} mode.
* Boundary and charset are set to {@code null}.
@ -133,16 +114,16 @@ public class MultipartEntity implements HttpEntity {
return buffer.toString();
}
/**
* @since 4.3
*/
protected AbstractMultipartForm getMultipart() {
return multipart;
private MultipartFormEntity getEntity() {
if (this.entity == null) {
this.entity = this.builder.buildEntity();
}
return this.entity;
}
public void addPart(final FormBodyPart bodyPart) {
this.multipart.addBodyPart(bodyPart);
this.dirty = true;
this.builder.addPart(bodyPart);
this.entity = null;
}
public void addPart(final String name, final ContentBody contentBody) {
@ -150,37 +131,27 @@ public class MultipartEntity implements HttpEntity {
}
public boolean isRepeatable() {
for (final FormBodyPart part: this.multipart.getBodyParts()) {
final ContentBody body = part.getBody();
if (body.getContentLength() < 0) {
return false;
}
}
return true;
return getEntity().isRepeatable();
}
public boolean isChunked() {
return !isRepeatable();
return getEntity().isChunked();
}
public boolean isStreaming() {
return !isRepeatable();
return getEntity().isStreaming();
}
public long getContentLength() {
if (this.dirty) {
this.length = this.multipart.getTotalLength();
this.dirty = false;
}
return this.length;
return getEntity().getContentLength();
}
public Header getContentType() {
return this.contentType;
return getEntity().getContentType();
}
public Header getContentEncoding() {
return null;
return getEntity().getContentEncoding();
}
public void consumeContent()
@ -197,7 +168,7 @@ public class MultipartEntity implements HttpEntity {
}
public void writeTo(final OutputStream outstream) throws IOException {
this.multipart.writeTo(outstream);
getEntity().writeTo(outstream);
}
}

View File

@ -31,20 +31,36 @@ import java.io.File;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import org.apache.http.HttpEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.content.ByteArrayBody;
import org.apache.http.entity.mime.content.ContentBody;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.InputStreamBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.util.Args;
/**
* Builder for multipart {@link HttpEntity}s.
*
* @since 4.3
*/
public class MultipartEntityBuilder {
/**
* The pool of ASCII chars to be used for generating a multipart boundary.
*/
private final static char[] MULTIPART_CHARS =
"-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
.toCharArray();
private final static String DEFAULT_SUBTYPE = "form-data";
private String subType = DEFAULT_SUBTYPE;
private HttpMultipartMode mode = HttpMultipartMode.STRICT;
private String boundary = null;
private Charset charset = null;
@ -58,6 +74,11 @@ public class MultipartEntityBuilder {
super();
}
public MultipartEntityBuilder setMode(final HttpMultipartMode mode) {
this.mode = mode;
return this;
}
public MultipartEntityBuilder setLaxMode() {
this.mode = HttpMultipartMode.BROWSER_COMPATIBLE;
return this;
@ -78,17 +99,28 @@ public class MultipartEntityBuilder {
return this;
}
public MultipartEntityBuilder addTextBody(
final String name, final String text, final ContentType contentType) {
Args.notNull(name, "Name");
Args.notNull(text, "Text");
MultipartEntityBuilder addPart(final FormBodyPart bodyPart) {
if (bodyPart == null) {
return this;
}
if (this.bodyParts == null) {
this.bodyParts = new ArrayList<FormBodyPart>();
}
this.bodyParts.add(new FormBodyPart(name, new StringBody(text, contentType)));
this.bodyParts.add(bodyPart);
return this;
}
public MultipartEntityBuilder addPart(final String name, final ContentBody contentBody) {
Args.notNull(name, "Name");
Args.notNull(contentBody, "Content body");
return addPart(new FormBodyPart(name, contentBody));
}
public MultipartEntityBuilder addTextBody(
final String name, final String text, final ContentType contentType) {
return addPart(name, new StringBody(text, contentType));
}
public MultipartEntityBuilder addTextBody(
final String name, final String text) {
return addTextBody(name, text, ContentType.DEFAULT_TEXT);
@ -96,11 +128,7 @@ public class MultipartEntityBuilder {
public MultipartEntityBuilder addBinaryBody(
final String name, final byte[] b, final ContentType contentType, final String filename) {
if (this.bodyParts == null) {
this.bodyParts = new ArrayList<FormBodyPart>();
}
this.bodyParts.add(new FormBodyPart(name, new ByteArrayBody(b, contentType, filename)));
return this;
return addPart(name, new ByteArrayBody(b, contentType, filename));
}
public MultipartEntityBuilder addBinaryBody(
@ -110,12 +138,7 @@ public class MultipartEntityBuilder {
public MultipartEntityBuilder addBinaryBody(
final String name, final File file, final ContentType contentType, final String filename) {
if (this.bodyParts == null) {
this.bodyParts = new ArrayList<FormBodyPart>();
}
this.bodyParts.add(
new FormBodyPart(name, new FileBody(file, contentType, filename)));
return this;
return addPart(name, new FileBody(file, contentType, filename));
}
public MultipartEntityBuilder addBinaryBody(
@ -126,28 +149,59 @@ public class MultipartEntityBuilder {
public MultipartEntityBuilder addBinaryBody(
final String name, final InputStream stream, final ContentType contentType,
final String filename) {
if (this.bodyParts == null) {
this.bodyParts = new ArrayList<FormBodyPart>();
}
this.bodyParts.add(
new FormBodyPart(name, new InputStreamBody(stream, contentType, filename)));
return this;
return addPart(name, new InputStreamBody(stream, contentType, filename));
}
public MultipartEntityBuilder addBinaryBody(final String name, final InputStream stream) {
return addBinaryBody(name, stream, ContentType.DEFAULT_BINARY, null);
}
public MultipartEntity build() {
final MultipartEntity e = new MultipartEntity(
this.mode,
this.boundary, this.charset);
if (this.bodyParts != null) {
for (final FormBodyPart bp: this.bodyParts) {
e.addPart(bp);
}
private String generateContentType(
final String boundary,
final Charset charset) {
final StringBuilder buffer = new StringBuilder();
buffer.append("multipart/form-data; boundary=");
buffer.append(boundary);
if (charset != null) {
buffer.append("; charset=");
buffer.append(charset.name());
}
return e;
return buffer.toString();
}
private String generateBoundary() {
final StringBuilder buffer = new StringBuilder();
final Random rand = new Random();
final int count = rand.nextInt(11) + 30; // a random size from 30 to 40
for (int i = 0; i < count; i++) {
buffer.append(MULTIPART_CHARS[rand.nextInt(MULTIPART_CHARS.length)]);
}
return buffer.toString();
}
MultipartFormEntity buildEntity() {
final String st = subType != null ? subType : DEFAULT_SUBTYPE;
final Charset cs = charset;
final String b = boundary != null ? boundary : generateBoundary();
final List<FormBodyPart> bps = bodyParts != null ? new ArrayList<FormBodyPart>(bodyParts) :
Collections.<FormBodyPart>emptyList();
final HttpMultipartMode m = mode != null ? mode : HttpMultipartMode.STRICT;
final AbstractMultipartForm form;
switch (m) {
case BROWSER_COMPATIBLE:
form = new HttpBrowserCompatibleMultipart(st, cs, b, bps);
break;
case RFC6532:
form = new HttpRFC6532Multipart(st, cs, b, bps);
break;
default:
form = new HttpStrictMultipart(st, cs, b, bps);
}
return new MultipartFormEntity(form, generateContentType(b, cs), form.getTotalLength());
}
public HttpEntity build() {
return buildEntity();
}
}

View File

@ -0,0 +1,100 @@
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.entity.mime;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HTTP;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
class MultipartFormEntity implements HttpEntity {
private final AbstractMultipartForm multipart;
private final Header contentType;
private final long contentLength;
MultipartFormEntity(
final AbstractMultipartForm multipart,
final String contentType,
final long contentLength) {
super();
this.multipart = multipart;
this.contentType = new BasicHeader(HTTP.CONTENT_TYPE, contentType);
this.contentLength = contentLength;
}
AbstractMultipartForm getMultipart() {
return this.multipart;
}
public boolean isRepeatable() {
return this.contentLength != -1;
}
public boolean isChunked() {
return !isRepeatable();
}
public boolean isStreaming() {
return !isRepeatable();
}
public long getContentLength() {
return this.contentLength;
}
public Header getContentType() {
return this.contentType;
}
public Header getContentEncoding() {
return null;
}
public void consumeContent()
throws IOException, UnsupportedOperationException{
if (isStreaming()) {
throw new UnsupportedOperationException(
"Streaming entity does not implement #consumeContent()");
}
}
public InputStream getContent() throws IOException {
throw new UnsupportedOperationException(
"Multipart form entity does not implement #getContent()");
}
public void writeTo(final OutputStream outstream) throws IOException {
this.multipart.writeTo(outstream);
}
}

View File

@ -39,33 +39,33 @@ public class TestMultipartEntityBuilder {
@Test
public void testBasics() throws Exception {
final MultipartEntity entity = MultipartEntityBuilder.create().build();
final MultipartFormEntity entity = MultipartEntityBuilder.create().buildEntity();
Assert.assertNotNull(entity);
Assert.assertEquals("org.apache.http.entity.mime.HttpStrictMultipart", entity.getMultipart().getClass().getName());
Assert.assertTrue(entity.getMultipart() instanceof HttpStrictMultipart);
Assert.assertEquals(0, entity.getMultipart().getBodyParts().size());
}
@Test
public void testMultipartOptions() throws Exception {
final MultipartEntity entity = MultipartEntityBuilder.create()
final MultipartFormEntity entity = MultipartEntityBuilder.create()
.setBoundary("blah-blah")
.setCharset(Consts.UTF_8)
.setLaxMode()
.build();
.buildEntity();
Assert.assertNotNull(entity);
Assert.assertEquals("org.apache.http.entity.mime.HttpBrowserCompatibleMultipart", entity.getMultipart().getClass().getName());
Assert.assertTrue(entity.getMultipart() instanceof HttpBrowserCompatibleMultipart);
Assert.assertEquals("blah-blah", entity.getMultipart().getBoundary());
Assert.assertEquals(Consts.UTF_8, entity.getMultipart().getCharset());
}
@Test
public void testAddBodyParts() throws Exception {
final MultipartEntity entity = MultipartEntityBuilder.create()
final MultipartFormEntity entity = MultipartEntityBuilder.create()
.addTextBody("p1", "stuff")
.addBinaryBody("p2", new File("stuff"))
.addBinaryBody("p3", new byte[] {})
.addBinaryBody("p4", new ByteArrayInputStream(new byte[] {}))
.build();
.buildEntity();
Assert.assertNotNull(entity);
final List<FormBodyPart> bodyParts = entity.getMultipart().getBodyParts();
Assert.assertNotNull(bodyParts);

View File

@ -33,20 +33,30 @@ import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.Writer;
import java.nio.charset.Charset;
import java.util.Arrays;
import org.apache.http.Consts;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.InputStreamBody;
import org.apache.http.entity.mime.content.StringBody;
import org.junit.After;
import org.junit.Assert;
import org.junit.Test;
public class TestMultipartForm {
private File tmpfile;
@After
public void cleanup() {
if (tmpfile != null) {
tmpfile.delete();
}
}
@Test
public void testMultipartFormStringParts() throws Exception {
final AbstractMultipartForm multipart = new HttpStrictMultipart("form-data", "foo");
final FormBodyPart p1 = new FormBodyPart(
"field1",
new StringBody("this stuff", ContentType.DEFAULT_TEXT));
@ -57,10 +67,8 @@ public class TestMultipartForm {
final FormBodyPart p3 = new FormBodyPart(
"field3",
new StringBody("all kind of stuff", ContentType.DEFAULT_TEXT));
multipart.addBodyPart(p1);
multipart.addBodyPart(p2);
multipart.addBodyPart(p3);
final HttpStrictMultipart multipart = new HttpStrictMultipart("form-data", null, "foo",
Arrays.asList(p1, p2, p3));
final ByteArrayOutputStream out = new ByteArrayOutputStream();
multipart.writeTo(out);
@ -93,8 +101,7 @@ public class TestMultipartForm {
@Test
public void testMultipartFormBinaryParts() throws Exception {
final File tmpfile = File.createTempFile("tmp", ".bin");
tmpfile.deleteOnExit();
tmpfile = File.createTempFile("tmp", ".bin");
final Writer writer = new FileWriter(tmpfile);
try {
writer.append("some random whatever");
@ -102,16 +109,14 @@ public class TestMultipartForm {
writer.close();
}
final AbstractMultipartForm multipart = new HttpStrictMultipart("form-data", "foo");
final FormBodyPart p1 = new FormBodyPart(
"field1",
new FileBody(tmpfile));
final FormBodyPart p2 = new FormBodyPart(
"field2",
new InputStreamBody(new FileInputStream(tmpfile), "file.tmp"));
multipart.addBodyPart(p1);
multipart.addBodyPart(p2);
final HttpStrictMultipart multipart = new HttpStrictMultipart("form-data", null, "foo",
Arrays.asList(p1, p2));
final ByteArrayOutputStream out = new ByteArrayOutputStream();
multipart.writeTo(out);
@ -136,14 +141,11 @@ public class TestMultipartForm {
final String s = out.toString("US-ASCII");
Assert.assertEquals(expected, s);
Assert.assertEquals(-1, multipart.getTotalLength());
tmpfile.delete();
}
@Test
public void testMultipartFormBrowserCompatible() throws Exception {
final File tmpfile = File.createTempFile("tmp", ".bin");
tmpfile.deleteOnExit();
public void testMultipartFormStrict() throws Exception {
tmpfile = File.createTempFile("tmp", ".bin");
final Writer writer = new FileWriter(tmpfile);
try {
writer.append("some random whatever");
@ -151,8 +153,6 @@ public class TestMultipartForm {
writer.close();
}
// Strict is no accident here, despite the test name - otherwise Transfer-Encoding is not produced.
final AbstractMultipartForm multipart = new HttpStrictMultipart("form-data", null, "foo");
final FormBodyPart p1 = new FormBodyPart(
"field1",
new FileBody(tmpfile));
@ -162,10 +162,8 @@ public class TestMultipartForm {
final FormBodyPart p3 = new FormBodyPart(
"field3",
new InputStreamBody(new FileInputStream(tmpfile), "file.tmp"));
multipart.addBodyPart(p1);
multipart.addBodyPart(p2);
multipart.addBodyPart(p3);
final HttpStrictMultipart multipart = new HttpStrictMultipart("form-data", null, "foo",
Arrays.asList(p1, p2, p3));
final ByteArrayOutputStream out = new ByteArrayOutputStream();
multipart.writeTo(out);
@ -197,14 +195,11 @@ public class TestMultipartForm {
final String s = out.toString("US-ASCII");
Assert.assertEquals(expected, s);
Assert.assertEquals(-1, multipart.getTotalLength());
tmpfile.delete();
}
@Test
public void testMultipartFormRFC6532() throws Exception {
final File tmpfile = File.createTempFile("tmp", ".bin");
tmpfile.deleteOnExit();
tmpfile = File.createTempFile("tmp", ".bin");
final Writer writer = new FileWriter(tmpfile);
try {
writer.append("some random whatever");
@ -212,8 +207,6 @@ public class TestMultipartForm {
writer.close();
}
// Strict is no accident here, despite the test name - otherwise Transfer-Encoding is not produced.
final AbstractMultipartForm multipart = new HttpRFC6532Multipart("form-data", null, "foo");
final FormBodyPart p1 = new FormBodyPart(
"field1\u0414",
new FileBody(tmpfile));
@ -223,10 +216,8 @@ public class TestMultipartForm {
final FormBodyPart p3 = new FormBodyPart(
"field3",
new InputStreamBody(new FileInputStream(tmpfile), "file.tmp"));
multipart.addBodyPart(p1);
multipart.addBodyPart(p2);
multipart.addBodyPart(p3);
final HttpRFC6532Multipart multipart = new HttpRFC6532Multipart("form-data", null, "foo",
Arrays.asList(p1, p2, p3));
final ByteArrayOutputStream out = new ByteArrayOutputStream();
multipart.writeTo(out);
@ -258,8 +249,6 @@ public class TestMultipartForm {
final String s = out.toString("UTF-8");
Assert.assertEquals(expected, s);
Assert.assertEquals(-1, multipart.getTotalLength());
tmpfile.delete();
}
private static final int SWISS_GERMAN_HELLO [] = {
@ -286,8 +275,7 @@ public class TestMultipartForm {
final String s1 = constructString(SWISS_GERMAN_HELLO);
final String s2 = constructString(RUSSIAN_HELLO);
final File tmpfile = File.createTempFile("tmp", ".bin");
tmpfile.deleteOnExit();
tmpfile = File.createTempFile("tmp", ".bin");
final Writer writer = new FileWriter(tmpfile);
try {
writer.append("some random whatever");
@ -295,16 +283,15 @@ public class TestMultipartForm {
writer.close();
}
final AbstractMultipartForm multipart = new HttpBrowserCompatibleMultipart("form-data", Charset.forName("UTF-8"), "foo");
final FormBodyPart p1 = new FormBodyPart(
"field1",
new InputStreamBody(new FileInputStream(tmpfile), s1 + ".tmp"));
final FormBodyPart p2 = new FormBodyPart(
"field2",
new InputStreamBody(new FileInputStream(tmpfile), s2 + ".tmp"));
multipart.addBodyPart(p1);
multipart.addBodyPart(p2);
final HttpBrowserCompatibleMultipart multipart = new HttpBrowserCompatibleMultipart(
"form-data", Consts.UTF_8, "foo",
Arrays.asList(p1, p2));
final ByteArrayOutputStream out = new ByteArrayOutputStream();
multipart.writeTo(out);
@ -327,8 +314,6 @@ public class TestMultipartForm {
final String s = out.toString("UTF-8");
Assert.assertEquals(expected, s);
Assert.assertEquals(-1, multipart.getTotalLength());
tmpfile.delete();
}
@Test
@ -336,16 +321,14 @@ public class TestMultipartForm {
final String s1 = constructString(SWISS_GERMAN_HELLO);
final String s2 = constructString(RUSSIAN_HELLO);
final AbstractMultipartForm multipart = new HttpStrictMultipart("form-data", "foo");
final FormBodyPart p1 = new FormBodyPart(
"field1",
new StringBody(s1, ContentType.create("text/plain", Charset.forName("ISO-8859-1"))));
final FormBodyPart p2 = new FormBodyPart(
"field2",
new StringBody(s2, ContentType.create("text/plain", Charset.forName("KOI8-R"))));
multipart.addBodyPart(p1);
multipart.addBodyPart(p2);
final HttpStrictMultipart multipart = new HttpStrictMultipart("form-data", null, "foo",
Arrays.asList(p1, p2));
final ByteArrayOutputStream out1 = new ByteArrayOutputStream();
multipart.writeTo(out1);

View File

@ -29,14 +29,13 @@ package org.apache.http.entity.mime;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.nio.charset.Charset;
import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.content.InputStreamBody;
import org.apache.http.entity.mime.content.StringBody;
import org.junit.Assert;
import org.junit.Test;
@ -44,10 +43,11 @@ public class TestMultipartFormHttpEntity {
@Test
public void testExplictContractorParams() throws Exception {
final MultipartEntity entity = new MultipartEntity(
HttpMultipartMode.BROWSER_COMPATIBLE,
"whatever",
Charset.forName("UTF-8"));
final HttpEntity entity = MultipartEntityBuilder.create()
.setLaxMode()
.setBoundary("whatever")
.setCharset(MIME.UTF8_CHARSET)
.build();
Assert.assertNull(entity.getContentEncoding());
Assert.assertNotNull(entity.getContentType());
@ -68,7 +68,7 @@ public class TestMultipartFormHttpEntity {
@Test
public void testImplictContractorParams() throws Exception {
final MultipartEntity entity = new MultipartEntity();
final HttpEntity entity = MultipartEntityBuilder.create().build();
Assert.assertNull(entity.getContentEncoding());
Assert.assertNotNull(entity.getContentType());
final Header header = entity.getContentType();
@ -93,9 +93,10 @@ public class TestMultipartFormHttpEntity {
@Test
public void testRepeatable() throws Exception {
final MultipartEntity entity = new MultipartEntity();
entity.addPart("p1", new StringBody("blah blah", ContentType.DEFAULT_TEXT));
entity.addPart("p2", new StringBody("yada yada", ContentType.DEFAULT_TEXT));
final HttpEntity entity = MultipartEntityBuilder.create()
.addTextBody("p1", "blah blah", ContentType.DEFAULT_TEXT)
.addTextBody("p2", "yada yada", ContentType.DEFAULT_TEXT)
.build();
Assert.assertTrue(entity.isRepeatable());
Assert.assertFalse(entity.isChunked());
Assert.assertFalse(entity.isStreaming());
@ -124,11 +125,12 @@ public class TestMultipartFormHttpEntity {
@Test
public void testNonRepeatable() throws Exception {
final MultipartEntity entity = new MultipartEntity();
entity.addPart("p1", new InputStreamBody(
new ByteArrayInputStream("blah blah".getBytes()), ContentType.DEFAULT_BINARY));
entity.addPart("p2", new InputStreamBody(
new ByteArrayInputStream("yada yada".getBytes()), ContentType.DEFAULT_BINARY));
final HttpEntity entity = MultipartEntityBuilder.create()
.addPart("p1", new InputStreamBody(
new ByteArrayInputStream("blah blah".getBytes()), ContentType.DEFAULT_BINARY))
.addPart("p2", new InputStreamBody(
new ByteArrayInputStream("yada yada".getBytes()), ContentType.DEFAULT_BINARY))
.build();
Assert.assertFalse(entity.isRepeatable());
Assert.assertTrue(entity.isChunked());
Assert.assertTrue(entity.isStreaming());