View Javadoc
1   /*
2    * Copyright (c) 2002-2025 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.html;
16  
17  import static java.nio.charset.StandardCharsets.UTF_8;
18  
19  import java.io.BufferedReader;
20  import java.io.ByteArrayOutputStream;
21  import java.io.File;
22  import java.io.IOException;
23  import java.io.Writer;
24  import java.lang.reflect.InvocationTargetException;
25  import java.lang.reflect.Method;
26  import java.net.URI;
27  import java.net.URL;
28  import java.net.URLDecoder;
29  import java.text.Normalizer;
30  import java.text.Normalizer.Form;
31  import java.util.HashMap;
32  import java.util.Locale;
33  import java.util.Map;
34  
35  import javax.servlet.Servlet;
36  import javax.servlet.ServletException;
37  import javax.servlet.http.HttpServlet;
38  import javax.servlet.http.HttpServletRequest;
39  import javax.servlet.http.HttpServletResponse;
40  
41  import org.apache.commons.fileupload.FileItem;
42  import org.apache.commons.fileupload.FileUploadBase;
43  import org.apache.commons.fileupload.disk.DiskFileItemFactory;
44  import org.apache.commons.fileupload.servlet.ServletFileUpload;
45  import org.apache.http.HttpEntity;
46  import org.apache.http.client.methods.HttpPost;
47  import org.apache.http.impl.client.HttpClientBuilder;
48  import org.htmlunit.HttpWebConnection;
49  import org.htmlunit.MockWebConnection;
50  import org.htmlunit.WebClient;
51  import org.htmlunit.WebRequest;
52  import org.htmlunit.WebServerTestCase;
53  import org.htmlunit.junit.BrowserRunner;
54  import org.htmlunit.junit.annotation.Alerts;
55  import org.htmlunit.util.KeyDataPair;
56  import org.htmlunit.util.MimeType;
57  import org.junit.Test;
58  import org.junit.runner.RunWith;
59  
60  /**
61   * Tests for {@link HtmlFileInput}.
62   *
63   * @author Marc Guillemot
64   * @author Ahmed Ashour
65   * @author Ronald Brill
66   * @author Frank Danek
67   */
68  @RunWith(BrowserRunner.class)
69  public class HtmlFileInput2Test extends WebServerTestCase {
70  
71      /**
72       * @throws Exception if the test fails
73       */
74      @Test
75      public void fileInput() throws Exception {
76          final URL fileURL = getClass().getClassLoader().getResource("testfiles/tiny-png.img");
77          final File file = new File(fileURL.toURI());
78          assertTrue("File '" + file.getAbsolutePath() + "' does not exist", file.exists());
79  
80          testFileInput(file);
81  
82          String path = fileURL.getPath();
83          if (path.startsWith("file:")) {
84              path = path.substring("file:".length());
85          }
86          while (path.startsWith("/")) {
87              path = path.substring(1);
88          }
89          if (System.getProperty("os.name").toLowerCase(Locale.ROOT).contains("windows")) {
90              testFileInput(new File(URLDecoder.decode(path.replace('/', '\\'), UTF_8.name())));
91          }
92          testFileInput(new File("file:/" + path));
93          testFileInput(new File("file://" + path));
94          testFileInput(new File("file:///" + path));
95      }
96  
97      private void testFileInput(final File file) throws Exception {
98          final String firstContent = DOCTYPE_HTML
99              + "<html><head></head><body>\n"
100             + "<form enctype='multipart/form-data' action='" + URL_SECOND + "' method='POST'>\n"
101             + "  <input type='file' name='image'>\n"
102             + "  <input type='submit' id='clickMe'>\n"
103             + "</form>\n"
104             + "</body>\n"
105             + "</html>";
106         final String secondContent = DOCTYPE_HTML + "<html><head><title>second</title></head></html>";
107         final WebClient client = getWebClient();
108 
109         final MockWebConnection webConnection = new MockWebConnection();
110         webConnection.setResponse(URL_FIRST, firstContent);
111         webConnection.setResponse(URL_SECOND, secondContent);
112 
113         client.setWebConnection(webConnection);
114 
115         final HtmlPage firstPage = client.getPage(URL_FIRST);
116         final HtmlForm f = firstPage.getForms().get(0);
117         final HtmlFileInput fileInput = f.getInputByName("image");
118         fileInput.setFiles(file);
119         firstPage.getHtmlElementById("clickMe").click();
120         final KeyDataPair pair = (KeyDataPair) webConnection.getLastParameters().get(0);
121         assertNotNull(pair.getFile());
122         assertTrue(pair.getFile().length() != 0);
123     }
124 
125     /**
126      * Tests setValueAttribute method.
127      * @throws Exception if the test fails
128      */
129     @Test
130     public void setValueAttributeAndSetDataDummyFile() throws Exception {
131         final String firstContent = DOCTYPE_HTML
132             + "<html><head></head><body>\n"
133             + "<form enctype='multipart/form-data' action='" + URL_SECOND + "' method='POST'>\n"
134             + "  <input type='file' name='image'>\n"
135             + "  <input type='submit' id='mySubmit'>\n"
136             + "</form>\n"
137             + "</body>\n"
138             + "</html>";
139         final String secondContent = DOCTYPE_HTML + "<html><head><title>second</title></head></html>";
140         final WebClient client = getWebClient();
141 
142         final MockWebConnection webConnection = new MockWebConnection();
143         webConnection.setResponse(URL_FIRST, firstContent);
144         webConnection.setResponse(URL_SECOND, secondContent);
145 
146         client.setWebConnection(webConnection);
147 
148         final HtmlPage firstPage = client.getPage(URL_FIRST);
149         final HtmlForm f = firstPage.getForms().get(0);
150         final HtmlFileInput fileInput = f.getInputByName("image");
151         fileInput.setValueAttribute("dummy.txt");
152         fileInput.setContentType("text/csv");
153         fileInput.setData("My file data".getBytes());
154         firstPage.getHtmlElementById("mySubmit").click();
155         final KeyDataPair pair = (KeyDataPair) webConnection.getLastParameters().get(0);
156 
157         assertNull(pair.getData());
158 
159         final HttpEntity httpEntity = post(client, webConnection);
160 
161         try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
162             httpEntity.writeTo(out);
163 
164             assertFalse(out.toString().contains("dummy.txt"));
165         }
166     }
167 
168     /**
169      * Tests setData method.
170      * @throws Exception if the test fails
171      */
172     @Test
173     public void setValueAndSetDataDummyFile() throws Exception {
174         final String firstContent = DOCTYPE_HTML
175             + "<html><head></head><body>\n"
176             + "<form enctype='multipart/form-data' action='" + URL_SECOND + "' method='POST'>\n"
177             + "  <input type='file' name='image'>\n"
178             + "  <input type='submit' id='mySubmit'>\n"
179             + "</form>\n"
180             + "</body>\n"
181             + "</html>";
182         final String secondContent = DOCTYPE_HTML + "<html><head><title>second</title></head></html>";
183         final WebClient client = getWebClient();
184 
185         final MockWebConnection webConnection = new MockWebConnection();
186         webConnection.setResponse(URL_FIRST, firstContent);
187         webConnection.setResponse(URL_SECOND, secondContent);
188 
189         client.setWebConnection(webConnection);
190 
191         final HtmlPage firstPage = client.getPage(URL_FIRST);
192         final HtmlForm f = firstPage.getForms().get(0);
193         final HtmlFileInput fileInput = f.getInputByName("image");
194         fileInput.setValue("dummy.txt");
195         fileInput.setContentType("text/csv");
196         fileInput.setData("My file data".getBytes());
197         firstPage.getHtmlElementById("mySubmit").click();
198         final KeyDataPair pair = (KeyDataPair) webConnection.getLastParameters().get(0);
199 
200         assertNotNull(pair.getData());
201         assertTrue(pair.getData().length > 10);
202 
203         final HttpEntity httpEntity = post(client, webConnection);
204 
205         try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
206             httpEntity.writeTo(out);
207 
208             assertTrue(out.toString().contains("dummy.txt"));
209         }
210     }
211 
212     /**
213      * Tests setValueAttribute method.
214      * @throws Exception if the test fails
215      */
216     @Test
217     public void setValueAttributeAndSetDataRealFile() throws Exception {
218         final String firstContent = DOCTYPE_HTML
219             + "<html><head></head><body>\n"
220             + "<form enctype='multipart/form-data' action='" + URL_SECOND + "' method='POST'>\n"
221             + "  <input type='file' name='image'>\n"
222             + "  <input type='submit' id='mySubmit'>\n"
223             + "</form>\n"
224             + "</body>\n"
225             + "</html>";
226         final String secondContent = DOCTYPE_HTML + "<html><head><title>second</title></head></html>";
227         final WebClient client = getWebClient();
228 
229         final MockWebConnection webConnection = new MockWebConnection();
230         webConnection.setResponse(URL_FIRST, firstContent);
231         webConnection.setResponse(URL_SECOND, secondContent);
232 
233         client.setWebConnection(webConnection);
234 
235         final HtmlPage firstPage = client.getPage(URL_FIRST);
236         final HtmlForm f = firstPage.getForms().get(0);
237         final HtmlFileInput fileInput = f.getInputByName("image");
238         final String path = getClass().getClassLoader().getResource("testfiles/" + "tiny-png.img").toExternalForm();
239         fileInput.setValueAttribute(path);
240         fileInput.setData("My file data".getBytes());
241         firstPage.getHtmlElementById("mySubmit").click();
242         final KeyDataPair pair = (KeyDataPair) webConnection.getLastParameters().get(0);
243 
244         assertNull(pair.getData());
245 
246         final HttpEntity httpEntity = post(client, webConnection);
247 
248         try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
249             httpEntity.writeTo(out);
250 
251             assertFalse(out.toString()
252                     .contains("Content-Disposition: form-data; name=\"image\"; filename=\"tiny-png.img\""));
253         }
254     }
255 
256     /**
257      * Tests setData method.
258      * @throws Exception if the test fails
259      */
260     @Test
261     public void setValueAndSetDataRealFile() throws Exception {
262         final String firstContent = DOCTYPE_HTML
263             + "<html><head></head><body>\n"
264             + "<form enctype='multipart/form-data' action='" + URL_SECOND + "' method='POST'>\n"
265             + "  <input type='file' name='image'>\n"
266             + "  <input type='submit' id='mySubmit'>\n"
267             + "</form>\n"
268             + "</body>\n"
269             + "</html>";
270         final String secondContent = DOCTYPE_HTML + "<html><head><title>second</title></head></html>";
271         final WebClient client = getWebClient();
272 
273         final MockWebConnection webConnection = new MockWebConnection();
274         webConnection.setResponse(URL_FIRST, firstContent);
275         webConnection.setResponse(URL_SECOND, secondContent);
276 
277         client.setWebConnection(webConnection);
278 
279         final HtmlPage firstPage = client.getPage(URL_FIRST);
280         final HtmlForm f = firstPage.getForms().get(0);
281         final HtmlFileInput fileInput = f.getInputByName("image");
282         final String path = getClass().getClassLoader().getResource("testfiles/" + "tiny-png.img").toExternalForm();
283         fileInput.setValue(path);
284         fileInput.setData("My file data".getBytes());
285         firstPage.getHtmlElementById("mySubmit").click();
286         final KeyDataPair pair = (KeyDataPair) webConnection.getLastParameters().get(0);
287 
288         assertNotNull(pair.getData());
289         assertTrue(pair.getData().length > 10);
290 
291         final HttpEntity httpEntity = post(client, webConnection);
292 
293         try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
294             httpEntity.writeTo(out);
295 
296             assertTrue(out.toString()
297                     .contains("Content-Disposition: form-data; name=\"image\"; filename=\"tiny-png.img\""));
298         }
299     }
300 
301     /**
302      * Tests setData method.
303      * @throws Exception if the test fails
304      */
305     @Test
306     public void setDataOnly() throws Exception {
307         final String firstContent = DOCTYPE_HTML
308             + "<html><head></head><body>\n"
309             + "<form enctype='multipart/form-data' action='" + URL_SECOND + "' method='POST'>\n"
310             + "  <input type='file' name='image'>\n"
311             + "  <input type='submit' id='mySubmit'>\n"
312             + "</form>\n"
313             + "</body>\n"
314             + "</html>";
315         final String secondContent = DOCTYPE_HTML + "<html><head><title>second</title></head></html>";
316         final WebClient client = getWebClient();
317 
318         final MockWebConnection webConnection = new MockWebConnection();
319         webConnection.setResponse(URL_FIRST, firstContent);
320         webConnection.setResponse(URL_SECOND, secondContent);
321 
322         client.setWebConnection(webConnection);
323 
324         final HtmlPage firstPage = client.getPage(URL_FIRST);
325         final HtmlForm f = firstPage.getForms().get(0);
326         final HtmlFileInput fileInput = f.getInputByName("image");
327         fileInput.setData("My file data".getBytes());
328         firstPage.getHtmlElementById("mySubmit").click();
329         final KeyDataPair pair = (KeyDataPair) webConnection.getLastParameters().get(0);
330 
331         assertNull(pair.getData());
332 
333         final HttpEntity httpEntity = post(client, webConnection);
334 
335         try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
336             httpEntity.writeTo(out);
337 
338             assertTrue(out.toString()
339                     .contains("Content-Disposition: form-data; name=\"image\"; filename=\"\""));
340         }
341     }
342 
343     /**
344      * Helper that does some nasty magic.
345      */
346     private static HttpEntity post(final WebClient client,
347             final MockWebConnection webConnection)
348             throws NoSuchMethodException, IllegalAccessException,
349             InvocationTargetException {
350         final Method makeHttpMethod = HttpWebConnection.class.getDeclaredMethod("makeHttpMethod",
351                 WebRequest.class, HttpClientBuilder.class);
352         makeHttpMethod.setAccessible(true);
353 
354         final HttpWebConnection con = new HttpWebConnection(client);
355 
356         final Method getHttpClientBuilderMethod = HttpWebConnection.class.getDeclaredMethod("getHttpClientBuilder");
357         getHttpClientBuilderMethod.setAccessible(true);
358         final HttpClientBuilder builder = (HttpClientBuilder) getHttpClientBuilderMethod.invoke(con);
359 
360         final HttpPost httpPost = (HttpPost) makeHttpMethod.invoke(con, webConnection.getLastWebRequest(), builder);
361         final HttpEntity httpEntity = httpPost.getEntity();
362         return httpEntity;
363     }
364 
365     /**
366      * Verifies that content is provided for a not filled file input.
367      * @throws Exception if the test fails
368      */
369     @Test
370     public void emptyField() throws Exception {
371         final String firstContent = DOCTYPE_HTML
372             + "<html><head></head><body>\n"
373             + "<form enctype='multipart/form-data' action='" + URL_SECOND + "' method='POST'>\n"
374             + "  <input type='file' name='image' />\n"
375             + "  <input type='submit' id='clickMe'>\n"
376             + "</form>\n"
377             + "</body>\n"
378             + "</html>";
379         final String secondContent = DOCTYPE_HTML + "<html><head><title>second</title></head></html>";
380         final WebClient client = getWebClient();
381 
382         final MockWebConnection webConnection = new MockWebConnection();
383         webConnection.setResponse(URL_FIRST, firstContent);
384         webConnection.setResponse(URL_SECOND, secondContent);
385 
386         client.setWebConnection(webConnection);
387 
388         final HtmlPage firstPage = client.getPage(URL_FIRST);
389         firstPage.getHtmlElementById("clickMe").click();
390         final KeyDataPair pair = (KeyDataPair) webConnection.getLastParameters().get(0);
391         assertEquals("image", pair.getName());
392         assertNull(pair.getFile());
393     }
394 
395     /**
396      * @throws Exception if the test fails
397      */
398     @Test
399     public void contentType() throws Exception {
400         final String firstContent = DOCTYPE_HTML
401             + "<html><head></head><body>\n"
402             + "<form enctype='multipart/form-data' action='" + URL_SECOND + "' method='POST'>\n"
403             + "  <input type='file' name='image' />\n"
404             + "  <input type='submit' name='mysubmit'/>\n"
405             + "</form>\n"
406             + "</body>\n"
407             + "</html>";
408         final String secondContent = DOCTYPE_HTML + "<html><head><title>second</title></head></html>";
409         final WebClient client = getWebClient();
410 
411         final MockWebConnection webConnection = new MockWebConnection();
412         webConnection.setResponse(URL_FIRST, firstContent);
413         webConnection.setResponse(URL_SECOND, secondContent);
414 
415         client.setWebConnection(webConnection);
416 
417         final HtmlPage firstPage = client.getPage(URL_FIRST);
418         final HtmlForm f = firstPage.getForms().get(0);
419         final HtmlFileInput fileInput = f.getInputByName("image");
420 
421         final URL fileURL = getClass().getClassLoader().getResource("testfiles/empty.png");
422         final File file = new File(fileURL.toURI());
423         assertTrue("File '" + file.getAbsolutePath() + "' does not exist", file.exists());
424 
425         fileInput.setFiles(file);
426         f.getInputByName("mysubmit").click();
427 
428         assertEquals(2, webConnection.getLastParameters().size());
429         KeyDataPair pair = (KeyDataPair) webConnection.getLastParameters().get(0);
430         if ("mysubmit".equals(pair.getName())) {
431             pair = (KeyDataPair) webConnection.getLastParameters().get(1);
432         }
433         assertNotNull(pair.getFile());
434         assertFalse("Content type: " + pair.getMimeType(), "text/webtest".equals(pair.getMimeType()));
435 
436         fileInput.setContentType("text/webtest");
437         f.getInputByName("mysubmit").click();
438 
439         assertEquals(2, webConnection.getLastParameters().size());
440         KeyDataPair pair2 = (KeyDataPair) webConnection.getLastParameters().get(0);
441         if ("mysubmit".equals(pair2.getName())) {
442             pair2 = (KeyDataPair) webConnection.getLastParameters().get(1);
443         }
444         assertNotNull(pair2.getFile());
445         assertEquals("text/webtest", pair2.getMimeType());
446     }
447 
448     /**
449      * Test uploading a file with non-ASCII name.
450      *
451      * Test for http://sourceforge.net/p/htmlunit/bugs/535/
452      *
453      * @throws Exception if the test fails
454      */
455     @Test
456     public void uploadFileWithNonASCIIName() throws Exception {
457         final Map<String, Class<? extends Servlet>> servlets = new HashMap<>();
458         servlets.put("/upload1", Upload1Servlet.class);
459         servlets.put("/upload2", Upload2Servlet.class);
460         startWebServer("./", null, servlets);
461 
462         final String filename = "\u6A94\u6848\uD30C\uC77C\u30D5\u30A1\u30A4\u30EB\u0645\u0644\u0641.txt";
463         final URL fileURL = getClass().getClassLoader().getResource(filename);
464         final File file = new File(fileURL.toURI());
465         assertTrue("File '" + file.getAbsolutePath() + "' does not exist", file.exists());
466 
467         final WebClient client = getWebClient();
468         final HtmlPage firstPage = client.getPage(URL_FIRST + "upload1");
469 
470         final HtmlForm form = firstPage.getForms().get(0);
471         final HtmlFileInput fileInput = form.getInputByName("myInput");
472         fileInput.setFiles(file);
473 
474         final HtmlSubmitInput submitInput = form.getInputByValue("Upload");
475         final HtmlPage secondPage = submitInput.click();
476 
477         final String response = secondPage.getWebResponse().getContentAsString();
478 
479         //this is the value with UTF-8 encoding
480         final String expectedResponse = "6A94 6848 D30C C77C 30D5 30A1 30A4 30EB 645 644 641 2E 74 78 74 <br>myInput";
481 
482         assertTrue("Invalid Response: " + response, response.endsWith(expectedResponse));
483     }
484 
485     /**
486      * Servlet for '/upload1'.
487      */
488     public static class Upload1Servlet extends HttpServlet {
489 
490         /**
491          * {@inheritDoc}
492          */
493         @Override
494         protected void doGet(final HttpServletRequest request, final HttpServletResponse response)
495             throws ServletException, IOException {
496             response.setCharacterEncoding(UTF_8.name());
497             response.setContentType(MimeType.TEXT_HTML);
498             response.getWriter().write("<html>\n"
499                 + "<body><form action='upload2' method='post' enctype='multipart/form-data'>\n"
500                 + "Name: <input name='myInput' type='file'><br>\n"
501                 + "Name 2 (should stay empty): <input name='myInput2' type='file'><br>\n"
502                 + "<input type='submit' value='Upload' id='mySubmit'>\n"
503                 + "</form></body></html>\n");
504         }
505     }
506 
507     /**
508      * Servlet for '/upload2'.
509      */
510     public static class Upload2Servlet extends HttpServlet {
511 
512         /**
513          * {@inheritDoc}
514          */
515         @Override
516         protected void doPost(final HttpServletRequest request, final HttpServletResponse response)
517             throws ServletException, IOException {
518             request.setCharacterEncoding(UTF_8.name());
519             response.setContentType(MimeType.TEXT_HTML);
520             final Writer writer = response.getWriter();
521             if (ServletFileUpload.isMultipartContent(request)) {
522                 try {
523                     final ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory());
524                     for (final FileItem item : upload.parseRequest(request)) {
525                         if ("myInput".equals(item.getFieldName())) {
526                             final String path = item.getName();
527                             for (final char ch : path.toCharArray()) {
528                                 writer.write(Integer.toHexString(ch).toUpperCase(Locale.ROOT) + " ");
529                             }
530                             writer.write("<br>");
531                             writer.write(item.getFieldName());
532                         }
533                     }
534                 }
535                 catch (final FileUploadBase.SizeLimitExceededException e) {
536                     writer.write("SizeLimitExceeded");
537                 }
538                 catch (final Exception e) {
539                     writer.write("error");
540                 }
541             }
542         }
543     }
544 
545     /**
546      * @throws Exception if the test fails
547      */
548     @Test
549     public void mutiple() throws Exception {
550         final Map<String, Class<? extends Servlet>> servlets = new HashMap<>();
551         servlets.put("/upload1", Multiple1Servlet.class);
552         servlets.put("/upload2", PrintRequestServlet.class);
553         startWebServer("./", null, servlets);
554 
555         final String filename1 = "HtmlFileInputTest_one.txt";
556         final String path1 = getClass().getResource(filename1).toExternalForm();
557         final File file1 = new File(new URI(path1));
558         assertTrue(file1.exists());
559 
560         final String filename2 = "HtmlFileInputTest_two.txt";
561         final String path2 = getClass().getResource(filename2).toExternalForm();
562         final File file2 = new File(new URI(path2));
563         assertTrue(file2.exists());
564 
565         final WebClient client = getWebClient();
566         final HtmlPage firstPage = client.getPage(URL_FIRST + "upload1");
567 
568         final HtmlForm form = firstPage.getForms().get(0);
569         final HtmlFileInput fileInput = form.getInputByName("myInput");
570         fileInput.setFiles(file1, file2);
571 
572         final HtmlSubmitInput submitInput = form.getInputByValue("Upload");
573         final HtmlPage secondPage = submitInput.click();
574 
575         final String response = secondPage.getWebResponse().getContentAsString();
576 
577         assertTrue(response.contains("HtmlFileInputTest_one.txt"));
578         assertTrue(response.contains("First"));
579         assertTrue(response.contains("HtmlFileInputTest_two.txt"));
580         assertTrue(response.contains("Second"));
581     }
582 
583 
584     /**
585      * @throws Exception if the test fails
586      */
587     @Test
588     public void webkitdirectory() throws Exception {
589         final Map<String, Class<? extends Servlet>> servlets = new HashMap<>();
590         servlets.put("/upload1", MultipleWebkitdirectoryServlet.class);
591         servlets.put("/upload2", PrintRequestServlet.class);
592         startWebServer("./", null, servlets);
593 
594         final File dir = new File("src/test/resources/pjl-comp-filter");
595         assertTrue(dir.exists());
596         assertTrue(dir.isDirectory());
597 
598         final WebClient client = getWebClient();
599         final HtmlPage firstPage = client.getPage(URL_FIRST + "upload1");
600 
601         final HtmlForm form = firstPage.getForms().get(0);
602         final HtmlFileInput fileInput = form.getInputByName("myInput");
603         fileInput.setDirectory(dir);
604 
605         final HtmlSubmitInput submitInput = form.getInputByValue("Upload");
606         final HtmlPage secondPage = submitInput.click();
607 
608         final String response = secondPage.getWebResponse().getContentAsString();
609 
610         assertTrue(response.contains("index.html"));
611         assertTrue(response.contains("web.xml"));
612         assertTrue(response.contains("pjl-comp-filter-1.8.1.jar"));
613     }
614 
615     /**
616      * Servlet for '/upload1'.
617      */
618     public static class Multiple1Servlet extends HttpServlet {
619 
620         /**
621          * {@inheritDoc}
622          */
623         @Override
624         protected void doGet(final HttpServletRequest request, final HttpServletResponse response)
625             throws ServletException, IOException {
626             response.setCharacterEncoding(UTF_8.name());
627             response.setContentType(MimeType.TEXT_HTML);
628             response.getWriter().write("<html>\n"
629                 + "<body><form action='upload2' method='post' enctype='multipart/form-data'>\n"
630                 + "Name: <input name='myInput' type='file' multiple><br>\n"
631                 + "<input type='submit' value='Upload' id='mySubmit'>\n"
632                 + "</form></body></html>\n");
633         }
634     }
635 
636     /**
637      * Servlet for '/upload1'.
638      */
639     public static class MultipleWebkitdirectoryServlet extends HttpServlet {
640 
641         /**
642          * {@inheritDoc}
643          */
644         @Override
645         protected void doGet(final HttpServletRequest request, final HttpServletResponse response)
646             throws ServletException, IOException {
647             response.setCharacterEncoding(UTF_8.name());
648             response.setContentType(MimeType.TEXT_HTML);
649             response.getWriter().write("<html>\n"
650                 + "<body><form action='upload2' method='post' enctype='multipart/form-data'>\n"
651                 + "Name: <input name='myInput' type='file' multiple webkitdirectory><br>\n"
652                 + "<input type='submit' value='Upload' id='mySubmit'>\n"
653                 + "</form></body></html>\n");
654         }
655     }
656 
657     /**
658      * Prints request content to the response.
659      */
660     public static class PrintRequestServlet extends HttpServlet {
661 
662         /**
663          * {@inheritDoc}
664          */
665         @Override
666         protected void doPost(final HttpServletRequest request, final HttpServletResponse response)
667             throws ServletException, IOException {
668             request.setCharacterEncoding(UTF_8.name());
669             response.setContentType(MimeType.TEXT_HTML);
670             final Writer writer = response.getWriter();
671             final BufferedReader reader = request.getReader();
672             String line;
673             while ((line = reader.readLine()) != null) {
674                 final String normalized = Normalizer.normalize(line, Form.NFD);
675                 writer.write(normalized);
676             }
677         }
678     }
679 
680     /**
681      * @throws Exception if an error occurs
682      */
683     @Test
684     @Alerts("foo, change")
685     public void onchangeMultiple() throws Exception {
686         final String html = DOCTYPE_HTML
687               + "<html>\n"
688               + "<head>\n"
689               + "</head>\n"
690               + "<body>\n"
691               + "  <input type='file' id='f' value='Hello world' multiple"
692               + "      onChange='alert(\"foo\");alert(event.type);'>\n"
693               + "  <button id='clickMe' onclick='test()'>Click Me</button>\n"
694               + "</body></html>";
695 
696         final File pom = new File("pom.xml");
697         final File license = new File("LICENSE.txt");
698 
699         final HtmlPage page = loadPage(html);
700         ((HtmlFileInput) page.getElementById("f")).setFiles(pom, license);
701         Thread.sleep(100);
702         assertEquals(getExpectedAlerts(), getCollectedAlerts(page));
703     }
704 
705     /**
706      * @throws Exception if an error occurs
707      */
708     @Test
709     public void clear() throws Exception {
710         final String html = DOCTYPE_HTML
711                 + "<html><head>\n"
712                 + "  <script>\n"
713                 + "    function test() {\n"
714                 + "      var f =  document.createElement('input');\n"
715                 + "      f.type='file';\n"
716                 + "      f.id='fileId';\n"
717                 + "      document.body.appendChild(f);"
718 
719                 + "      f.value='';\n"
720                 + "    }\n"
721                 + "  </script>\n"
722                 + "</head>\n"
723                 + "<body onload='test()'>\n"
724                 + "</body></html>";
725 
726         final HtmlPage page = loadPage(html);
727         final HtmlFileInput file = page.<HtmlFileInput>getHtmlElementById("fileId");
728         assertEquals(0, file.getFiles().length);
729     }
730 
731     /**
732      * @throws Exception if an error occurs
733      */
734     @Test
735     public void clearFromJava() throws Exception {
736         final String html = DOCTYPE_HTML
737                 + "<html><head>\n"
738                 + "  <script>\n"
739                 + "    function test() {\n"
740                 + "      var f =  document.createElement('input');\n"
741                 + "      f.type='file';\n"
742                 + "      f.id='fileId';\n"
743                 + "      document.body.appendChild(f);"
744                 + "    }\n"
745                 + "  </script>\n"
746                 + "</head>\n"
747                 + "<body onload='test()'>\n"
748                 + "</body></html>";
749 
750         final HtmlPage page = loadPage(html);
751         final HtmlFileInput file = page.<HtmlFileInput>getHtmlElementById("fileId");
752         file.setValue("");
753         assertEquals(0, file.getFiles().length);
754     }
755 }