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:
parent
f596896b32
commit
9056303b5c
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
|
Loading…
Reference in New Issue