From: <asa...@us...> - 2014-01-31 15:07:44
|
Revision: 9094 http://sourceforge.net/p/htmlunit/code/9094 Author: asashour Date: 2014-01-31 15:07:40 +0000 (Fri, 31 Jan 2014) Log Message: ----------- HtmlFileInput: ability to upload multiple files using setValueAttribute(String []). Issue 215 Modified Paths: -------------- trunk/htmlunit/src/changes/changes.xml trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFileInput.java trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/html/HtmlFileInputTest.java Added Paths: ----------- trunk/htmlunit/src/test/resources/com/gargoylesoftware/htmlunit/html/HtmlFileInputTest_one.txt trunk/htmlunit/src/test/resources/com/gargoylesoftware/htmlunit/html/HtmlFileInputTest_two.txt Modified: trunk/htmlunit/src/changes/changes.xml =================================================================== --- trunk/htmlunit/src/changes/changes.xml 2014-01-31 05:28:09 UTC (rev 9093) +++ trunk/htmlunit/src/changes/changes.xml 2014-01-31 15:07:40 UTC (rev 9094) @@ -8,6 +8,9 @@ <body> <release version="2.14" date="???" description="FF24, Bugfixes, initial work on IE11"> + <action type="add" dev="asashour" issue="215" system="features"> + HtmlFileInput: ability to upload multiple files using setValueAttribute(String []). + </action> <action type="fix" dev="asashour"> HTMLObjectElement: classid could be affected by webClient.setActiveXObjectMap(). </action> Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFileInput.java =================================================================== --- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFileInput.java 2014-01-31 05:28:09 UTC (rev 9093) +++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlFileInput.java 2014-01-31 15:07:40 UTC (rev 9094) @@ -19,11 +19,14 @@ import java.io.File; import java.net.URI; import java.net.URISyntaxException; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.apache.commons.lang3.StringUtils; +import com.gargoylesoftware.htmlunit.Page; import com.gargoylesoftware.htmlunit.SgmlPage; import com.gargoylesoftware.htmlunit.util.KeyDataPair; import com.gargoylesoftware.htmlunit.util.NameValuePair; @@ -52,7 +55,7 @@ * @param attributes the initial attributes */ HtmlFileInput(final String qualifiedName, final SgmlPage page, - final Map<String, DomAttr> attributes) { + final Map<String, DomAttr> attributes) { super(qualifiedName, page, addValueIfNeeded(page, attributes)); if (hasFeature(FILEINPUT_EMPTY_DEFAULT_VALUE)) { @@ -110,44 +113,48 @@ */ @Override public NameValuePair[] getSubmitKeyValuePairs() { - String value = getValueAttribute(); + final String valueAttribute = getValueAttribute(); - if (StringUtils.isEmpty(value)) { + if (StringUtils.isEmpty(valueAttribute)) { return new NameValuePair[] {new KeyDataPair(getNameAttribute(), new File(""), null, null)}; } - File file = null; - // to tolerate file:// - if (value.startsWith("file:/")) { - if (value.startsWith("file://") && !value.startsWith("file:///")) { - value = "file:///" + value.substring(7); + final List<NameValuePair> list = new ArrayList<NameValuePair>(); + for (String value : valueAttribute.split("§")) { + File file = null; + // to tolerate file:// + if (value.startsWith("file:/")) { + if (value.startsWith("file://") && !value.startsWith("file:///")) { + value = "file:///" + value.substring(7); + } + try { + file = new File(new URI(value)); + } + catch (final URISyntaxException e) { + // nothing here + } } - try { - file = new File(new URI(value)); + + if (file == null) { + file = new File(value); } - catch (final URISyntaxException e) { - // nothing here + + // contentType and charset are determined from browser and page + // perhaps it could be interesting to have setters for it in this class + // to give finer control to user + final String contentType; + if (contentType_ == null) { + contentType = getPage().getWebClient().guessContentType(file); } + else { + contentType = contentType_; + } + final String charset = getPage().getPageEncoding(); + final KeyDataPair keyDataPair = new KeyDataPair(getNameAttribute(), file, contentType, charset); + keyDataPair.setData(data_); + list.add(keyDataPair); } - - if (file == null) { - file = new File(value); - } - - // contentType and charset are determined from browser and page - // perhaps it could be interesting to have setters for it in this class - // to give finer control to user - final String contentType; - if (contentType_ == null) { - contentType = getPage().getWebClient().guessContentType(file); - } - else { - contentType = contentType_; - } - final String charset = getPage().getPageEncoding(); - final KeyDataPair keyDataPair = new KeyDataPair(getNameAttribute(), file, contentType, charset); - keyDataPair.setData(data_); - return new NameValuePair[] {keyDataPair}; + return list.toArray(new NameValuePair[list.size()]); } /** @@ -186,4 +193,28 @@ public String getContentType() { return contentType_; } + + /** + * Used to specify <code>multiple</code> paths to upload. + * + * The current implementation splits the value based on '§'. + * We may follow WebDriver solution, once made, + * see https://code.google.com/p/selenium/issues/detail?id=2239 + * @param paths the list of paths of the files to upload + * @return the page contained by this element's window after the value is set + */ + public Page setValueAttribute(final String[] paths) { + if (getAttribute("multiple") == ATTRIBUTE_NOT_DEFINED) { + throw new IllegalStateException("HtmlFileInput is not 'multiple'."); + } + final StringBuilder builder = new StringBuilder(); + for (final String p : paths) { + if (builder.length() != 0) { + builder.append('§'); + } + builder.append(p); + } + return super.setValueAttribute(builder.toString()); + } + } Modified: trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/html/HtmlFileInputTest.java =================================================================== --- trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/html/HtmlFileInputTest.java 2014-01-31 05:28:09 UTC (rev 9093) +++ trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/html/HtmlFileInputTest.java 2014-01-31 15:07:40 UTC (rev 9094) @@ -493,4 +493,63 @@ writer.close(); } } + + /** + * @throws Exception if the test fails + */ + @Test + public void mutiple() throws Exception { + final Map<String, Class<? extends Servlet>> servlets = new HashMap<String, Class<? extends Servlet>>(); + 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"); + } + } } Added: trunk/htmlunit/src/test/resources/com/gargoylesoftware/htmlunit/html/HtmlFileInputTest_one.txt =================================================================== --- trunk/htmlunit/src/test/resources/com/gargoylesoftware/htmlunit/html/HtmlFileInputTest_one.txt (rev 0) +++ trunk/htmlunit/src/test/resources/com/gargoylesoftware/htmlunit/html/HtmlFileInputTest_one.txt 2014-01-31 15:07:40 UTC (rev 9094) @@ -0,0 +1 @@ +First \ No newline at end of file Property changes on: trunk/htmlunit/src/test/resources/com/gargoylesoftware/htmlunit/html/HtmlFileInputTest_one.txt ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: trunk/htmlunit/src/test/resources/com/gargoylesoftware/htmlunit/html/HtmlFileInputTest_two.txt =================================================================== --- trunk/htmlunit/src/test/resources/com/gargoylesoftware/htmlunit/html/HtmlFileInputTest_two.txt (rev 0) +++ trunk/htmlunit/src/test/resources/com/gargoylesoftware/htmlunit/html/HtmlFileInputTest_two.txt 2014-01-31 15:07:40 UTC (rev 9094) @@ -0,0 +1 @@ +Second \ No newline at end of file Property changes on: trunk/htmlunit/src/test/resources/com/gargoylesoftware/htmlunit/html/HtmlFileInputTest_two.txt ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property |