001: /*
002: * Copyright (c) 2002-2008 Gargoyle Software Inc. All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * 1. Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: * 2. Redistributions in binary form must reproduce the above copyright notice,
010: * this list of conditions and the following disclaimer in the documentation
011: * and/or other materials provided with the distribution.
012: * 3. The end-user documentation included with the redistribution, if any, must
013: * include the following acknowledgment:
014: *
015: * "This product includes software developed by Gargoyle Software Inc.
016: * (http://www.GargoyleSoftware.com/)."
017: *
018: * Alternately, this acknowledgment may appear in the software itself, if
019: * and wherever such third-party acknowledgments normally appear.
020: * 4. The name "Gargoyle Software" must not be used to endorse or promote
021: * products derived from this software without prior written permission.
022: * For written permission, please contact info@GargoyleSoftware.com.
023: * 5. Products derived from this software may not be called "HtmlUnit", nor may
024: * "HtmlUnit" appear in their name, without prior written permission of
025: * Gargoyle Software Inc.
026: *
027: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
028: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
029: * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARGOYLE
030: * SOFTWARE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
031: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
032: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
033: * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
034: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
035: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
036: * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
037: */
038: package com.gargoylesoftware.htmlunit.html;
039:
040: import java.io.File;
041: import java.io.IOException;
042: import java.io.Writer;
043: import java.net.URI;
044: import java.net.URL;
045: import java.net.URLDecoder;
046: import java.util.HashMap;
047: import java.util.Iterator;
048: import java.util.Map;
049:
050: import javax.servlet.ServletException;
051: import javax.servlet.http.HttpServlet;
052: import javax.servlet.http.HttpServletRequest;
053: import javax.servlet.http.HttpServletResponse;
054:
055: import org.apache.commons.fileupload.FileItem;
056: import org.apache.commons.fileupload.FileUploadBase;
057: import org.apache.commons.fileupload.disk.DiskFileItemFactory;
058: import org.apache.commons.fileupload.servlet.ServletFileUpload;
059: import org.apache.commons.httpclient.HttpClient;
060: import org.apache.commons.httpclient.methods.PostMethod;
061: import org.apache.commons.httpclient.methods.multipart.FilePart;
062: import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
063: import org.apache.commons.httpclient.methods.multipart.Part;
064: import org.mortbay.jetty.Server;
065:
066: import com.gargoylesoftware.htmlunit.BrowserVersion;
067: import com.gargoylesoftware.htmlunit.HttpWebConnectionTest;
068: import com.gargoylesoftware.htmlunit.KeyDataPair;
069: import com.gargoylesoftware.htmlunit.MockWebConnection;
070: import com.gargoylesoftware.htmlunit.WebClient;
071: import com.gargoylesoftware.htmlunit.WebTestCase;
072: import com.gargoylesoftware.htmlunit.util.ServletContentWrapper;
073:
074: /**
075: * Tests for {@link HtmlFileInput}.
076: *
077: * @version $Revision: 2132 $
078: * @author Marc Guillemot
079: * @author Ahmed Ashour
080: */
081: public class HtmlFileInputTest extends WebTestCase {
082:
083: private Server server_;
084:
085: /**
086: * Create an instance
087: * @param name The name of the test
088: */
089: public HtmlFileInputTest(final String name) {
090: super (name);
091: }
092:
093: /**
094: * @throws Exception If the test fails.
095: */
096: public void testFileInput() throws Exception {
097: String path = getClass().getClassLoader().getResource(
098: "testfiles/" + "tiny-png.img").toExternalForm();
099: testFileInput(path);
100: final File file = new File(new URI(path));
101: testFileInput(file.getCanonicalPath());
102:
103: if (path.startsWith("file:")) {
104: path = path.substring("file:".length());
105: }
106: while (path.startsWith("/")) {
107: path = path.substring(1);
108: }
109: if (System.getProperty("os.name").toLowerCase().indexOf(
110: "windows") != -1) {
111: testFileInput(URLDecoder.decode(path.replace('/', '\\'),
112: "UTF-8"));
113: }
114: testFileInput("file:/" + path);
115: testFileInput("file://" + path);
116: testFileInput("file:///" + path);
117: }
118:
119: private void testFileInput(final String fileURL) throws Exception {
120: final String firstContent = "<html><head></head><body>\n"
121: + "<form enctype='multipart/form-data' action='"
122: + URL_SECOND + "' method='POST'>\n"
123: + " <input type='file' name='image' />\n"
124: + "</form>\n" + "</body>\n" + "</html>";
125: final String secondContent = "<html><head><title>second</title></head></html>";
126: final WebClient client = new WebClient();
127:
128: final MockWebConnection webConnection = new MockWebConnection(
129: client);
130: webConnection.setResponse(URL_FIRST, firstContent);
131: webConnection.setResponse(URL_SECOND, secondContent);
132:
133: client.setWebConnection(webConnection);
134:
135: final HtmlPage firstPage = (HtmlPage) client.getPage(URL_FIRST);
136: final HtmlForm f = (HtmlForm) firstPage.getForms().get(0);
137: final HtmlFileInput fileInput = (HtmlFileInput) f
138: .getInputByName("image");
139: fileInput.setValueAttribute(fileURL);
140: f.submit((SubmittableElement) null);
141: final KeyDataPair pair = (KeyDataPair) webConnection
142: .getLastParameters().get(0);
143: assertNotNull(pair.getFile());
144: assertTrue(pair.getFile().length() != 0);
145: }
146:
147: /**
148: * Test content provided for a not filled file input
149: * @throws Exception if the test fails
150: */
151: public void testEmptyField() throws Exception {
152: final String firstContent = "<html><head></head><body>\n"
153: + "<form enctype='multipart/form-data' action='"
154: + URL_SECOND + "' method='POST'>\n"
155: + " <input type='file' name='image' />\n"
156: + "</form>\n" + "</body>\n" + "</html>";
157: final String secondContent = "<html><head><title>second</title></head></html>";
158: final WebClient client = new WebClient();
159:
160: final MockWebConnection webConnection = new MockWebConnection(
161: client);
162: webConnection.setResponse(URL_FIRST, firstContent);
163: webConnection.setResponse(URL_SECOND, secondContent);
164:
165: client.setWebConnection(webConnection);
166:
167: final HtmlPage firstPage = (HtmlPage) client.getPage(URL_FIRST);
168: final HtmlForm f = (HtmlForm) firstPage.getForms().get(0);
169: f.submit((SubmittableElement) null);
170: final KeyDataPair pair = (KeyDataPair) webConnection
171: .getLastParameters().get(0);
172: assertEquals("image", pair.getName());
173: assertNull(pair.getFile());
174: }
175:
176: /**
177: * @throws Exception if the test fails
178: */
179: public void testContentType() throws Exception {
180: final String firstContent = "<html><head></head><body>\n"
181: + "<form enctype='multipart/form-data' action='"
182: + URL_SECOND + "' method='POST'>\n"
183: + " <input type='file' name='image' />\n"
184: + "</form>\n" + "</body>\n" + "</html>";
185: final String secondContent = "<html><head><title>second</title></head></html>";
186: final WebClient client = new WebClient();
187:
188: final MockWebConnection webConnection = new MockWebConnection(
189: client);
190: webConnection.setResponse(URL_FIRST, firstContent);
191: webConnection.setResponse(URL_SECOND, secondContent);
192:
193: client.setWebConnection(webConnection);
194:
195: final HtmlPage firstPage = (HtmlPage) client.getPage(URL_FIRST);
196: final HtmlForm f = (HtmlForm) firstPage.getForms().get(0);
197: final HtmlFileInput fileInput = (HtmlFileInput) f
198: .getInputByName("image");
199:
200: final URL fileURL = getClass().getClassLoader().getResource(
201: "testfiles/empty.png");
202:
203: fileInput.setValueAttribute(fileURL.toExternalForm());
204: f.submit((SubmittableElement) null);
205: final KeyDataPair pair = (KeyDataPair) webConnection
206: .getLastParameters().get(0);
207: assertNotNull(pair.getFile());
208: assertFalse("Content type: " + pair.getContentType(),
209: "text/webtest".equals(pair.getContentType()));
210:
211: fileInput.setContentType("text/webtest");
212: f.submit((SubmittableElement) null);
213: final KeyDataPair pair2 = (KeyDataPair) webConnection
214: .getLastParameters().get(0);
215: assertNotNull(pair2.getFile());
216: assertEquals("text/webtest", pair2.getContentType());
217: }
218:
219: /**
220: * Test HttpClient for uploading a file with non-ASCII name, if it works it means HttpClient has fixed its bug.
221: *
222: * Test for http://issues.apache.org/jira/browse/HTTPCLIENT-293,
223: * which is related to http://sourceforge.net/tracker/index.php?func=detail&aid=1818569&group_id=47038&atid=448266
224: *
225: * @throws Exception If the test fails.
226: */
227: public void testUploadFileWithNonASCIIName_HttpClient()
228: throws Exception {
229: if (notYetImplemented()) {
230: return;
231: }
232:
233: final String filename = "\u6A94\u6848\uD30C\uC77C\u30D5\u30A1\u30A4\u30EB\u0645\u0644\u0641.txt";
234: final String path = getClass().getClassLoader().getResource(
235: filename).toExternalForm();
236: final File file = new File(new URI(path));
237: assertTrue(file.exists());
238:
239: final Map servlets = new HashMap();
240: servlets.put(Upload2Servlet.class, "/upload2");
241:
242: server_ = HttpWebConnectionTest.startWebServer("./", null,
243: servlets);
244: final PostMethod filePost = new PostMethod("http://localhost:"
245: + HttpWebConnectionTest.PORT + "/upload2");
246:
247: final FilePart part = new FilePart("myInput", file);
248: part.setCharSet("UTF-8");
249:
250: filePost.setRequestEntity(new MultipartRequestEntity(
251: new Part[] { part }, filePost.getParams()));
252: final HttpClient client = new HttpClient();
253: client.executeMethod(filePost);
254:
255: final String response = filePost.getResponseBodyAsString();
256: //this is the value with ASCII encoding
257: assertFalse("3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 3F 2E 74 78 74 <br>myInput"
258: .equals(response));
259: }
260:
261: /**
262: * Test uploading a file with non-ASCII name.
263: *
264: * Test for http://sourceforge.net/tracker/index.php?func=detail&aid=1818569&group_id=47038&atid=448266
265: *
266: * @throws Exception If the test fails.
267: */
268: public void testUploadFileWithNonASCIIName() throws Exception {
269: final Map servlets = new HashMap();
270: servlets.put(Upload1Servlet.class, "/upload1");
271: servlets.put(Upload2Servlet.class, "/upload2");
272: server_ = HttpWebConnectionTest.startWebServer("./", null,
273: servlets);
274:
275: testUploadFileWithNonASCIIName(BrowserVersion.FIREFOX_2);
276: testUploadFileWithNonASCIIName(BrowserVersion.INTERNET_EXPLORER_7_0);
277: }
278:
279: private void testUploadFileWithNonASCIIName(
280: final BrowserVersion browserVersion) throws Exception {
281: final String filename = "\u6A94\u6848\uD30C\uC77C\u30D5\u30A1\u30A4\u30EB\u0645\u0644\u0641.txt";
282: final String path = getClass().getClassLoader().getResource(
283: filename).toExternalForm();
284: final File file = new File(new URI(path));
285: assertTrue(file.exists());
286:
287: final WebClient client = new WebClient(browserVersion);
288: final HtmlPage firstPage = (HtmlPage) client.getPage(new URL(
289: "http://localhost:" + HttpWebConnectionTest.PORT
290: + "/upload1"));
291:
292: final HtmlForm form = (HtmlForm) firstPage.getForms().get(0);
293: final HtmlFileInput fileInput = (HtmlFileInput) form
294: .getInputByName("myInput");
295: fileInput.setValueAttribute(path);
296:
297: final HtmlSubmitInput submitInput = (HtmlSubmitInput) form
298: .getInputByValue("Upload");
299: final HtmlPage secondPage = (HtmlPage) submitInput.click();
300:
301: final String response = secondPage.getWebResponse()
302: .getContentAsString();
303:
304: //this is the value with UTF-8 encoding
305: final String expectedResponse = "6A94 6848 D30C C77C 30D5 30A1 30A4 30EB 645 644 641 2E 74 78 74 <br>myInput";
306:
307: assertTrue("Invalid Response: " + response, response
308: .indexOf(expectedResponse) != -1);
309:
310: if (browserVersion.isIE()) {
311: assertTrue(expectedResponse.length() < response.length());
312: } else {
313: assertEquals(expectedResponse.length(), response.length());
314: }
315: }
316:
317: /**
318: * Servlet for '/upload1'
319: */
320: public static class Upload1Servlet extends ServletContentWrapper {
321:
322: private static final long serialVersionUID = 6693252829875297263L;
323:
324: /**
325: * Creates an instance.
326: */
327: public Upload1Servlet() {
328: super (
329: "<html><head><meta http-equiv='Content-Type' content='text/html; charset=utf-8'/></head>\n"
330: + "<form action='upload2' method='post' enctype='multipart/form-data'>\n"
331: + "Name: <input name='myInput' type='file'><br>\n"
332: + "Name 2 (should stay empty): <input name='myInput2' type='file'><br>\n"
333: + "<input type='submit' value='Upload' id='mySubmit'>\n"
334: + "</form>\n");
335: }
336: }
337:
338: /**
339: * Servlet for '/upload2'
340: */
341: public static class Upload2Servlet extends HttpServlet {
342:
343: private static final long serialVersionUID = -1350878755076138012L;
344:
345: /**
346: * {@inheritDoc}
347: */
348: protected void doPost(final HttpServletRequest request,
349: final HttpServletResponse response)
350: throws ServletException, IOException {
351: request.setCharacterEncoding("UTF-8");
352: response.setContentType("text/html");
353: final Writer writer = response.getWriter();
354: if (ServletFileUpload.isMultipartContent(request)) {
355: try {
356: final ServletFileUpload upload = new ServletFileUpload(
357: new DiskFileItemFactory());
358: for (final Iterator iterator = upload.parseRequest(
359: request).iterator(); iterator.hasNext();) {
360: final FileItem item = (FileItem) iterator
361: .next();
362: if ("myInput".equals(item.getFieldName())) {
363: final String path = item.getName();
364: for (int i = 0; i < path.length(); i++) {
365: writer.write(Integer.toHexString(
366: path.charAt(i)).toUpperCase()
367: + " ");
368: }
369: writer.write("<br>");
370: writer.write(item.getFieldName());
371: }
372: }
373: } catch (final FileUploadBase.SizeLimitExceededException e) {
374: writer.write("SizeLimitExceeded");
375: } catch (final Exception e) {
376: writer.write("error");
377: }
378: }
379: writer.close();
380: }
381:
382: }
383:
384: /**
385: * {@inheritDoc}
386: * Stops the web server if it has been started.
387: */
388: protected void tearDown() throws Exception {
389: super.tearDown();
390: HttpWebConnectionTest.stopWebServer(server_);
391: server_ = null;
392: }
393: }
|