View Javadoc

1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  
28  package org.apache.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.util.Arrays;
37  
38  import org.apache.http.Consts;
39  import org.apache.http.entity.ContentType;
40  import org.apache.http.entity.mime.content.FileBody;
41  import org.apache.http.entity.mime.content.InputStreamBody;
42  import org.apache.http.entity.mime.content.StringBody;
43  import org.junit.After;
44  import org.junit.Assert;
45  import org.junit.Test;
46  
47  public class TestMultipartForm {
48  
49      private File tmpfile;
50  
51      @After
52      public void cleanup() {
53          if (tmpfile != null) {
54              tmpfile.delete();
55          }
56      }
57  
58      @Test
59      public void testMultipartFormStringParts() throws Exception {
60          final FormBodyPart p1 = new FormBodyPart(
61                  "field1",
62                  new StringBody("this stuff", ContentType.DEFAULT_TEXT));
63          final FormBodyPart p2 = new FormBodyPart(
64                  "field2",
65                  new StringBody("that stuff", ContentType.create(
66                          ContentType.TEXT_PLAIN.getMimeType(), Consts.UTF_8)));
67          final FormBodyPart p3 = new FormBodyPart(
68                  "field3",
69                  new StringBody("all kind of stuff", ContentType.DEFAULT_TEXT));
70          final HttpStrictMultipart multipart = new HttpStrictMultipart("form-data", null, "foo",
71                  Arrays.asList(p1, p2, p3));
72  
73          final ByteArrayOutputStream out = new ByteArrayOutputStream();
74          multipart.writeTo(out);
75          out.close();
76  
77          final String expected =
78              "--foo\r\n" +
79              "Content-Disposition: form-data; name=\"field1\"\r\n" +
80              "Content-Type: text/plain; charset=ISO-8859-1\r\n" +
81              "Content-Transfer-Encoding: 8bit\r\n" +
82              "\r\n" +
83              "this stuff\r\n" +
84              "--foo\r\n" +
85              "Content-Disposition: form-data; name=\"field2\"\r\n" +
86              "Content-Type: text/plain; charset=UTF-8\r\n" +
87              "Content-Transfer-Encoding: 8bit\r\n" +
88              "\r\n" +
89              "that stuff\r\n" +
90              "--foo\r\n" +
91              "Content-Disposition: form-data; name=\"field3\"\r\n" +
92              "Content-Type: text/plain; charset=ISO-8859-1\r\n" +
93              "Content-Transfer-Encoding: 8bit\r\n" +
94              "\r\n" +
95              "all kind of stuff\r\n" +
96              "--foo--\r\n";
97          final String s = out.toString("US-ASCII");
98          Assert.assertEquals(expected, s);
99          Assert.assertEquals(s.length(), multipart.getTotalLength());
100     }
101 
102     @Test
103     public void testMultipartFormCustomContentType() throws Exception {
104         final FormBodyPart p1 = new FormBodyPart(
105                 "field1",
106                 new StringBody("this stuff", ContentType.DEFAULT_TEXT));
107         final FormBodyPart p2 = new FormBodyPart(
108                 "field2",
109                 new StringBody("that stuff", ContentType.parse("stuff/plain; param=value")));
110         final HttpStrictMultipart multipart = new HttpStrictMultipart("form-data", null, "foo",
111                 Arrays.asList(p1, p2));
112 
113         final ByteArrayOutputStream out = new ByteArrayOutputStream();
114         multipart.writeTo(out);
115         out.close();
116 
117         final String expected =
118                 "--foo\r\n" +
119                         "Content-Disposition: form-data; name=\"field1\"\r\n" +
120                         "Content-Type: text/plain; charset=ISO-8859-1\r\n" +
121                         "Content-Transfer-Encoding: 8bit\r\n" +
122                         "\r\n" +
123                         "this stuff\r\n" +
124                         "--foo\r\n" +
125                         "Content-Disposition: form-data; name=\"field2\"\r\n" +
126                         "Content-Type: stuff/plain; param=value\r\n" +
127                         "Content-Transfer-Encoding: 8bit\r\n" +
128                         "\r\n" +
129                         "that stuff\r\n" +
130                         "--foo--\r\n";
131         final String s = out.toString("US-ASCII");
132         Assert.assertEquals(expected, s);
133         Assert.assertEquals(s.length(), multipart.getTotalLength());
134     }
135 
136     @Test
137     public void testMultipartFormBinaryParts() throws Exception {
138         tmpfile = File.createTempFile("tmp", ".bin");
139         final Writer writer = new FileWriter(tmpfile);
140         try {
141             writer.append("some random whatever");
142         } finally {
143             writer.close();
144         }
145 
146         final FormBodyPart p1 = new FormBodyPart(
147                 "field1",
148                 new FileBody(tmpfile));
149         final FormBodyPart p2 = new FormBodyPart(
150                 "field2",
151                 new InputStreamBody(new FileInputStream(tmpfile), "file.tmp"));
152         final HttpStrictMultipart multipart = new HttpStrictMultipart("form-data", null, "foo",
153                 Arrays.asList(p1, p2));
154 
155         final ByteArrayOutputStream out = new ByteArrayOutputStream();
156         multipart.writeTo(out);
157         out.close();
158 
159         final String expected =
160             "--foo\r\n" +
161             "Content-Disposition: form-data; name=\"field1\"; " +
162                 "filename=\"" + tmpfile.getName() + "\"\r\n" +
163             "Content-Type: application/octet-stream\r\n" +
164             "Content-Transfer-Encoding: binary\r\n" +
165             "\r\n" +
166             "some random whatever\r\n" +
167             "--foo\r\n" +
168             "Content-Disposition: form-data; name=\"field2\"; " +
169                 "filename=\"file.tmp\"\r\n" +
170             "Content-Type: application/octet-stream\r\n" +
171             "Content-Transfer-Encoding: binary\r\n" +
172             "\r\n" +
173             "some random whatever\r\n" +
174             "--foo--\r\n";
175         final String s = out.toString("US-ASCII");
176         Assert.assertEquals(expected, s);
177         Assert.assertEquals(-1, multipart.getTotalLength());
178     }
179 
180     @Test
181     public void testMultipartFormStrict() throws Exception {
182         tmpfile = File.createTempFile("tmp", ".bin");
183         final Writer writer = new FileWriter(tmpfile);
184         try {
185             writer.append("some random whatever");
186         } finally {
187             writer.close();
188         }
189 
190         final FormBodyPart p1 = new FormBodyPart(
191                 "field1",
192                 new FileBody(tmpfile));
193         final FormBodyPart p2 = new FormBodyPart(
194                 "field2",
195                 new FileBody(tmpfile, ContentType.create("text/plain", "ANSI_X3.4-1968"), "test-file"));
196         final FormBodyPart p3 = new FormBodyPart(
197                 "field3",
198                 new InputStreamBody(new FileInputStream(tmpfile), "file.tmp"));
199         final HttpStrictMultipart multipart = new HttpStrictMultipart("form-data", null, "foo",
200                 Arrays.asList(p1, p2, p3));
201 
202         final ByteArrayOutputStream out = new ByteArrayOutputStream();
203         multipart.writeTo(out);
204         out.close();
205 
206         final String expected =
207             "--foo\r\n" +
208             "Content-Disposition: form-data; name=\"field1\"; " +
209                 "filename=\"" + tmpfile.getName() + "\"\r\n" +
210             "Content-Type: application/octet-stream\r\n" +
211             "Content-Transfer-Encoding: binary\r\n" +
212             "\r\n" +
213             "some random whatever\r\n" +
214             "--foo\r\n" +
215             "Content-Disposition: form-data; name=\"field2\"; " +
216                 "filename=\"test-file\"\r\n" +
217             "Content-Type: text/plain; charset=US-ASCII\r\n" +
218             "Content-Transfer-Encoding: binary\r\n" +
219             "\r\n" +
220             "some random whatever\r\n" +
221             "--foo\r\n" +
222             "Content-Disposition: form-data; name=\"field3\"; " +
223                 "filename=\"file.tmp\"\r\n" +
224             "Content-Type: application/octet-stream\r\n" +
225             "Content-Transfer-Encoding: binary\r\n" +
226             "\r\n" +
227             "some random whatever\r\n" +
228             "--foo--\r\n";
229         final String s = out.toString("US-ASCII");
230         Assert.assertEquals(expected, s);
231         Assert.assertEquals(-1, multipart.getTotalLength());
232     }
233 
234     @Test
235     public void testMultipartFormRFC6532() throws Exception {
236         tmpfile = File.createTempFile("tmp", ".bin");
237         final Writer writer = new FileWriter(tmpfile);
238         try {
239             writer.append("some random whatever");
240         } finally {
241             writer.close();
242         }
243 
244         final FormBodyPart p1 = new FormBodyPart(
245                 "field1\u0414",
246                 new FileBody(tmpfile));
247         final FormBodyPart p2 = new FormBodyPart(
248                 "field2",
249                 new FileBody(tmpfile, ContentType.create("text/plain", "ANSI_X3.4-1968"), "test-file"));
250         final FormBodyPart p3 = new FormBodyPart(
251                 "field3",
252                 new InputStreamBody(new FileInputStream(tmpfile), "file.tmp"));
253         final HttpRFC6532Multipart multipart = new HttpRFC6532Multipart("form-data", null, "foo",
254                 Arrays.asList(p1, p2, p3));
255 
256         final ByteArrayOutputStream out = new ByteArrayOutputStream();
257         multipart.writeTo(out);
258         out.close();
259 
260         final String expected =
261             "--foo\r\n" +
262             "Content-Disposition: form-data; name=\"field1\u0414\"; " +
263                 "filename=\"" + tmpfile.getName() + "\"\r\n" +
264             "Content-Type: application/octet-stream\r\n" +
265             "Content-Transfer-Encoding: binary\r\n" +
266             "\r\n" +
267             "some random whatever\r\n" +
268             "--foo\r\n" +
269             "Content-Disposition: form-data; name=\"field2\"; " +
270                 "filename=\"test-file\"\r\n" +
271             "Content-Type: text/plain; charset=US-ASCII\r\n" +
272             "Content-Transfer-Encoding: binary\r\n" +
273             "\r\n" +
274             "some random whatever\r\n" +
275             "--foo\r\n" +
276             "Content-Disposition: form-data; name=\"field3\"; " +
277                 "filename=\"file.tmp\"\r\n" +
278             "Content-Type: application/octet-stream\r\n" +
279             "Content-Transfer-Encoding: binary\r\n" +
280             "\r\n" +
281             "some random whatever\r\n" +
282             "--foo--\r\n";
283         final String s = out.toString("UTF-8");
284         Assert.assertEquals(expected, s);
285         Assert.assertEquals(-1, multipart.getTotalLength());
286     }
287 
288     private static final int SWISS_GERMAN_HELLO [] = {
289         0x47, 0x72, 0xFC, 0x65, 0x7A, 0x69, 0x5F, 0x7A, 0xE4, 0x6D, 0xE4
290     };
291 
292     private static final int RUSSIAN_HELLO [] = {
293         0x412, 0x441, 0x435, 0x43C, 0x5F, 0x43F, 0x440, 0x438,
294         0x432, 0x435, 0x442
295     };
296 
297     private static String constructString(final int [] unicodeChars) {
298         final StringBuilder buffer = new StringBuilder();
299         if (unicodeChars != null) {
300             for (final int unicodeChar : unicodeChars) {
301                 buffer.append((char)unicodeChar);
302             }
303         }
304         return buffer.toString();
305     }
306 
307     @Test
308     public void testMultipartFormBrowserCompatibleNonASCIIHeaders() throws Exception {
309         final String s1 = constructString(SWISS_GERMAN_HELLO);
310         final String s2 = constructString(RUSSIAN_HELLO);
311 
312         tmpfile = File.createTempFile("tmp", ".bin");
313         final Writer writer = new FileWriter(tmpfile);
314         try {
315             writer.append("some random whatever");
316         } finally {
317             writer.close();
318         }
319 
320         final FormBodyPart p1 = new FormBodyPart(
321                 "field1",
322                 new InputStreamBody(new FileInputStream(tmpfile), s1 + ".tmp"));
323         final FormBodyPart p2 = new FormBodyPart(
324                 "field2",
325                 new InputStreamBody(new FileInputStream(tmpfile), s2 + ".tmp"));
326         final HttpBrowserCompatibleMultipart multipart = new HttpBrowserCompatibleMultipart(
327                 "form-data", Consts.UTF_8, "foo",
328                 Arrays.asList(p1, p2));
329 
330         final ByteArrayOutputStream out = new ByteArrayOutputStream();
331         multipart.writeTo(out);
332         out.close();
333 
334         final String expected =
335             "--foo\r\n" +
336             "Content-Disposition: form-data; name=\"field1\"; " +
337                 "filename=\"" + s1 + ".tmp\"\r\n" +
338             "Content-Type: application/octet-stream\r\n" +
339             "\r\n" +
340             "some random whatever\r\n" +
341             "--foo\r\n" +
342             "Content-Disposition: form-data; name=\"field2\"; " +
343                 "filename=\"" + s2 + ".tmp\"\r\n" +
344             "Content-Type: application/octet-stream\r\n" +
345             "\r\n" +
346             "some random whatever\r\n" +
347             "--foo--\r\n";
348         final String s = out.toString("UTF-8");
349         Assert.assertEquals(expected, s);
350         Assert.assertEquals(-1, multipart.getTotalLength());
351     }
352 
353     @Test
354     public void testMultipartFormStringPartsMultiCharsets() throws Exception {
355         final String s1 = constructString(SWISS_GERMAN_HELLO);
356         final String s2 = constructString(RUSSIAN_HELLO);
357 
358         final FormBodyPart p1 = new FormBodyPart(
359                 "field1",
360                 new StringBody(s1, ContentType.create("text/plain", Charset.forName("ISO-8859-1"))));
361         final FormBodyPart p2 = new FormBodyPart(
362                 "field2",
363                 new StringBody(s2, ContentType.create("text/plain", Charset.forName("KOI8-R"))));
364         final HttpStrictMultipart multipart = new HttpStrictMultipart("form-data", null, "foo",
365                 Arrays.asList(p1, p2));
366 
367         final ByteArrayOutputStream out1 = new ByteArrayOutputStream();
368         multipart.writeTo(out1);
369         out1.close();
370 
371         final ByteArrayOutputStream out2 = new ByteArrayOutputStream();
372 
373         out2.write((
374             "--foo\r\n" +
375             "Content-Disposition: form-data; name=\"field1\"\r\n" +
376             "Content-Type: text/plain; charset=ISO-8859-1\r\n" +
377             "Content-Transfer-Encoding: 8bit\r\n" +
378             "\r\n").getBytes("US-ASCII"));
379         out2.write(s1.getBytes("ISO-8859-1"));
380         out2.write(("\r\n" +
381             "--foo\r\n" +
382             "Content-Disposition: form-data; name=\"field2\"\r\n" +
383             "Content-Type: text/plain; charset=KOI8-R\r\n" +
384             "Content-Transfer-Encoding: 8bit\r\n" +
385             "\r\n").getBytes("US-ASCII"));
386         out2.write(s2.getBytes("KOI8-R"));
387         out2.write(("\r\n" +
388             "--foo--\r\n").getBytes("US-ASCII"));
389         out2.close();
390 
391         final byte[] actual = out1.toByteArray();
392         final byte[] expected = out2.toByteArray();
393 
394         Assert.assertEquals(expected.length, actual.length);
395         for (int i = 0; i < actual.length; i++) {
396             Assert.assertEquals(expected[i], actual[i]);
397         }
398         Assert.assertEquals(expected.length, multipart.getTotalLength());
399     }
400 
401 }