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.io.ByteArrayInputStream;
31 import java.io.ByteArrayOutputStream;
32 import java.io.File;
33 import java.nio.charset.StandardCharsets;
34 import java.util.ArrayList;
35 import java.util.List;
36
37 import org.apache.hc.core5.http.ContentType;
38 import org.apache.hc.core5.http.NameValuePair;
39 import org.apache.hc.core5.http.message.BasicNameValuePair;
40 import org.junit.jupiter.api.Assertions;
41 import org.junit.jupiter.api.Test;
42
43 public class TestMultipartEntityBuilder {
44
45 @Test
46 public void testBasics() throws Exception {
47 final MultipartFormEntity entity = MultipartEntityBuilder.create().buildEntity();
48 Assertions.assertNotNull(entity);
49 Assertions.assertTrue(entity.getMultipart() instanceof HttpStrictMultipart);
50 Assertions.assertEquals(0, entity.getMultipart().getParts().size());
51 }
52
53 @Test
54 public void testMultipartOptions() throws Exception {
55 final MultipartFormEntity entity = MultipartEntityBuilder.create()
56 .setBoundary("blah-blah")
57 .setCharset(StandardCharsets.UTF_8)
58 .setLaxMode()
59 .buildEntity();
60 Assertions.assertNotNull(entity);
61 Assertions.assertTrue(entity.getMultipart() instanceof LegacyMultipart);
62 Assertions.assertEquals("blah-blah", entity.getMultipart().boundary);
63 Assertions.assertEquals(StandardCharsets.UTF_8, entity.getMultipart().charset);
64 }
65
66 @Test
67 public void testAddBodyParts() throws Exception {
68 final MultipartFormEntity entity = MultipartEntityBuilder.create()
69 .addTextBody("p1", "stuff")
70 .addBinaryBody("p2", new File("stuff"))
71 .addBinaryBody("p3", new byte[]{})
72 .addBinaryBody("p4", new ByteArrayInputStream(new byte[]{}))
73 .addBinaryBody("p5", new ByteArrayInputStream(new byte[]{}), ContentType.DEFAULT_BINARY, "filename")
74 .buildEntity();
75 Assertions.assertNotNull(entity);
76 final List<MultipartPart> bodyParts = entity.getMultipart().getParts();
77 Assertions.assertNotNull(bodyParts);
78 Assertions.assertEquals(5, bodyParts.size());
79 }
80
81
82 @Test
83 public void testMultipartCustomContentType() throws Exception {
84 final MultipartFormEntity entity = MultipartEntityBuilder.create()
85 .setContentType(ContentType.APPLICATION_XML)
86 .setBoundary("blah-blah")
87 .setCharset(StandardCharsets.UTF_8)
88 .setLaxMode()
89 .buildEntity();
90 Assertions.assertNotNull(entity);
91 Assertions.assertEquals("application/xml; boundary=blah-blah; charset=UTF-8", entity.getContentType());
92 }
93
94 @Test
95 public void testMultipartContentTypeParameter() throws Exception {
96 final MultipartFormEntity entity = MultipartEntityBuilder.create()
97 .setContentType(ContentType.MULTIPART_FORM_DATA.withParameters(
98 new BasicNameValuePair("boundary", "yada-yada"),
99 new BasicNameValuePair("charset", "ascii")))
100 .buildEntity();
101 Assertions.assertNotNull(entity);
102 Assertions.assertEquals("multipart/form-data; boundary=yada-yada; charset=US-ASCII", entity.getContentType());
103 Assertions.assertEquals("yada-yada", entity.getMultipart().boundary);
104 Assertions.assertEquals(StandardCharsets.US_ASCII, entity.getMultipart().charset);
105 }
106
107 @Test
108 public void testMultipartCustomContentTypeParameterOverrides() throws Exception {
109 final MultipartFormEntity entity = MultipartEntityBuilder.create()
110 .setContentType(ContentType.MULTIPART_FORM_DATA.withParameters(
111 new BasicNameValuePair("boundary", "yada-yada"),
112 new BasicNameValuePair("charset", "ascii"),
113 new BasicNameValuePair("my", "stuff")))
114 .setBoundary("blah-blah")
115 .setCharset(StandardCharsets.UTF_8)
116 .setLaxMode()
117 .buildEntity();
118 Assertions.assertNotNull(entity);
119 Assertions.assertEquals("multipart/form-data; boundary=blah-blah; charset=UTF-8; my=stuff",
120 entity.getContentType());
121 }
122
123 @Test
124 public void testMultipartCustomContentTypeUsingAddParameter() {
125 final MultipartEntityBuilder eb = MultipartEntityBuilder.create();
126 eb.setMimeSubtype("related");
127 eb.addParameter(new BasicNameValuePair("boundary", "yada-yada"));
128 eb.addParameter(new BasicNameValuePair("charset", "ascii"));
129 eb.addParameter(new BasicNameValuePair("my", "stuff"));
130 eb.buildEntity();
131 final MultipartFormEntity entity = eb.buildEntity();
132 Assertions.assertNotNull(entity);
133 Assertions.assertEquals("multipart/related; boundary=yada-yada; charset=US-ASCII; my=stuff",
134 entity.getContentType());
135 }
136
137 @Test
138 public void testMultipartWriteTo() throws Exception {
139 final String helloWorld = "hello world";
140 final List<NameValuePair> parameters = new ArrayList<>();
141 parameters.add(new BasicNameValuePair(MimeConsts.FIELD_PARAM_NAME, "test"));
142 parameters.add(new BasicNameValuePair(MimeConsts.FIELD_PARAM_FILENAME, helloWorld));
143 final MultipartFormEntity entity = MultipartEntityBuilder.create()
144 .setStrictMode()
145 .setBoundary("xxxxxxxxxxxxxxxxxxxxxxxx")
146 .addPart(new FormBodyPartBuilder()
147 .setName("test")
148 .setBody(new StringBody("hello world", ContentType.TEXT_PLAIN))
149 .addField("Content-Disposition", "multipart/form-data", parameters)
150 .build())
151 .buildEntity();
152
153
154 final ByteArrayOutputStream out = new ByteArrayOutputStream();
155 entity.writeTo(out);
156 out.close();
157 Assertions.assertEquals("--xxxxxxxxxxxxxxxxxxxxxxxx\r\n" +
158 "Content-Disposition: multipart/form-data; name=\"test\"; filename=\"hello world\"\r\n" +
159 "Content-Type: text/plain; charset=UTF-8\r\n" +
160 "\r\n" +
161 helloWorld + "\r\n" +
162 "--xxxxxxxxxxxxxxxxxxxxxxxx--\r\n", out.toString(StandardCharsets.US_ASCII.name()));
163 }
164
165 @Test
166 public void testMultipartWriteToRFC7578Mode() throws Exception {
167 final String helloWorld = "hello \u03BA\u03CC\u03C3\u03BC\u03B5!%";
168 final List<NameValuePair> parameters = new ArrayList<>();
169 parameters.add(new BasicNameValuePair(MimeConsts.FIELD_PARAM_NAME, "test"));
170 parameters.add(new BasicNameValuePair(MimeConsts.FIELD_PARAM_FILENAME, helloWorld));
171
172 final MultipartFormEntity entity = MultipartEntityBuilder.create()
173 .setMode(HttpMultipartMode.EXTENDED)
174 .setBoundary("xxxxxxxxxxxxxxxxxxxxxxxx")
175 .addPart(new FormBodyPartBuilder()
176 .setName("test")
177 .setBody(new StringBody(helloWorld, ContentType.TEXT_PLAIN.withCharset(StandardCharsets.UTF_8)))
178 .addField("Content-Disposition", "multipart/form-data", parameters)
179 .build())
180 .buildEntity();
181
182 final ByteArrayOutputStream out = new ByteArrayOutputStream();
183 entity.writeTo(out);
184 out.close();
185 Assertions.assertEquals("--xxxxxxxxxxxxxxxxxxxxxxxx\r\n" +
186 "Content-Disposition: multipart/form-data; name=\"test\"; filename=\"hello%20%CE%BA%CF%8C%CF%83%CE%BC%CE%B5!%25\"\r\n" +
187 "Content-Type: text/plain; charset=UTF-8\r\n" +
188 "\r\n" +
189 "hello \u00ce\u00ba\u00cf\u008c\u00cf\u0083\u00ce\u00bc\u00ce\u00b5!%\r\n" +
190 "--xxxxxxxxxxxxxxxxxxxxxxxx--\r\n", out.toString(StandardCharsets.ISO_8859_1.name()));
191 }
192
193 @Test
194 public void testMultipartWriteToRFC6532Mode() throws Exception {
195 final String helloWorld = "hello \u03BA\u03CC\u03C3\u03BC\u03B5!%";
196 final List<NameValuePair> parameters = new ArrayList<>();
197 parameters.add(new BasicNameValuePair(MimeConsts.FIELD_PARAM_NAME, "test"));
198 parameters.add(new BasicNameValuePair(MimeConsts.FIELD_PARAM_FILENAME, helloWorld));
199
200 final MultipartFormEntity entity = MultipartEntityBuilder.create()
201 .setMode(HttpMultipartMode.EXTENDED)
202 .setContentType(ContentType.create("multipart/other"))
203 .setBoundary("xxxxxxxxxxxxxxxxxxxxxxxx")
204 .addPart(new FormBodyPartBuilder()
205 .setName("test")
206 .setBody(new StringBody(helloWorld, ContentType.TEXT_PLAIN.withCharset(StandardCharsets.UTF_8)))
207 .addField("Content-Disposition", "multipart/form-data", parameters)
208 .build())
209 .buildEntity();
210
211 final ByteArrayOutputStream out = new ByteArrayOutputStream();
212 entity.writeTo(out);
213 out.close();
214 Assertions.assertEquals("--xxxxxxxxxxxxxxxxxxxxxxxx\r\n" +
215 "Content-Disposition: multipart/form-data; name=\"test\"; " +
216 "filename=\"hello \u00ce\u00ba\u00cf\u008c\u00cf\u0083\u00ce\u00bc\u00ce\u00b5!%\"\r\n" +
217 "Content-Type: text/plain; charset=UTF-8\r\n" +
218 "\r\n" +
219 "hello \u00ce\u00ba\u00cf\u008c\u00cf\u0083\u00ce\u00bc\u00ce\u00b5!%\r\n" +
220 "--xxxxxxxxxxxxxxxxxxxxxxxx--\r\n", out.toString(StandardCharsets.ISO_8859_1.name()));
221 }
222
223 @Test
224 public void testMultipartWriteToWithPreambleAndEpilogue() throws Exception {
225 final String helloWorld = "hello \u03BA\u03CC\u03C3\u03BC\u03B5!%";
226 final List<NameValuePair> parameters = new ArrayList<>();
227 parameters.add(new BasicNameValuePair(MimeConsts.FIELD_PARAM_NAME, "test"));
228 parameters.add(new BasicNameValuePair(MimeConsts.FIELD_PARAM_FILENAME, helloWorld));
229
230 final MultipartFormEntity entity = MultipartEntityBuilder.create()
231 .setMode(HttpMultipartMode.EXTENDED)
232 .setContentType(ContentType.create("multipart/other"))
233 .setBoundary("xxxxxxxxxxxxxxxxxxxxxxxx")
234 .addPart(new FormBodyPartBuilder()
235 .setName("test")
236 .setBody(new StringBody(helloWorld, ContentType.TEXT_PLAIN.withCharset(StandardCharsets.UTF_8)))
237 .addField("Content-Disposition", "multipart/form-data", parameters)
238 .build())
239 .addPreamble("This is the preamble.")
240 .addEpilogue("This is the epilogue.")
241 .buildEntity();
242
243 final ByteArrayOutputStream out = new ByteArrayOutputStream();
244 entity.writeTo(out);
245 out.close();
246 Assertions.assertEquals("This is the preamble.\r\n" +
247 "--xxxxxxxxxxxxxxxxxxxxxxxx\r\n" +
248 "Content-Disposition: multipart/form-data; name=\"test\"; " +
249 "filename=\"hello \u00ce\u00ba\u00cf\u008c\u00cf\u0083\u00ce\u00bc\u00ce\u00b5!%\"\r\n" +
250 "Content-Type: text/plain; charset=UTF-8\r\n" +
251 "\r\n" +
252 "hello \u00ce\u00ba\u00cf\u008c\u00cf\u0083\u00ce\u00bc\u00ce\u00b5!%\r\n" +
253 "--xxxxxxxxxxxxxxxxxxxxxxxx--\r\n" +
254 "This is the epilogue.\r\n", out.toString(StandardCharsets.ISO_8859_1.name()));
255 }
256
257 @Test
258 public void testMultipartWriteToRFC7578ModeWithFilenameStar() throws Exception {
259 final String helloWorld = "hello \u03BA\u03CC\u03C3\u03BC\u03B5!%";
260 final List<NameValuePair> parameters = new ArrayList<>();
261 parameters.add(new BasicNameValuePair(MimeConsts.FIELD_PARAM_NAME, "test"));
262 parameters.add(new BasicNameValuePair(MimeConsts.FIELD_PARAM_FILENAME_START, helloWorld));
263
264 final MultipartFormEntity entity = MultipartEntityBuilder.create()
265 .setMode(HttpMultipartMode.EXTENDED)
266 .setBoundary("xxxxxxxxxxxxxxxxxxxxxxxx")
267 .addPart(new FormBodyPartBuilder()
268 .setName("test")
269 .setBody(new StringBody(helloWorld, ContentType.TEXT_PLAIN.withCharset(StandardCharsets.UTF_8)))
270 .addField("Content-Disposition", "multipart/form-data", parameters)
271 .build())
272 .buildEntity();
273
274 final ByteArrayOutputStream out = new ByteArrayOutputStream();
275 entity.writeTo(out);
276 out.close();
277 Assertions.assertEquals("--xxxxxxxxxxxxxxxxxxxxxxxx\r\n" +
278 "Content-Disposition: multipart/form-data; name=\"test\"; filename*=\"UTF-8''hello%20%CE%BA%CF%8C%CF%83%CE%BC%CE%B5!%25\"\r\n" +
279 "Content-Type: text/plain; charset=UTF-8\r\n" +
280 "\r\n" +
281 "hello \u00ce\u00ba\u00cf\u008c\u00cf\u0083\u00ce\u00bc\u00ce\u00b5!%\r\n" +
282 "--xxxxxxxxxxxxxxxxxxxxxxxx--\r\n", out.toString(StandardCharsets.ISO_8859_1.name()));
283 }
284
285 }