1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.hc.client5.http.entity.mime;
29
30 import java.nio.charset.CharsetEncoder;
31 import java.nio.charset.StandardCharsets;
32 import java.util.ArrayList;
33 import java.util.List;
34
35 import org.apache.hc.core5.http.ContentType;
36 import org.apache.hc.core5.http.NameValuePair;
37 import org.apache.hc.core5.http.message.BasicNameValuePair;
38 import org.apache.hc.core5.net.PercentCodec;
39 import org.apache.hc.core5.util.Args;
40 import org.apache.hc.core5.util.Asserts;
41
42
43
44
45
46
47 public class FormBodyPartBuilder {
48
49 private String name;
50 private ContentBody body;
51 private final Header header;
52
53
54
55
56
57
58
59 private HttpMultipartMode mode;
60
61
62
63
64
65 private CharsetEncoder iso8859_1Encoder;
66
67
68
69
70
71
72
73
74
75
76
77 public static FormBodyPartBuilder create(final String name, final ContentBody body, final HttpMultipartMode mode) {
78 return new FormBodyPartBuilder(name, body, mode);
79 }
80
81 public static FormBodyPartBuilder create(final String name, final ContentBody body) {
82 return new FormBodyPartBuilder(name, body, HttpMultipartMode.STRICT);
83 }
84
85 public static FormBodyPartBuilder create() {
86 return new FormBodyPartBuilder();
87 }
88
89 FormBodyPartBuilder(final String name, final ContentBody body, final HttpMultipartMode mode) {
90 this();
91 this.name = name;
92 this.body = body;
93 this.mode = mode != null ? mode : HttpMultipartMode.STRICT;
94 }
95
96 FormBodyPartBuilder() {
97 this.header = new Header();
98 this.mode = HttpMultipartMode.STRICT;
99 }
100
101 public FormBodyPartBuilder setName(final String name) {
102 this.name = name;
103 return this;
104 }
105
106 public FormBodyPartBuilder setBody(final ContentBody body) {
107 this.body = body;
108 return this;
109 }
110
111
112
113
114 public FormBodyPartBuilder addField(final String name, final String value, final List<NameValuePair> parameters) {
115 Args.notNull(name, "Field name");
116 this.header.addField(new MimeField(name, value, parameters));
117 return this;
118 }
119
120 public FormBodyPartBuilder addField(final String name, final String value) {
121 Args.notNull(name, "Field name");
122 this.header.addField(new MimeField(name, value));
123 return this;
124 }
125
126 public FormBodyPartBuilder setField(final String name, final String value) {
127 Args.notNull(name, "Field name");
128 this.header.setField(new MimeField(name, value));
129 return this;
130 }
131
132 public FormBodyPartBuilder removeFields(final String name) {
133 Args.notNull(name, "Field name");
134 this.header.removeFields(name);
135 return this;
136 }
137
138
139
140
141
142
143
144
145
146
147 private boolean canEncodeToISO8859_1(final String input) {
148 if (iso8859_1Encoder == null) {
149 iso8859_1Encoder = StandardCharsets.ISO_8859_1.newEncoder();
150 }
151 return iso8859_1Encoder.canEncode(input);
152 }
153
154
155
156
157
158
159
160
161
162
163 private static String encodeRFC5987(final String filename) {
164 return "UTF-8''" + PercentCodec.RFC5987.encode(filename);
165 }
166
167 public FormBodyPart build() {
168 Asserts.notBlank(this.name, "Name");
169 Asserts.notNull(this.body, "Content body");
170 final Header headerCopy = new Header();
171 final List<MimeField> fields = this.header.getFields();
172 for (final MimeField field: fields) {
173 headerCopy.addField(field);
174 }
175 if (headerCopy.getField(MimeConsts.CONTENT_DISPOSITION) == null) {
176 final List<NameValuePair> fieldParameters = new ArrayList<>();
177 fieldParameters.add(new BasicNameValuePair(MimeConsts.FIELD_PARAM_NAME, this.name));
178 if (this.body.getFilename() != null) {
179 final String filename = this.body.getFilename();
180 fieldParameters.add(new BasicNameValuePair(MimeConsts.FIELD_PARAM_FILENAME, filename));
181
182 if (mode != HttpMultipartMode.LEGACY && !canEncodeToISO8859_1(filename)) {
183 fieldParameters.add(new BasicNameValuePair(MimeConsts.FIELD_PARAM_FILENAME_START, encodeRFC5987(filename)));
184 }
185 }
186 headerCopy.addField(new MimeField(MimeConsts.CONTENT_DISPOSITION, "form-data", fieldParameters));
187 }
188 if (headerCopy.getField(MimeConsts.CONTENT_TYPE) == null) {
189 final ContentType contentType;
190 if (body instanceof AbstractContentBody) {
191 contentType = ((AbstractContentBody) body).getContentType();
192 } else {
193 contentType = null;
194 }
195 if (contentType != null) {
196 headerCopy.addField(new MimeField(MimeConsts.CONTENT_TYPE, contentType.toString()));
197 } else {
198 final StringBuilder buffer = new StringBuilder();
199 buffer.append(this.body.getMimeType());
200 if (this.body.getCharset() != null) {
201 buffer.append("; charset=");
202 buffer.append(this.body.getCharset());
203 }
204 headerCopy.addField(new MimeField(MimeConsts.CONTENT_TYPE, buffer.toString()));
205 }
206 }
207 return new FormBodyPart(this.name, this.body, headerCopy);
208 }
209 }