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.ByteArrayOutputStream;
31 import java.io.File;
32 import java.io.FileInputStream;
33 import java.io.FileWriter;
34 import java.io.Writer;
35 import java.nio.charset.Charset;
36 import java.nio.charset.StandardCharsets;
37 import java.util.Arrays;
38
39 import org.apache.hc.core5.http.ContentType;
40 import org.junit.jupiter.api.AfterEach;
41 import org.junit.jupiter.api.Assertions;
42 import org.junit.jupiter.api.Test;
43
44 class TestMultipartMixed {
45
46 private File tmpfile;
47
48 @AfterEach
49 void cleanup() {
50 if (tmpfile != null) {
51 tmpfile.delete();
52 }
53 }
54
55 @Test
56 void testMultipartPartStringParts() throws Exception {
57 final MultipartPart p1 = MultipartPartBuilder.create(
58 new StringBody("this stuff", ContentType.DEFAULT_TEXT)).build();
59 final MultipartPart p2 = MultipartPartBuilder.create(
60 new StringBody("that stuff", ContentType.create(
61 ContentType.TEXT_PLAIN.getMimeType(), StandardCharsets.ISO_8859_1))).build();
62 final MultipartPart p3 = MultipartPartBuilder.create(
63 new StringBody("all kind of stuff", ContentType.DEFAULT_TEXT)).build();
64 final HttpStrictMultipart multipart = new HttpStrictMultipart(null, "foo",
65 Arrays.asList(p1, p2, p3));
66
67 final ByteArrayOutputStream out = new ByteArrayOutputStream();
68 multipart.writeTo(out);
69 out.close();
70
71 final String expected =
72 "--foo\r\n" +
73 "Content-Type: text/plain; charset=UTF-8\r\n" +
74 "\r\n" +
75 "this stuff\r\n" +
76 "--foo\r\n" +
77 "Content-Type: text/plain; charset=ISO-8859-1\r\n" +
78 "\r\n" +
79 "that stuff\r\n" +
80 "--foo\r\n" +
81 "Content-Type: text/plain; charset=UTF-8\r\n" +
82 "\r\n" +
83 "all kind of stuff\r\n" +
84 "--foo--\r\n";
85 final String s = out.toString("US-ASCII");
86 Assertions.assertEquals(expected, s);
87 Assertions.assertEquals(s.length(), multipart.getTotalLength());
88 }
89
90 @Test
91 void testMultipartPartCustomContentType() throws Exception {
92 final MultipartPart p1 = MultipartPartBuilder.create(
93 new StringBody("this stuff", ContentType.DEFAULT_TEXT)).build();
94 final MultipartPart p2 = MultipartPartBuilder.create(
95 new StringBody("that stuff", ContentType.parse("stuff/plain; param=value"))).build();
96 final HttpStrictMultipart multipart = new HttpStrictMultipart(null, "foo",
97 Arrays.asList(p1, p2));
98
99 final ByteArrayOutputStream out = new ByteArrayOutputStream();
100 multipart.writeTo(out);
101 out.close();
102
103 final String expected =
104 "--foo\r\n" +
105 "Content-Type: text/plain; charset=UTF-8\r\n" +
106 "\r\n" +
107 "this stuff\r\n" +
108 "--foo\r\n" +
109 "Content-Type: stuff/plain; param=value\r\n" +
110 "\r\n" +
111 "that stuff\r\n" +
112 "--foo--\r\n";
113 final String s = out.toString("US-ASCII");
114 Assertions.assertEquals(expected, s);
115 Assertions.assertEquals(s.length(), multipart.getTotalLength());
116 }
117
118 @Test
119 void testMultipartPartBinaryParts() throws Exception {
120 tmpfile = File.createTempFile("tmp", ".bin");
121 try (Writer writer = new FileWriter(tmpfile)) {
122 writer.append("some random whatever");
123 }
124
125 final MultipartPart p1 = MultipartPartBuilder.create(
126 new FileBody(tmpfile)).build();
127 @SuppressWarnings("resource")
128 final MultipartPart p2 = MultipartPartBuilder.create(
129 new InputStreamBody(new FileInputStream(tmpfile), "file.tmp")).build();
130 final HttpStrictMultipart multipart = new HttpStrictMultipart(null, "foo",
131 Arrays.asList(p1, p2));
132
133 final ByteArrayOutputStream out = new ByteArrayOutputStream();
134 multipart.writeTo(out);
135 out.close();
136
137 final String expected =
138 "--foo\r\n" +
139 "Content-Type: application/octet-stream\r\n" +
140 "\r\n" +
141 "some random whatever\r\n" +
142 "--foo\r\n" +
143 "Content-Type: application/octet-stream\r\n" +
144 "\r\n" +
145 "some random whatever\r\n" +
146 "--foo--\r\n";
147 final String s = out.toString("US-ASCII");
148 Assertions.assertEquals(expected, s);
149 Assertions.assertEquals(-1, multipart.getTotalLength());
150 }
151
152 @Test
153 void testMultipartPartStrict() throws Exception {
154 tmpfile = File.createTempFile("tmp", ".bin");
155 try (Writer writer = new FileWriter(tmpfile)) {
156 writer.append("some random whatever");
157 }
158
159 final MultipartPart p1 = MultipartPartBuilder.create(
160 new FileBody(tmpfile)).build();
161 final MultipartPart p2 = MultipartPartBuilder.create(
162 new FileBody(tmpfile, ContentType.create("text/plain", "ANSI_X3.4-1968"), "test-file")).build();
163 @SuppressWarnings("resource")
164 final MultipartPart p3 = MultipartPartBuilder.create(
165 new InputStreamBody(new FileInputStream(tmpfile), "file.tmp")).build();
166 final HttpStrictMultipart multipart = new HttpStrictMultipart(null, "foo",
167 Arrays.asList(p1, p2, p3));
168
169 final ByteArrayOutputStream out = new ByteArrayOutputStream();
170 multipart.writeTo(out);
171 out.close();
172
173 final String expected =
174 "--foo\r\n" +
175 "Content-Type: application/octet-stream\r\n" +
176 "\r\n" +
177 "some random whatever\r\n" +
178 "--foo\r\n" +
179 "Content-Type: text/plain; charset=US-ASCII\r\n" +
180 "\r\n" +
181 "some random whatever\r\n" +
182 "--foo\r\n" +
183 "Content-Type: application/octet-stream\r\n" +
184 "\r\n" +
185 "some random whatever\r\n" +
186 "--foo--\r\n";
187 final String s = out.toString("US-ASCII");
188 Assertions.assertEquals(expected, s);
189 Assertions.assertEquals(-1, multipart.getTotalLength());
190 }
191
192 @Test
193 void testMultipartPartRFC6532() throws Exception {
194 tmpfile = File.createTempFile("tmp", ".bin");
195 try (Writer writer = new FileWriter(tmpfile)) {
196 writer.append("some random whatever");
197 }
198
199 final MultipartPart p1 = MultipartPartBuilder.create(
200 new FileBody(tmpfile)).build();
201 final MultipartPart p2 = MultipartPartBuilder.create(
202 new FileBody(tmpfile, ContentType.create("text/plain", "ANSI_X3.4-1968"), "test-file")).build();
203 @SuppressWarnings("resource")
204 final MultipartPart p3 = MultipartPartBuilder.create(
205 new InputStreamBody(new FileInputStream(tmpfile), "file.tmp")).build();
206 final HttpRFC6532Multipart multipart = new HttpRFC6532Multipart(null, "foo",
207 Arrays.asList(p1, p2, p3));
208
209 final ByteArrayOutputStream out = new ByteArrayOutputStream();
210 multipart.writeTo(out);
211 out.close();
212
213 final String expected =
214 "--foo\r\n" +
215 "Content-Type: application/octet-stream\r\n" +
216 "\r\n" +
217 "some random whatever\r\n" +
218 "--foo\r\n" +
219 "Content-Type: text/plain; charset=US-ASCII\r\n" +
220 "\r\n" +
221 "some random whatever\r\n" +
222 "--foo\r\n" +
223 "Content-Type: application/octet-stream\r\n" +
224 "\r\n" +
225 "some random whatever\r\n" +
226 "--foo--\r\n";
227 final String s = out.toString("UTF-8");
228 Assertions.assertEquals(expected, s);
229 Assertions.assertEquals(-1, multipart.getTotalLength());
230 }
231
232 private static final int SWISS_GERMAN_HELLO [] = {
233 0x47, 0x72, 0xFC, 0x65, 0x7A, 0x69, 0x5F, 0x7A, 0xE4, 0x6D, 0xE4
234 };
235
236 private static final int RUSSIAN_HELLO [] = {
237 0x412, 0x441, 0x435, 0x43C, 0x5F, 0x43F, 0x440, 0x438,
238 0x432, 0x435, 0x442
239 };
240
241 private static String constructString(final int [] unicodeChars) {
242 final StringBuilder buffer = new StringBuilder();
243 if (unicodeChars != null) {
244 for (final int unicodeChar : unicodeChars) {
245 buffer.append((char)unicodeChar);
246 }
247 }
248 return buffer.toString();
249 }
250
251 @Test
252 void testMultipartPartBrowserCompatibleNonASCIIHeaders() throws Exception {
253 final String s1 = constructString(SWISS_GERMAN_HELLO);
254 final String s2 = constructString(RUSSIAN_HELLO);
255
256 tmpfile = File.createTempFile("tmp", ".bin");
257 try (Writer writer = new FileWriter(tmpfile)) {
258 writer.append("some random whatever");
259 }
260
261 @SuppressWarnings("resource")
262 final MultipartPart p1 = MultipartPartBuilder.create(
263 new InputStreamBody(new FileInputStream(tmpfile), s1 + ".tmp")).build();
264 @SuppressWarnings("resource")
265 final MultipartPart p2 = MultipartPartBuilder.create(
266 new InputStreamBody(new FileInputStream(tmpfile), s2 + ".tmp")).build();
267 final LegacyMultipart multipart = new LegacyMultipart(
268 StandardCharsets.UTF_8, "foo",
269 Arrays.asList(p1, p2));
270
271 final ByteArrayOutputStream out = new ByteArrayOutputStream();
272 multipart.writeTo(out);
273 out.close();
274
275 final String expected =
276 "--foo\r\n" +
277 "Content-Type: application/octet-stream\r\n" +
278 "\r\n" +
279 "some random whatever\r\n" +
280 "--foo\r\n" +
281 "Content-Type: application/octet-stream\r\n" +
282 "\r\n" +
283 "some random whatever\r\n" +
284 "--foo--\r\n";
285 final String s = out.toString("UTF-8");
286 Assertions.assertEquals(expected, s);
287 Assertions.assertEquals(-1, multipart.getTotalLength());
288 }
289
290 @Test
291 void testMultipartPartStringPartsMultiCharsets() throws Exception {
292 final String s1 = constructString(SWISS_GERMAN_HELLO);
293 final String s2 = constructString(RUSSIAN_HELLO);
294
295 final MultipartPart p1 = MultipartPartBuilder.create(
296 new StringBody(s1, ContentType.create("text/plain", StandardCharsets.ISO_8859_1))).build();
297 final MultipartPart p2 = MultipartPartBuilder.create(
298 new StringBody(s2, ContentType.create("text/plain", Charset.forName("KOI8-R")))).build();
299 final HttpStrictMultipart multipart = new HttpStrictMultipart(null, "foo",
300 Arrays.asList(p1, p2));
301
302 final ByteArrayOutputStream out1 = new ByteArrayOutputStream();
303 multipart.writeTo(out1);
304 out1.close();
305
306 final ByteArrayOutputStream out2 = new ByteArrayOutputStream();
307
308 out2.write((
309 "--foo\r\n" +
310 "Content-Type: text/plain; charset=ISO-8859-1\r\n" +
311 "\r\n").getBytes(StandardCharsets.US_ASCII));
312 out2.write(s1.getBytes(StandardCharsets.ISO_8859_1));
313 out2.write(("\r\n" +
314 "--foo\r\n" +
315 "Content-Type: text/plain; charset=KOI8-R\r\n" +
316 "\r\n").getBytes(StandardCharsets.US_ASCII));
317 out2.write(s2.getBytes(Charset.forName("KOI8-R")));
318 out2.write(("\r\n" +
319 "--foo--\r\n").getBytes(StandardCharsets.US_ASCII));
320 out2.close();
321
322 final byte[] actual = out1.toByteArray();
323 final byte[] expected = out2.toByteArray();
324
325 Assertions.assertEquals(expected.length, actual.length);
326 for (int i = 0; i < actual.length; i++) {
327 Assertions.assertEquals(expected[i], actual[i]);
328 }
329 Assertions.assertEquals(expected.length, multipart.getTotalLength());
330 }
331
332 }