From: <no...@us...> - 2003-09-09 20:48:02
|
Log Message: ----------- Added support for file upload - patch provided by Brad Clarke Modified Files: -------------- /cvsroot/htmlunit/htmlunit/src/test/java/com/gargoylesoftware/htmlunit: FakeWebConnection.java /cvsroot/htmlunit/htmlunit/src/xdocs: changes.xml /cvsroot/htmlunit/htmlunit/src/java/com/gargoylesoftware/htmlunit/html: HtmlForm.java /cvsroot/htmlunit/htmlunit/src/java/com/gargoylesoftware/htmlunit: WebConnection.java HttpWebConnection.java WebClient.java Added Files: ----------- /cvsroot/htmlunit/htmlunit/src/java/com/gargoylesoftware/htmlunit: KeyDataPair.java FormEncodingType.java Revision Data ------------- Index: FakeWebConnection.java =================================================================== RCS file: /cvsroot/htmlunit/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/FakeWebConnection.java,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- FakeWebConnection.java 3 Sep 2003 15:55:23 -0000 1.6 +++ FakeWebConnection.java 9 Sep 2003 20:47:56 -0000 1.7 @@ -110,11 +110,29 @@ super( webClient ); } + /** + * Submit a request to the processor + * + * @param url The url of the server + * @param method The submit method. Ie SubmitMethod.GET + * @param parameters Any parameters + * @param requestParameters Any headers that need to be put into the request. + * @return See above + */ + public WebResponse getResponse( + final URL url, + final SubmitMethod method, + final List parameters, + final Map requestParameters ) { + + return this.getResponse(url, FormEncodingType.URL_ENCODED, method, parameters, requestParameters); + } /** * Submit a request and retrieve a response * * @param url The url of the server + * @param encType form encoding type to use for POST method * @param method The submit method. Ie SubmitMethod.GET * @param parameters Any parameters * @param requestHeaders Any headers that need to be put into the request. @@ -122,6 +140,7 @@ */ public WebResponse getResponse( final URL url, + final FormEncodingType encType, final SubmitMethod method, final List parameters, final Map requestHeaders ) { Index: changes.xml =================================================================== RCS file: /cvsroot/htmlunit/htmlunit/src/xdocs/changes.xml,v retrieving revision 1.125 retrieving revision 1.126 diff -u -d -r1.125 -r1.126 --- changes.xml 9 Sep 2003 20:22:05 -0000 1.125 +++ changes.xml 9 Sep 2003 20:47:57 -0000 1.126 @@ -21,6 +21,9 @@ a src jar for the current build Patch submitted by Brad Clarke </action> + <action type="update" dev="mbowler" id="803229 " due-to="Brad Clarke"> + Added HtmlFileInput support. Patch submitted by Brad Clarke + </action> </release> Index: HtmlForm.java =================================================================== RCS file: /cvsroot/htmlunit/htmlunit/src/java/com/gargoylesoftware/htmlunit/html/HtmlForm.java,v retrieving revision 1.22 retrieving revision 1.23 diff -u -d -r1.22 -r1.23 --- HtmlForm.java 11 Aug 2003 15:24:57 -0000 1.22 +++ HtmlForm.java 9 Sep 2003 20:47:57 -0000 1.23 @@ -37,6 +37,7 @@ */ package com.gargoylesoftware.htmlunit.html; +import com.gargoylesoftware.htmlunit.FormEncodingType; import com.gargoylesoftware.htmlunit.Assert; import com.gargoylesoftware.htmlunit.ElementNotFoundException; import com.gargoylesoftware.htmlunit.KeyValuePair; @@ -163,10 +164,10 @@ catch( final MalformedURLException e ) { throw new IllegalArgumentException( "Not a valid url: " + action ); } - + final FormEncodingType encType = FormEncodingType.getInstance( this.getEnctypeAttribute() ); final SubmitMethod method = SubmitMethod.getInstance( getAttributeValue( "method" ) ); final WebWindow webWindow = htmlPage.getEnclosingWindow(); - return htmlPage.getWebClient().getPage( webWindow, url, method, parameterList ); + return htmlPage.getWebClient().getPage( webWindow, url, encType, method, parameterList ); } --- NEW FILE: KeyDataPair.java --- /* * Copyright (c) 2002, 2003 Gargoyle Software Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The end-user documentation included with the redistribution, if any, must * include the following acknowledgment: * * "This product includes software developed by Gargoyle Software Inc. * (http://www.GargoyleSoftware.com/)." * * Alternately, this acknowledgment may appear in the software itself, if * and wherever such third-party acknowledgments normally appear. * 4. The name "Gargoyle Software" must not be used to endorse or promote * products derived from this software without prior written permission. * For written permission, please contact in...@Ga.... * 5. Products derived from this software may not be called "HtmlUnit", nor may * "HtmlUnit" appear in their name, without prior written permission of * Gargoyle Software Inc. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARGOYLE * SOFTWARE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.gargoylesoftware.htmlunit; /** * A holder for key/data pairs. * * @version $Revision: 1.1 $ * @author Brad Clarke */ public class KeyDataPair extends KeyValuePair { private final Object dataObject_; /** * Create an instance. * * @param key The key. * @param value The value. */ public KeyDataPair( final String key, final String value) { super(key, value); dataObject_ = value; } /** * Create an instance * * @param key The key. * @param data The value */ public KeyDataPair(String key, Object data) { super(key, data.toString()); dataObject_ = data; } /** @return The data object */ public Object getData() { return dataObject_; } } --- NEW FILE: FormEncodingType.java --- /* * Copyright (c) 2002, 2003 Gargoyle Software Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The end-user documentation included with the redistribution, if any, must * include the following acknowledgment: * * "This product includes software developed by Gargoyle Software Inc. * (http://www.GargoyleSoftware.com/)." * * Alternately, this acknowledgment may appear in the software itself, if * and wherever such third-party acknowledgments normally appear. * 4. The name "Gargoyle Software" must not be used to endorse or promote * products derived from this software without prior written permission. * For written permission, please contact in...@Ga.... * 5. Products derived from this software may not be called "HtmlUnit", nor may * "HtmlUnit" appear in their name, without prior written permission of * Gargoyle Software Inc. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARGOYLE * SOFTWARE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package com.gargoylesoftware.htmlunit; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.MultipartPostMethod; /** * A collection of constants that represent the various ways a form can be * encoded when submitted * * @version $Revision: 1.1 $ * @author Brad Clarke */ public class FormEncodingType { /** * URL_ENCODED */ public static final FormEncodingType URL_ENCODED = new FormEncodingType(PostMethod.FORM_URL_ENCODED_CONTENT_TYPE); /** * MULTIPART */ public static final FormEncodingType MULTIPART = new FormEncodingType(MultipartPostMethod.MULTIPART_FORM_CONTENT_TYPE); private final String name_; private FormEncodingType(final String name) { name_ = name; } /** * Return the name of this EncodingType * * @return See above */ public String getName() { return name_; } /** * Return the constant that matches the given name * * @param name The name to search by * @return See above */ public static FormEncodingType getInstance(final String name) { final String lowerCaseName = name.toLowerCase(); final FormEncodingType allInstances[] = new FormEncodingType[] { URL_ENCODED, MULTIPART }; int i; for (i = 0; i < allInstances.length; i++) { if (allInstances[i].getName().equals(lowerCaseName)) { return allInstances[i]; } } // Special case: empty string defaults to url encoded if (name.equals("")) { return URL_ENCODED; } throw new IllegalArgumentException("No encoding type found for [" + name + "]"); } /** * Return a string representation of this object * * @return See above */ public String toString() { return "EncodingType[name=" + getName() + "]"; } } Index: WebConnection.java =================================================================== RCS file: /cvsroot/htmlunit/htmlunit/src/java/com/gargoylesoftware/htmlunit/WebConnection.java,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- WebConnection.java 16 Jul 2003 20:11:21 -0000 1.7 +++ WebConnection.java 9 Sep 2003 20:47:57 -0000 1.8 @@ -103,6 +103,25 @@ throws IOException; + /** + * Submit a request and retrieve a response + * + * @param parameters Any parameters + * @param url The url of the server + * @param encType Encoding type of the form when done as a POST + * @param submitMethod The submit method. Ie SubmitMethod.GET + * @param requestHeaders Any headers that need to be put into the request. + * @return See above + * @exception IOException If an IO error occurs + */ + public abstract WebResponse getResponse( + final URL url, + final FormEncodingType encType, + final SubmitMethod submitMethod, + final List parameters, + final Map requestHeaders ) + throws + IOException; /** * Return the web client Index: HttpWebConnection.java =================================================================== RCS file: /cvsroot/htmlunit/htmlunit/src/java/com/gargoylesoftware/htmlunit/HttpWebConnection.java,v retrieving revision 1.13 retrieving revision 1.14 diff -u -d -r1.13 -r1.14 --- HttpWebConnection.java 19 Jul 2003 17:17:30 -0000 1.13 +++ HttpWebConnection.java 9 Sep 2003 20:47:57 -0000 1.14 @@ -37,6 +37,7 @@ */ package com.gargoylesoftware.htmlunit; +import java.io.File; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @@ -58,6 +59,7 @@ import org.apache.commons.httpclient.URI; import org.apache.commons.httpclient.URIException; import org.apache.commons.httpclient.cookie.CookiePolicy; +import org.apache.commons.httpclient.methods.MultipartPostMethod; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.logging.Log; @@ -98,12 +100,32 @@ super(webClient, proxyHost, proxyPort); } + /** + * Submit a request and retrieve a response + * + * @param parameters Any parameters + * @param url The url of the server + * @param submitMethod The submit method. Ie SubmitMethod.GET + * @param requestHeaders Any headers that need to be put in the request. + * @return See above + * @exception IOException If an IO error occurs + */ + public WebResponse getResponse( + final URL url, + final SubmitMethod submitMethod, + final List parameters, + final Map requestHeaders ) + throws + IOException { + return this.getResponse(url, FormEncodingType.URL_ENCODED, submitMethod, parameters, requestHeaders); + } /** * Submit a request and retrieve a response * * @param parameters Any parameters * @param url The url of the server + * @param encType Encoding type of the form when done as a POST * @param submitMethod The submit method. Ie SubmitMethod.GET * @param requestHeaders Any headers that need to be put in the request. * @return See above @@ -111,6 +133,7 @@ */ public WebResponse getResponse( final URL url, + final FormEncodingType encType, final SubmitMethod submitMethod, final List parameters, final Map requestHeaders ) @@ -122,14 +145,14 @@ try { long startTime, endTime; - HttpMethod httpMethod = makeHttpMethod( url, submitMethod, parameters, requestHeaders ); + HttpMethod httpMethod = makeHttpMethod( url, encType, submitMethod, parameters, requestHeaders ); startTime = System.currentTimeMillis(); int responseCode = httpClient.executeMethod( httpMethod ); endTime = System.currentTimeMillis(); if( responseCode == 401 ) { // Authentication required final KeyValuePair pair = getCredentials( httpMethod, url ); if( pair != null ) { - httpMethod = makeHttpMethod( url, submitMethod, parameters, requestHeaders ); + httpMethod = makeHttpMethod( url, encType, submitMethod, parameters, requestHeaders ); addCredentialsToHttpMethod( httpMethod, pair ); startTime = System.currentTimeMillis(); responseCode = httpClient.executeMethod( httpMethod ); @@ -200,6 +223,7 @@ private HttpMethod makeHttpMethod( final URL url, + final FormEncodingType encType, final SubmitMethod method, final List parameters, final Map requestHeaders ) @@ -224,7 +248,12 @@ } } else if( method == SubmitMethod.POST ) { - httpMethod = new PostMethod( path ); + if (encType == FormEncodingType.URL_ENCODED) { + httpMethod = new PostMethod( path ); + } + else { + httpMethod = new MultipartPostMethod(path); + } final String queryString = url.getQuery(); if( queryString != null ) { httpMethod.setQueryString(queryString); @@ -234,15 +263,35 @@ // Note that this has to be done in two loops otherwise it won't // be able to support two elements with the same name. iterator = parameters.iterator(); - while( iterator.hasNext() ) { - final NameValuePair pair = ( NameValuePair )iterator.next(); - ( ( PostMethod )httpMethod ).removeParameter( pair.getName(), pair.getValue() ); - } - - iterator = parameters.iterator(); - while( iterator.hasNext() ) { - final NameValuePair pair = ( NameValuePair )iterator.next(); - ( ( PostMethod )httpMethod ).addParameter( pair.getName(), pair.getValue() ); + if (encType == FormEncodingType.URL_ENCODED) { + while( iterator.hasNext() ) { + final NameValuePair pair = ( NameValuePair )iterator.next(); + ( ( PostMethod )httpMethod ).removeParameter( pair.getName(), pair.getValue() ); + } + + iterator = parameters.iterator(); + while( iterator.hasNext() ) { + final NameValuePair pair = ( NameValuePair )iterator.next(); + ( ( PostMethod )httpMethod ).addParameter( pair.getName(), pair.getValue() ); + } + } + else { + iterator = parameters.iterator(); + while (iterator.hasNext()) { + final KeyValuePair pair = (KeyValuePair) iterator.next(); + if (pair instanceof KeyDataPair) { + File f = (File) ((KeyDataPair)pair).getData(); + if (f.exists()){ + ((MultipartPostMethod) httpMethod).addParameter(pair.getName(), f); + } + else { + ((MultipartPostMethod) httpMethod).addParameter(pair.getName(), pair.getValue()); + } + } + else { + ((MultipartPostMethod) httpMethod).addParameter(pair.getName(), pair.getValue()); + } + } } } else { Index: WebClient.java =================================================================== RCS file: /cvsroot/htmlunit/htmlunit/src/java/com/gargoylesoftware/htmlunit/WebClient.java,v retrieving revision 1.46 retrieving revision 1.47 diff -u -d -r1.46 -r1.47 --- WebClient.java 3 Sep 2003 19:15:57 -0000 1.46 +++ WebClient.java 9 Sep 2003 20:47:57 -0000 1.47 @@ -319,9 +319,68 @@ FailingHttpStatusCodeException { return getPage(webWindow, url, method, parameters, getThrowExceptionOnFailingStatusCode()); } - + /** + * Return a page. + * + * @param webWindow The window that the new page will be loaded into. + * @param url The url of the server + * @param encType Encoding type of the form when done as a POST + * @param method The submit method. Ie Submit.GET or SubmitMethod.POST + * @param parameters A list of {@link + * com.gargoylesoftware.htmlunit.KeyValuePair KeyValuePair}'s that + * contain the parameters to send to the server + * @return The page that was loaded. + * @exception IOException If an IO error occurs + * @exception FailingHttpStatusCodeException If the server returns a + * failing status code AND the property + * "throwExceptionOnFailingStatusCode" is set to true (see {@link + * #setThrowExceptionOnFailingStatusCode(boolean)}) + */ + public Page getPage( + final WebWindow webWindow, + final URL url, + final FormEncodingType encType, + final SubmitMethod method, + final List parameters ) + throws + IOException, + FailingHttpStatusCodeException { + return getPage(webWindow, url, encType, method, parameters, getThrowExceptionOnFailingStatusCode()); + } /** + * Return a page. + * + * @param webWindow The window that the new page will be loaded into. + * @param url The url of the server + * @param method The submit method. Ie Submit.GET or SubmitMethod.POST + * @param parameters A list of {@link + * com.gargoylesoftware.htmlunit.KeyValuePair KeyValuePair}'s that + * contain the parameters to send to the server + * @param throwExceptionOnFailingStatusCode true if this method should throw + * an exception whenever a failing status code is received. + * @return The page that was loaded. + * @exception IOException If an IO error occurs + * @exception FailingHttpStatusCodeException If the server returns a + * failing status code AND the variable + * "throwExceptionOnFailingStatusCode" is set to true + */ + public Page getPage( + final WebWindow webWindow, + final URL url, + final SubmitMethod method, + final List parameters, + final boolean throwExceptionOnFailingStatusCode ) + throws + IOException, + FailingHttpStatusCodeException { + + return this.getPage( + webWindow, url, FormEncodingType.URL_ENCODED, method, + parameters, throwExceptionOnFailingStatusCode); + } + + /** * Send a request to a server and return a Page that represents the * response from the server. This page will be used to populate this frame.<p> * @@ -352,6 +411,7 @@ * * @param webWindow The window that the new page will be loaded into. * @param url The url of the server + * @param encType Encoding type of the form when done as a POST * @param method The submit method. Ie Submit.GET or SubmitMethod.POST * @param parameters A list of {@link * com.gargoylesoftware.htmlunit.KeyValuePair KeyValuePair}'s that @@ -367,6 +427,7 @@ public Page getPage( final WebWindow webWindow, final URL url, + final FormEncodingType encType, final SubmitMethod method, final List parameters, final boolean throwExceptionOnFailingStatusCode ) @@ -383,7 +444,7 @@ webResponse = makeWebResponseForAboutUrl(webWindow,url); } else { - webResponse = loadWebResponse( url, method, parameters ); + webResponse = loadWebResponse( url, encType, method, parameters ); } final String contentType = webResponse.getContentType(); final int statusCode = webResponse.getStatusCode(); @@ -1006,7 +1067,6 @@ }; } - /** * Load a {@link WebResponse} from the server * @param url The url to load the response from. @@ -1019,12 +1079,29 @@ final URL url, final SubmitMethod method, final List parameters) throws IOException { + return this.loadWebResponse(url, FormEncodingType.URL_ENCODED, method, parameters); + } + + /** + * Load a {@link WebResponse} from the server + * @param url The url to load the response from. + * @param encType Encoding type of the form when done as a POST + * @param method The {@link SubmitMethod} to use + * @param parameters Any parameters that are being passed into the request + * @throws IOException if an IO problem occurs + * @return The WebResponse + */ + public final WebResponse loadWebResponse( + final URL url, final FormEncodingType encType, final SubmitMethod method, final List parameters) + throws + IOException { Assert.notNull("url", url); Assert.notNull("method", method); Assert.notNull("parameters", parameters); - final WebResponse webResponse = getWebConnection().getResponse( url, method, parameters, requestHeaders_ ); + final WebResponse webResponse + = getWebConnection().getResponse( url, encType, method, parameters, requestHeaders_ ); final int statusCode = webResponse.getStatusCode(); if( statusCode >= 301 && statusCode <=307 && isRedirectEnabled() ) { |