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.httpclient;
16  
17  import static java.nio.charset.StandardCharsets.UTF_8;
18  
19  import java.io.File;
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.io.Writer;
23  import java.net.URL;
24  import java.util.HashMap;
25  import java.util.Locale;
26  import java.util.Map;
27  
28  import javax.servlet.Servlet;
29  import javax.servlet.ServletException;
30  import javax.servlet.http.HttpServlet;
31  import javax.servlet.http.HttpServletRequest;
32  import javax.servlet.http.HttpServletResponse;
33  
34  import org.apache.commons.fileupload.FileItem;
35  import org.apache.commons.fileupload.FileUploadBase;
36  import org.apache.commons.fileupload.disk.DiskFileItemFactory;
37  import org.apache.commons.fileupload.servlet.ServletFileUpload;
38  import org.apache.commons.io.IOUtils;
39  import org.apache.http.HttpResponse;
40  import org.apache.http.client.methods.HttpPost;
41  import org.apache.http.entity.ContentType;
42  import org.apache.http.entity.mime.HttpMultipartMode;
43  import org.apache.http.entity.mime.MultipartEntityBuilder;
44  import org.apache.http.entity.mime.content.FileBody;
45  import org.apache.http.impl.client.HttpClientBuilder;
46  import org.htmlunit.WebServerTestCase;
47  import org.htmlunit.html.HtmlFileInput;
48  import org.htmlunit.junit.BrowserRunner;
49  import org.htmlunit.util.MimeType;
50  import org.junit.Test;
51  import org.junit.runner.RunWith;
52  
53  /**
54   * Tests for {@link HtmlFileInput}.
55   *
56   * @author Marc Guillemot
57   * @author Ahmed Ashour
58   * @author Ronald Brill
59   * @author Frank Danek
60   */
61  @RunWith(BrowserRunner.class)
62  public class HttpClientTest extends WebServerTestCase {
63  
64      /**
65       * Servlet for '/upload'.
66       */
67      public static class UploadServlet extends HttpServlet {
68  
69          /**
70           * {@inheritDoc}
71           */
72          @Override
73          protected void doPost(final HttpServletRequest request, final HttpServletResponse response)
74              throws ServletException, IOException {
75              request.setCharacterEncoding(UTF_8.name());
76              response.setContentType(MimeType.TEXT_HTML);
77              final Writer writer = response.getWriter();
78              if (ServletFileUpload.isMultipartContent(request)) {
79                  try {
80                      final ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory());
81                      for (final FileItem item : upload.parseRequest(request)) {
82                          if ("myInput".equals(item.getFieldName())) {
83                              final String path = item.getName();
84                              for (final char ch : path.toCharArray()) {
85                                  writer.write(Integer.toHexString(ch).toUpperCase(Locale.ROOT) + " ");
86                              }
87                              writer.write("<br>");
88                              writer.write(item.getFieldName());
89                          }
90                      }
91                  }
92                  catch (final FileUploadBase.SizeLimitExceededException e) {
93                      writer.write("SizeLimitExceeded");
94                  }
95                  catch (final Exception e) {
96                      writer.write("error");
97                  }
98              }
99          }
100     }
101 
102     /**
103      * Test HttpClient for uploading a file with non-ASCII name, if it works it means HttpClient has fixed its bug.
104      *
105      * Test for http://issues.apache.org/jira/browse/HTTPCLIENT-293,
106      * which is related to http://sourceforge.net/p/htmlunit/bugs/535/
107      *
108      * @throws Exception if the test fails
109      */
110     @Test
111     public void uploadFileWithNonASCIIName_HttpClient() throws Exception {
112         final String filename = "\u6A94\u6848\uD30C\uC77C\u30D5\u30A1\u30A4\u30EB\u0645\u0644\u0641.txt";
113         final URL fileURL = getClass().getClassLoader().getResource(filename);
114         assertNotNull("Resource '" + filename + "' not found", fileURL);
115         final File file = new File(fileURL.toURI());
116         assertTrue("File '" + file.getAbsolutePath() + "' does not exist", file.exists());
117 
118         final Map<String, Class<? extends Servlet>> servlets = new HashMap<>();
119         servlets.put("/upload2", UploadServlet.class);
120 
121         startWebServer("./", null, servlets);
122         final HttpPost filePost = new HttpPost(URL_FIRST + "upload2");
123 
124         final MultipartEntityBuilder builder = MultipartEntityBuilder.create();
125         builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE).setCharset(UTF_8);
126         builder.addPart("myInput", new FileBody(file, ContentType.APPLICATION_OCTET_STREAM));
127 
128         filePost.setEntity(builder.build());
129 
130         final HttpClientBuilder clientBuilder = HttpClientBuilder.create();
131         final HttpResponse httpResponse = clientBuilder.build().execute(filePost);
132 
133         try (InputStream content = httpResponse.getEntity().getContent()) {
134             final String response = new String(IOUtils.toByteArray(content));
135             //this is the value with ASCII encoding
136             assertFalse("3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 2E 74 78 74 <br>myInput".equals(response));
137         }
138     }
139 }