Simplified MIME multipart generation modes (legacy, strict and extended)

This commit is contained in:
Oleg Kalnichevski 2019-12-20 10:40:54 +01:00
parent 56463de35d
commit 54a341ea92
6 changed files with 43 additions and 28 deletions

View File

@ -28,18 +28,35 @@
package org.apache.hc.client5.http.entity.mime; package org.apache.hc.client5.http.entity.mime;
/** /**
* MIME compliance mode.
* *
* @since 4.0 * @since 4.0
*/ */
public enum HttpMultipartMode { public enum HttpMultipartMode {
/** RFC 822, RFC 2045, RFC 2046 compliant */ /**
* Legacy compatibility mode.
* <p>
* In this mode only the most essential fields are generated
* such as Content-Type and Content-Disposition.
*/
LEGACY,
/**
* Strict MIME specification conformance.
* <p>
* Presently conforms to RFC 822, RFC 2045, RFC 2046.
*/
STRICT, STRICT,
/** browser-compatible mode, i.e. only write Content-Disposition; use content charset */
BROWSER_COMPATIBLE, /**
/** RFC 6532 compliant */ * Extended MIME specification conformance.
RFC6532, * <p>
/** RFC 7578 compliant */ * In this mode header field values may contain international UTF-8 encoded
RFC7578 * characters.
* <p>
* Presently conforms to RFC 6532 and RFC 7578.
*/
EXTENDED,
} }

View File

@ -38,11 +38,11 @@ import java.util.List;
* *
* @since 4.3 * @since 4.3
*/ */
class HttpBrowserCompatibleMultipart extends AbstractMultipartFormat { class LegacyMultipart extends AbstractMultipartFormat {
private final List<MultipartPart> parts; private final List<MultipartPart> parts;
public HttpBrowserCompatibleMultipart( public LegacyMultipart(
final Charset charset, final Charset charset,
final String boundary, final String boundary,
final List<MultipartPart> parts) { final List<MultipartPart> parts) {

View File

@ -56,9 +56,6 @@ public class MultipartEntityBuilder {
"-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
.toCharArray(); .toCharArray();
private final static String FORM_SUBTYPE = "form-data";
private final static String MIXED_SUBTYPE = "mixed";
private ContentType contentType; private ContentType contentType;
private HttpMultipartMode mode = HttpMultipartMode.STRICT; private HttpMultipartMode mode = HttpMultipartMode.STRICT;
private String boundary = null; private String boundary = null;
@ -78,7 +75,7 @@ public class MultipartEntityBuilder {
} }
public MultipartEntityBuilder setLaxMode() { public MultipartEntityBuilder setLaxMode() {
this.mode = HttpMultipartMode.BROWSER_COMPATIBLE; this.mode = HttpMultipartMode.LEGACY;
return this; return this;
} }
@ -219,9 +216,9 @@ public class MultipartEntityBuilder {
} }
if (formData) { if (formData) {
contentTypeCopy = ContentType.create("multipart/" + FORM_SUBTYPE, params); contentTypeCopy = ContentType.MULTIPART_FORM_DATA.withParameters(params);
} else { } else {
contentTypeCopy = ContentType.create("multipart/" + MIXED_SUBTYPE, params); contentTypeCopy = ContentType.create("multipart/mixed", params);
} }
} }
final List<MultipartPart> multipartPartsCopy = multipartParts != null ? new ArrayList<>(multipartParts) : final List<MultipartPart> multipartPartsCopy = multipartParts != null ? new ArrayList<>(multipartParts) :
@ -229,17 +226,18 @@ public class MultipartEntityBuilder {
final HttpMultipartMode modeCopy = mode != null ? mode : HttpMultipartMode.STRICT; final HttpMultipartMode modeCopy = mode != null ? mode : HttpMultipartMode.STRICT;
final AbstractMultipartFormat form; final AbstractMultipartFormat form;
switch (modeCopy) { switch (modeCopy) {
case BROWSER_COMPATIBLE: case LEGACY:
form = new HttpBrowserCompatibleMultipart(charsetCopy, boundaryCopy, multipartPartsCopy); form = new LegacyMultipart(charsetCopy, boundaryCopy, multipartPartsCopy);
break; break;
case RFC6532: case EXTENDED:
form = new HttpRFC6532Multipart(charsetCopy, boundaryCopy, multipartPartsCopy); if (ContentType.MULTIPART_FORM_DATA.isSameMimeType(ContentType.MULTIPART_FORM_DATA)) {
break; if (charsetCopy == null) {
case RFC7578: charsetCopy = StandardCharsets.UTF_8;
if (charsetCopy == null) { }
charsetCopy = StandardCharsets.UTF_8; form = new HttpRFC7578Multipart(charsetCopy, boundaryCopy, multipartPartsCopy);
} else {
form = new HttpRFC6532Multipart(charsetCopy, boundaryCopy, multipartPartsCopy);
} }
form = new HttpRFC7578Multipart(charsetCopy, boundaryCopy, multipartPartsCopy);
break; break;
default: default:
form = new HttpStrictMultipart(StandardCharsets.US_ASCII, boundaryCopy, multipartPartsCopy); form = new HttpStrictMultipart(StandardCharsets.US_ASCII, boundaryCopy, multipartPartsCopy);

View File

@ -58,7 +58,7 @@ public class TestMultipartEntityBuilder {
.setLaxMode() .setLaxMode()
.buildEntity(); .buildEntity();
Assert.assertNotNull(entity); Assert.assertNotNull(entity);
Assert.assertTrue(entity.getMultipart() instanceof HttpBrowserCompatibleMultipart); Assert.assertTrue(entity.getMultipart() instanceof LegacyMultipart);
Assert.assertEquals("blah-blah", entity.getMultipart().boundary); Assert.assertEquals("blah-blah", entity.getMultipart().boundary);
Assert.assertEquals(StandardCharsets.UTF_8, entity.getMultipart().charset); Assert.assertEquals(StandardCharsets.UTF_8, entity.getMultipart().charset);
} }
@ -151,7 +151,7 @@ public class TestMultipartEntityBuilder {
parameters.add(new BasicNameValuePair(MimeConsts.FIELD_PARAM_FILENAME, "hello \u03BA\u03CC\u03C3\u03BC\u03B5!%")); parameters.add(new BasicNameValuePair(MimeConsts.FIELD_PARAM_FILENAME, "hello \u03BA\u03CC\u03C3\u03BC\u03B5!%"));
final MultipartFormEntity entity = MultipartEntityBuilder.create() final MultipartFormEntity entity = MultipartEntityBuilder.create()
.setMode(HttpMultipartMode.RFC7578) .setMode(HttpMultipartMode.EXTENDED)
.setBoundary("xxxxxxxxxxxxxxxxxxxxxxxx") .setBoundary("xxxxxxxxxxxxxxxxxxxxxxxx")
.addPart(new FormBodyPartBuilder() .addPart(new FormBodyPartBuilder()
.setName("test") .setName("test")

View File

@ -300,7 +300,7 @@ public class TestMultipartForm {
final FormBodyPart p2 = FormBodyPartBuilder.create( final FormBodyPart p2 = FormBodyPartBuilder.create(
"field2", "field2",
new InputStreamBody(new FileInputStream(tmpfile), s2 + ".tmp")).build(); new InputStreamBody(new FileInputStream(tmpfile), s2 + ".tmp")).build();
final HttpBrowserCompatibleMultipart multipart = new HttpBrowserCompatibleMultipart( final LegacyMultipart multipart = new LegacyMultipart(
StandardCharsets.UTF_8, "foo", StandardCharsets.UTF_8, "foo",
Arrays.<MultipartPart>asList(p1, p2)); Arrays.<MultipartPart>asList(p1, p2));

View File

@ -264,7 +264,7 @@ public class TestMultipartMixed {
@SuppressWarnings("resource") @SuppressWarnings("resource")
final MultipartPart p2 = MultipartPartBuilder.create( final MultipartPart p2 = MultipartPartBuilder.create(
new InputStreamBody(new FileInputStream(tmpfile), s2 + ".tmp")).build(); new InputStreamBody(new FileInputStream(tmpfile), s2 + ".tmp")).build();
final HttpBrowserCompatibleMultipart multipart = new HttpBrowserCompatibleMultipart( final LegacyMultipart multipart = new LegacyMultipart(
StandardCharsets.UTF_8, "foo", StandardCharsets.UTF_8, "foo",
Arrays.<MultipartPart>asList(p1, p2)); Arrays.<MultipartPart>asList(p1, p2));