Java tutorial
/* * Copyright (c) 2002-2016 Gargoyle Software Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.gargoylesoftware.htmlunit.html; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.Writer; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URI; import java.net.URL; import java.net.URLDecoder; import java.nio.charset.Charset; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.servlet.Servlet; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileUploadBase; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.commons.io.IOUtils; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.ContentType; import org.apache.http.entity.mime.HttpMultipartMode; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.entity.mime.content.FileBody; import org.apache.http.impl.client.HttpClientBuilder; import org.junit.Test; import org.junit.runner.RunWith; import com.gargoylesoftware.htmlunit.BrowserRunner; import com.gargoylesoftware.htmlunit.HttpWebConnection; import com.gargoylesoftware.htmlunit.MockWebConnection; import com.gargoylesoftware.htmlunit.WebClient; import com.gargoylesoftware.htmlunit.WebRequest; import com.gargoylesoftware.htmlunit.WebServerTestCase; import com.gargoylesoftware.htmlunit.util.KeyDataPair; /** * Tests for {@link HtmlFileInput}. * * @author Marc Guillemot * @author Ahmed Ashour * @author Ronald Brill */ @RunWith(BrowserRunner.class) public class HtmlFileInputTest extends WebServerTestCase { /** * @throws Exception if the test fails */ @Test public void testFileInput() throws Exception { String path = getClass().getClassLoader().getResource("testfiles/" + "tiny-png.img").toExternalForm(); testFileInput(path); final File file = new File(new URI(path)); testFileInput(file.getCanonicalPath()); if (path.startsWith("file:")) { path = path.substring("file:".length()); } while (path.startsWith("/")) { path = path.substring(1); } if (System.getProperty("os.name").toLowerCase(Locale.ROOT).contains("windows")) { testFileInput(URLDecoder.decode(path.replace('/', '\\'), "UTF-8")); } testFileInput("file:/" + path); testFileInput("file://" + path); testFileInput("file:///" + path); } private void testFileInput(final String fileURL) throws Exception { final String firstContent = "<html><head></head><body>\n" + "<form enctype='multipart/form-data' action='" + URL_SECOND + "' method='POST'>\n" + " <input type='file' name='image'>\n" + " <input type='submit' id='clickMe'>\n" + "</form>\n" + "</body>\n" + "</html>"; final String secondContent = "<html><head><title>second</title></head></html>"; final WebClient client = getWebClient(); final MockWebConnection webConnection = new MockWebConnection(); webConnection.setResponse(URL_FIRST, firstContent); webConnection.setResponse(URL_SECOND, secondContent); client.setWebConnection(webConnection); final HtmlPage firstPage = client.getPage(URL_FIRST); final HtmlForm f = firstPage.getForms().get(0); final HtmlFileInput fileInput = f.getInputByName("image"); fileInput.setValueAttribute(fileURL); firstPage.getHtmlElementById("clickMe").click(); final KeyDataPair pair = (KeyDataPair) webConnection.getLastParameters().get(0); assertNotNull(pair.getFile()); assertTrue(pair.getFile().length() != 0); } /** * Tests setData method. * @throws Exception if the test fails */ @Test public void setValueAttributeAndSetDataDummyFile() throws Exception { final String firstContent = "<html><head></head><body>\n" + "<form enctype='multipart/form-data' action='" + URL_SECOND + "' method='POST'>\n" + " <input type='file' name='image'>\n" + " <input type='submit' id='mySubmit'>\n" + "</form>\n" + "</body>\n" + "</html>"; final String secondContent = "<html><head><title>second</title></head></html>"; final WebClient client = getWebClient(); final MockWebConnection webConnection = new MockWebConnection(); webConnection.setResponse(URL_FIRST, firstContent); webConnection.setResponse(URL_SECOND, secondContent); client.setWebConnection(webConnection); final HtmlPage firstPage = client.getPage(URL_FIRST); final HtmlForm f = firstPage.getForms().get(0); final HtmlFileInput fileInput = f.getInputByName("image"); fileInput.setValueAttribute("dummy.txt"); fileInput.setContentType("text/csv"); fileInput.setData("My file data".getBytes()); firstPage.getHtmlElementById("mySubmit").click(); final KeyDataPair pair = (KeyDataPair) webConnection.getLastParameters().get(0); assertNotNull(pair.getData()); assertTrue(pair.getData().length > 10); final HttpEntity httpEntity = post(client, webConnection); final ByteArrayOutputStream out = new ByteArrayOutputStream(); httpEntity.writeTo(out); out.close(); assertTrue( out.toString().contains("Content-Disposition: form-data; name=\"image\"; filename=\"dummy.txt\"")); } /** * Tests setData method. * @throws Exception if the test fails */ @Test public void setValueAttributeAndSetDataRealFile() throws Exception { final String firstContent = "<html><head></head><body>\n" + "<form enctype='multipart/form-data' action='" + URL_SECOND + "' method='POST'>\n" + " <input type='file' name='image'>\n" + " <input type='submit' id='mySubmit'>\n" + "</form>\n" + "</body>\n" + "</html>"; final String secondContent = "<html><head><title>second</title></head></html>"; final WebClient client = getWebClient(); final MockWebConnection webConnection = new MockWebConnection(); webConnection.setResponse(URL_FIRST, firstContent); webConnection.setResponse(URL_SECOND, secondContent); client.setWebConnection(webConnection); final HtmlPage firstPage = client.getPage(URL_FIRST); final HtmlForm f = firstPage.getForms().get(0); final HtmlFileInput fileInput = f.getInputByName("image"); final String path = getClass().getClassLoader().getResource("testfiles/" + "tiny-png.img").toExternalForm(); fileInput.setValueAttribute(path); fileInput.setData("My file data".getBytes()); firstPage.getHtmlElementById("mySubmit").click(); final KeyDataPair pair = (KeyDataPair) webConnection.getLastParameters().get(0); assertNotNull(pair.getData()); assertTrue(pair.getData().length > 10); final HttpEntity httpEntity = post(client, webConnection); final ByteArrayOutputStream out = new ByteArrayOutputStream(); httpEntity.writeTo(out); out.close(); if (getBrowserVersion().isIE()) { final Pattern pattern = Pattern.compile("Content-Disposition: form-data; name=\"image\";" + " filename=\".*testfiles[\\\\/]tiny-png\\.img\""); final Matcher matcher = pattern.matcher(out.toString()); assertTrue(matcher.find()); } else { assertTrue(out.toString() .contains("Content-Disposition: form-data; name=\"image\"; filename=\"tiny-png.img\"")); } } /** * Tests setData method. * @throws Exception if the test fails */ @Test public void setDataOnly() throws Exception { final String firstContent = "<html><head></head><body>\n" + "<form enctype='multipart/form-data' action='" + URL_SECOND + "' method='POST'>\n" + " <input type='file' name='image'>\n" + " <input type='submit' id='mySubmit'>\n" + "</form>\n" + "</body>\n" + "</html>"; final String secondContent = "<html><head><title>second</title></head></html>"; final WebClient client = getWebClient(); final MockWebConnection webConnection = new MockWebConnection(); webConnection.setResponse(URL_FIRST, firstContent); webConnection.setResponse(URL_SECOND, secondContent); client.setWebConnection(webConnection); final HtmlPage firstPage = client.getPage(URL_FIRST); final HtmlForm f = firstPage.getForms().get(0); final HtmlFileInput fileInput = f.getInputByName("image"); fileInput.setData("My file data".getBytes()); firstPage.getHtmlElementById("mySubmit").click(); final KeyDataPair pair = (KeyDataPair) webConnection.getLastParameters().get(0); assertNull(pair.getData()); final HttpEntity httpEntity = post(client, webConnection); final ByteArrayOutputStream out = new ByteArrayOutputStream(); httpEntity.writeTo(out); out.close(); assertTrue(out.toString().contains("Content-Disposition: form-data; name=\"image\"; filename=\"\"")); } /** * Helper that does some nasty magic. */ private HttpEntity post(final WebClient client, final MockWebConnection webConnection) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { final Method makeHttpMethod = HttpWebConnection.class.getDeclaredMethod("makeHttpMethod", WebRequest.class, HttpClientBuilder.class); makeHttpMethod.setAccessible(true); final HttpWebConnection con = new HttpWebConnection(client); final Method getHttpClientBuilderMethod = HttpWebConnection.class.getDeclaredMethod("getHttpClientBuilder"); getHttpClientBuilderMethod.setAccessible(true); final HttpClientBuilder builder = (HttpClientBuilder) getHttpClientBuilderMethod.invoke(con); final HttpPost httpPost = (HttpPost) makeHttpMethod.invoke(con, webConnection.getLastWebRequest(), builder); final HttpEntity httpEntity = httpPost.getEntity(); return httpEntity; } /** * Verifies that content is provided for a not filled file input. * @throws Exception if the test fails */ @Test public void emptyField() throws Exception { final String firstContent = "<html><head></head><body>\n" + "<form enctype='multipart/form-data' action='" + URL_SECOND + "' method='POST'>\n" + " <input type='file' name='image' />\n" + " <input type='submit' id='clickMe'>\n" + "</form>\n" + "</body>\n" + "</html>"; final String secondContent = "<html><head><title>second</title></head></html>"; final WebClient client = getWebClient(); final MockWebConnection webConnection = new MockWebConnection(); webConnection.setResponse(URL_FIRST, firstContent); webConnection.setResponse(URL_SECOND, secondContent); client.setWebConnection(webConnection); final HtmlPage firstPage = client.getPage(URL_FIRST); firstPage.getHtmlElementById("clickMe").click(); final KeyDataPair pair = (KeyDataPair) webConnection.getLastParameters().get(0); assertEquals("image", pair.getName()); assertNull(pair.getFile()); } /** * @throws Exception if the test fails */ @Test public void contentType() throws Exception { final String firstContent = "<html><head></head><body>\n" + "<form enctype='multipart/form-data' action='" + URL_SECOND + "' method='POST'>\n" + " <input type='file' name='image' />\n" + " <input type='submit' name='mysubmit'/>\n" + "</form>\n" + "</body>\n" + "</html>"; final String secondContent = "<html><head><title>second</title></head></html>"; final WebClient client = getWebClient(); final MockWebConnection webConnection = new MockWebConnection(); webConnection.setResponse(URL_FIRST, firstContent); webConnection.setResponse(URL_SECOND, secondContent); client.setWebConnection(webConnection); final HtmlPage firstPage = client.getPage(URL_FIRST); final HtmlForm f = firstPage.getForms().get(0); final HtmlFileInput fileInput = f.getInputByName("image"); final URL fileURL = getClass().getClassLoader().getResource("testfiles/empty.png"); fileInput.setValueAttribute(fileURL.toExternalForm()); f.getInputByName("mysubmit").click(); final KeyDataPair pair = (KeyDataPair) webConnection.getLastParameters().get(0); assertNotNull(pair.getFile()); assertFalse("Content type: " + pair.getMimeType(), "text/webtest".equals(pair.getMimeType())); fileInput.setContentType("text/webtest"); f.getInputByName("mysubmit").click(); final KeyDataPair pair2 = (KeyDataPair) webConnection.getLastParameters().get(0); assertNotNull(pair2.getFile()); assertEquals("text/webtest", pair2.getMimeType()); } /** * Test HttpClient for uploading a file with non-ASCII name, if it works it means HttpClient has fixed its bug. * * Test for http://issues.apache.org/jira/browse/HTTPCLIENT-293, * which is related to http://sourceforge.net/p/htmlunit/bugs/535/ * * @throws Exception if the test fails */ @Test public void uploadFileWithNonASCIIName_HttpClient() throws Exception { final String filename = "\u6A94\u6848\uD30C\uC77C\u30D5\u30A1\u30A4\u30EB\u0645\u0644\u0641.txt"; final String path = getClass().getClassLoader().getResource(filename).toExternalForm(); final File file = new File(new URI(path)); assertTrue(file.exists()); final Map<String, Class<? extends Servlet>> servlets = new HashMap<>(); servlets.put("/upload2", Upload2Servlet.class); startWebServer("./", null, servlets); final HttpPost filePost = new HttpPost("http://localhost:" + PORT + "/upload2"); final MultipartEntityBuilder builder = MultipartEntityBuilder.create(); builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE).setCharset(Charset.forName("UTF-8")); builder.addPart("myInput", new FileBody(file, ContentType.APPLICATION_OCTET_STREAM)); filePost.setEntity(builder.build()); final HttpClientBuilder clientBuilder = HttpClientBuilder.create(); final HttpResponse httpResponse = clientBuilder.build().execute(filePost); InputStream content = null; try { content = httpResponse.getEntity().getContent(); final String response = new String(IOUtils.toByteArray(content)); //this is the value with ASCII encoding assertFalse("3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 2E 74 78 74 <br>myInput".equals(response)); } finally { IOUtils.closeQuietly(content); } } /** * Test uploading a file with non-ASCII name. * * Test for http://sourceforge.net/p/htmlunit/bugs/535/ * * @throws Exception if the test fails */ @Test public void uploadFileWithNonASCIIName() throws Exception { final Map<String, Class<? extends Servlet>> servlets = new HashMap<>(); servlets.put("/upload1", Upload1Servlet.class); servlets.put("/upload2", Upload2Servlet.class); startWebServer("./", null, servlets); final String filename = "\u6A94\u6848\uD30C\uC77C\u30D5\u30A1\u30A4\u30EB\u0645\u0644\u0641.txt"; final String path = getClass().getClassLoader().getResource(filename).toExternalForm(); final File file = new File(new URI(path)); assertTrue(file.exists()); final WebClient client = getWebClient(); final HtmlPage firstPage = client.getPage("http://localhost:" + PORT + "/upload1"); final HtmlForm form = firstPage.getForms().get(0); final HtmlFileInput fileInput = form.getInputByName("myInput"); fileInput.setValueAttribute(path); final HtmlSubmitInput submitInput = form.getInputByValue("Upload"); final HtmlPage secondPage = submitInput.click(); final String response = secondPage.getWebResponse().getContentAsString(); //this is the value with UTF-8 encoding final String expectedResponse = "6A94 6848 D30C C77C 30D5 30A1 30A4 30EB 645 644 641 2E 74 78 74 <br>myInput"; assertTrue("Invalid Response: " + response, response.endsWith(expectedResponse)); } /** * Servlet for '/upload1'. */ public static class Upload1Servlet extends HttpServlet { /** * {@inheritDoc} */ @Override protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException { response.setCharacterEncoding("UTF-8"); response.setContentType("text/html"); response.getWriter() .write("<html>" + "<body><form action='upload2' method='post' enctype='multipart/form-data'>\n" + "Name: <input name='myInput' type='file'><br>\n" + "Name 2 (should stay empty): <input name='myInput2' type='file'><br>\n" + "<input type='submit' value='Upload' id='mySubmit'>\n" + "</form></body></html>\n"); } } /** * Servlet for '/upload2'. */ public static class Upload2Servlet extends HttpServlet { /** * {@inheritDoc} */ @Override protected void doPost(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); response.setContentType("text/html"); final Writer writer = response.getWriter(); if (ServletFileUpload.isMultipartContent(request)) { try { final ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory()); for (final FileItem item : upload.parseRequest(request)) { if ("myInput".equals(item.getFieldName())) { final String path = item.getName(); for (final char ch : path.toCharArray()) { writer.write(Integer.toHexString(ch).toUpperCase(Locale.ROOT) + " "); } writer.write("<br>"); writer.write(item.getFieldName()); } } } catch (final FileUploadBase.SizeLimitExceededException e) { writer.write("SizeLimitExceeded"); } catch (final Exception e) { writer.write("error"); } } writer.close(); } } /** * @throws Exception if the test fails */ @Test public void mutiple() throws Exception { final Map<String, Class<? extends Servlet>> servlets = new HashMap<>(); servlets.put("/upload1", Multiple1Servlet.class); servlets.put("/upload2", HtmlFileInput2Test.PrintRequestServlet.class); startWebServer("./", null, servlets); final String filename1 = "HtmlFileInputTest_one.txt"; final String path1 = getClass().getResource(filename1).toExternalForm(); final File file1 = new File(new URI(path1)); assertTrue(file1.exists()); final String filename2 = "HtmlFileInputTest_two.txt"; final String path2 = getClass().getResource(filename2).toExternalForm(); final File file2 = new File(new URI(path2)); assertTrue(file2.exists()); final WebClient client = getWebClient(); final HtmlPage firstPage = client.getPage("http://localhost:" + PORT + "/upload1"); final HtmlForm form = firstPage.getForms().get(0); final HtmlFileInput fileInput = form.getInputByName("myInput"); fileInput.setValueAttribute(new String[] { path1, path2 }); final HtmlSubmitInput submitInput = form.getInputByValue("Upload"); final HtmlPage secondPage = submitInput.click(); final String response = secondPage.getWebResponse().getContentAsString(); assertTrue(response.contains("HtmlFileInputTest_one.txt")); assertTrue(response.contains("First")); assertTrue(response.contains("HtmlFileInputTest_two.txt")); assertTrue(response.contains("Second")); } /** * Servlet for '/upload1'. */ public static class Multiple1Servlet extends HttpServlet { /** * {@inheritDoc} */ @Override protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException { response.setCharacterEncoding("UTF-8"); response.setContentType("text/html"); response.getWriter() .write("<html>" + "<body><form action='upload2' method='post' enctype='multipart/form-data'>\n" + "Name: <input name='myInput' type='file' multiple><br>\n" + "<input type='submit' value='Upload' id='mySubmit'>\n" + "</form></body></html>\n"); } } }